style(no-slop): remove every em-dash + banned words across all modules + capstone
Apply the no-ai-slop standard (now binding in AGENTS.md): the em-dash character is banned outright (restructured, not blind-replaced), plus the banned word/phrase list (delve, leverage, robust, seamless, truly, unlock, etc.). 0 em-dashes remain in modules + capstone; the only "robust" left is the planted M10 ai-change.patch trap. Module H1 titles use a colon separator. All deliberate teaching devices preserved; labs compile/parse (py/sh/yaml/json); no junk. AGENTS.md updated with the hard no-slop rules. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TfzV5QvtPDz8LJS3Pu5VLT
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# Module 8 — Remotes and Hosting: GitHub, the Alternatives, and Owning Your Repo
|
||||
# Module 8: Remotes and Hosting (GitHub, the Alternatives, and Owning Your Repo)
|
||||
|
||||
> **One repo on one laptop is one spilled coffee away from gone.** A remote gets your history
|
||||
> off your machine and somewhere durable. And because every clone carries the full history, a
|
||||
@@ -8,13 +8,13 @@
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **Module 2** — you have a Git repo (`tasks-app`) with real commits, and you understand commits as
|
||||
- **Module 2**: you have a Git repo (`tasks-app`) with real commits, and you understand commits as
|
||||
checkpoints and the repo as durable memory. This module gets that history *off the one disk it
|
||||
lives on*.
|
||||
- **Module 5** — you committed your agentic tool's instructions file into the repo. A remote is what
|
||||
- **Module 5**: you committed your agentic tool's instructions file into the repo. A remote is what
|
||||
finally makes that config *shared*: push it once and every teammate (and every agent) pulls the
|
||||
same setup.
|
||||
- **Module 6** — you can work on branches. Pushing is per-branch, so knowing what a branch is matters
|
||||
- **Module 6**: you can work on branches. Pushing is per-branch, so knowing what a branch is matters
|
||||
here.
|
||||
|
||||
Helpful but not required: **Module 7** (worktrees). Everything below works the same whether you have
|
||||
@@ -26,12 +26,12 @@ one working directory or several.
|
||||
|
||||
By the end of this module you can:
|
||||
|
||||
1. Explain what a remote *is* — a named pointer to another copy of the same repo — and why "it's just
|
||||
1. Explain what a remote *is* (a named pointer to another copy of the same repo) and why "it's just
|
||||
another copy" is the whole reason hosting is provider-neutral.
|
||||
2. Add a remote, push your history to it, and pull changes back, on any forge, with the same commands.
|
||||
3. Recover from the three failure modes that bite everyone on first push: authentication, a
|
||||
non-empty remote, and a branch-name mismatch.
|
||||
4. Choose a host deliberately — hosted vs. self-hosted — using a current, dated comparison instead of
|
||||
4. Choose a host deliberately, hosted vs. self-hosted, using a current, dated comparison instead of
|
||||
defaulting to GitHub by reflex.
|
||||
5. State precisely where "pushing to a remote" is and isn't a backup, and how a normal team workflow
|
||||
accidentally satisfies most of the 3-2-1 rule.
|
||||
@@ -68,7 +68,7 @@ git clone <URL> # make a brand-new local copy from a remote (histo
|
||||
```
|
||||
|
||||
`origin` is just the conventional name for "the place I push to." You can have more than one remote
|
||||
(a personal fork *and* the team's repo, say), and they can live on different hosts entirely — one on
|
||||
(a personal fork *and* the team's repo, say), and they can live on different hosts entirely: one on
|
||||
a SaaS forge, one on a box in your closet. Git doesn't care.
|
||||
|
||||
### Getting a remote: you create the empty repo first
|
||||
@@ -77,13 +77,13 @@ The one piece the commands above assume is that a remote repo *exists* to push i
|
||||
the shape is the same:
|
||||
|
||||
1. In the host's web UI (or its CLI/API), create a **new, empty** repository. Give it a name; do
|
||||
**not** let it add a README, license, or `.gitignore` — you want it empty so your local history
|
||||
**not** let it add a README, license, or `.gitignore`; you want it empty so your local history
|
||||
is the first thing in it.
|
||||
2. Copy the URL it gives you. You'll see two flavours:
|
||||
- **HTTPS** — `https://host/you/tasks-app.git`. Authenticates with a username + a personal access
|
||||
token (not your account password — password auth over Git is gone on essentially every modern
|
||||
- **HTTPS**: `https://host/you/tasks-app.git`. Authenticates with a username + a personal access
|
||||
token (not your account password; password auth over Git is gone on essentially every modern
|
||||
host).
|
||||
- **SSH** — `git@host:you/tasks-app.git`. Authenticates with an SSH key you've added to your
|
||||
- **SSH**: `git@host:you/tasks-app.git`. Authenticates with an SSH key you've added to your
|
||||
account. More setup once, less friction forever.
|
||||
3. Register the remote on the local side and push the history up. The shape of that exchange, with a
|
||||
first push to an empty remote, looks like this:
|
||||
@@ -128,15 +128,15 @@ and the callout below walks the shape of getting one.
|
||||
> The exact menu names and scope labels drift per host, so treat these as the *shape*, not gospel
|
||||
> (**Verify-before-publish** the specific UI wording for your forge):
|
||||
>
|
||||
> - **Scope is the gotcha — check it first.** In the host's **Settings → developer / access tokens →
|
||||
> - **Scope is the gotcha; check it first.** In the host's **Settings → developer / access tokens →
|
||||
> create token**, you must grant the token write access to repositories: usually a scope literally
|
||||
> named `repo`, or a "read **and write**" toggle on the repositories resource. A token created
|
||||
> *without* it authenticates and then `403`s on push — it looks like an auth failure, but the fix is
|
||||
> *without* it authenticates and then `403`s on push; it looks like an auth failure, but the fix is
|
||||
> to **edit the token's scopes**, not to delete and recreate it.
|
||||
> - **The token is shown once.** Hosts reveal the value a single time at creation. Copy it the moment
|
||||
> it appears; if you lose it you create a new one rather than recover the old.
|
||||
> - **Pasting it is invisible, and only happens once.** When Git prompts for your "password," paste
|
||||
> the token — most terminals show *nothing* as you paste a secret, which is normal, not a failure.
|
||||
> the token; most terminals show *nothing* as you paste a secret, which is normal, not a failure.
|
||||
> A **credential helper** (`git config --global credential.helper …`, e.g. `store`, `cache`, or your
|
||||
> OS keychain) remembers it after the first success so you aren't pasting it on every push.
|
||||
> - **SSH is the alternative.** A key you've added to the host skips passwords entirely: more setup
|
||||
@@ -145,18 +145,18 @@ and the callout below walks the shape of getting one.
|
||||
**2. The remote isn't empty (non-fast-forward).** You let the host create the repo *with* a README,
|
||||
then push, and get `! [rejected] ... (fetch first)` or `non-fast-forward`. The remote has a commit
|
||||
your local history doesn't, so Git refuses to overwrite it. The simple fix is to **recreate the remote
|
||||
empty** and push again. (The alternative you'll see online — `git pull --rebase origin main`, then
|
||||
push — replays your commits on top of the remote's, but `rebase` is an advanced, history-rewriting
|
||||
empty** and push again. (The alternative you'll see online is `git pull --rebase origin main` then
|
||||
push: it replays your commits on top of the remote's, but `rebase` is an advanced, history-rewriting
|
||||
operation this course doesn't teach as a step here, so prefer the empty-remote fix for now. And note
|
||||
that plain `git pull` won't rescue you against an auto-README remote — it refuses to merge unrelated
|
||||
that plain `git pull` won't rescue you against an auto-README remote; it refuses to merge unrelated
|
||||
histories.) This is the same "someone else pushed before me" situation you'll hit constantly once
|
||||
you're collaborating — Module 11 — except here the "someone else" was the host's auto-generated README.
|
||||
you're collaborating (Module 11), except here the "someone else" was the host's auto-generated README.
|
||||
|
||||
**3. Branch-name mismatch.** Your local default branch is `master` but the host expects `main` (or
|
||||
vice versa). `git push -u origin main` then errors with `src refspec main does not match any`. Fix:
|
||||
check what you actually have with `git branch`, and either push the branch you have
|
||||
(`git push -u origin master`) or rename it first (`git branch -m main`). If you initialized with
|
||||
`git init -b main` back in Module 2, you're already on `main` and this one won't bite you here — but
|
||||
`git init -b main` back in Module 2, you're already on `main` and this one won't bite you here. But
|
||||
it's the classic wall for any repo that started life on `master`, so it's worth recognizing.
|
||||
|
||||
### Pull, fetch, and the everyday loop
|
||||
@@ -168,9 +168,9 @@ Once the remote exists, day-to-day work adds two moves to the Module 2 loop:
|
||||
- **`git push`** after you've committed, to send your new checkpoints up.
|
||||
|
||||
When you want to *see* what the remote has before you let it touch your working files, use
|
||||
**`git fetch`** instead — it downloads the remote's commits into `origin/main` but leaves your branch
|
||||
**`git fetch`** instead: it downloads the remote's commits into `origin/main` but leaves your branch
|
||||
untouched, so you can `git log main..origin/main` to read exactly what's incoming before merging.
|
||||
That "look before you leap" habit matters more the moment other contributors — human or agent — are
|
||||
That "look before you leap" habit matters more the moment other contributors (human or agent) are
|
||||
pushing to the same place.
|
||||
|
||||
### Choosing a host: the comparison
|
||||
@@ -183,10 +183,10 @@ for a team with on-prem, air-gapped, or data-control requirements (a real and co
|
||||
this audience) it may be the wrong default. The genuine choice is between **hosted** (someone runs
|
||||
the forge; you just use it) and **self-hosted** (you run the forge on your own infrastructure).
|
||||
|
||||
> ### Hosting comparison — as of 2026-06-22
|
||||
> ### Hosting comparison (as of 2026-06-22)
|
||||
>
|
||||
> Pricing and feature claims drift fast. Everything in these two tables was checked on the date above
|
||||
> and must be re-verified before you rely on it — see the **Verify-before-publish** checklist at the
|
||||
> and must be re-verified before you rely on it; see the **Verify-before-publish** checklist at the
|
||||
> end. List prices are per-user/month at the entry paid tier, billed annually, in USD; promotional
|
||||
> and volume discounts are common and not shown.
|
||||
|
||||
@@ -194,18 +194,18 @@ the forge; you just use it) and **self-hosted** (you run the forge on your own i
|
||||
|
||||
| Platform | Pricing (entry → paid) | Built-in CI/CD | AI-tooling integration | Ease of operation |
|
||||
|---|---|---|---|---|
|
||||
| **GitHub** | Free; Team ~$4/user; Enterprise ~$21/user | GitHub Actions, built in (Free tier includes a monthly minutes allowance for private repos; unlimited for public) | **Deepest.** Most agents, MCP servers, and AI reviewers target GitHub first | Zero ops — pure SaaS |
|
||||
| **GitLab** (SaaS) | Free (capped users/namespace, small CI allowance); Premium ~$29/user; Ultimate ~$99/user | GitLab CI/CD — among the most mature, deeply integrated pipelines | Strong; first-party AI assistant plus growing agent support | Zero ops as SaaS; also self-hostable (see below) |
|
||||
| **GitHub** | Free; Team ~$4/user; Enterprise ~$21/user | GitHub Actions, built in (Free tier includes a monthly minutes allowance for private repos; unlimited for public) | **Deepest.** Most agents, MCP servers, and AI reviewers target GitHub first | Zero ops, pure SaaS |
|
||||
| **GitLab** (SaaS) | Free (capped users/namespace, small CI allowance); Premium ~$29/user; Ultimate ~$99/user | GitLab CI/CD, among the most mature, deeply integrated pipelines | Strong; first-party AI assistant plus growing agent support | Zero ops as SaaS; also self-hostable (see below) |
|
||||
| **Bitbucket** (Atlassian) | Free (≤5 users); Standard ~$3.65/user; Premium ~$7.25/user | Pipelines, built in (small free monthly build-minute allowance) | Growing; tightest value is deep Jira/Atlassian tie-in | Zero ops as SaaS; Data Center edition self-hostable (enterprise pricing) |
|
||||
| **Azure DevOps** | First 5 users free; Basic ~$6/user beyond; pipelines ~$40/parallel job after a free job | Azure Pipelines, built in (one free parallel job + monthly minutes) | Good within the Microsoft ecosystem; Copilot integration | Zero ops as SaaS; Azure DevOps Server self-hostable |
|
||||
| **Codeberg** | Free (FOSS projects only; soft repo/storage caps) | Forgejo Actions (it runs Forgejo) | Via API/MCP; not a first-tier agent target | Zero ops; nonprofit-run, no commercial/closed-source hosting |
|
||||
| **SourceHut** | Paid to host: ~$5 / $10 / $15 (all tiers buy the *same* service — "pay what's fair"); reduced ~$2 rate / financial aid if the full price is a hardship; free to *contribute* | builds.sr.ht, built in | Minimal first-class AI tooling; reachable via API | Zero ops as SaaS; fully self-hostable (it's open source) |
|
||||
| **SourceHut** | Paid to host: ~$5 / $10 / $15 (all tiers buy the *same* service, "pay what's fair"); reduced ~$2 rate / financial aid if the full price is a hardship; free to *contribute* | builds.sr.ht, built in | Minimal first-class AI tooling; reachable via API | Zero ops as SaaS; fully self-hostable (it's open source) |
|
||||
|
||||
**Self-hostable open-source forges (you run it):**
|
||||
|
||||
| Forge | License / cost | Built-in CI/CD | AI-tooling integration | Ease of operation |
|
||||
|---|---|---|---|---|
|
||||
| **Forgejo** | Free, open source (you pay infra + ops) | Forgejo Actions — runs GitHub-Actions-compatible workflow YAML | Full REST API; community MCP servers; agents work over git + API | **Easiest.** Single Go binary, runs on a tiny VPS (~256 MB RAM). Community/nonprofit governed |
|
||||
| **Forgejo** | Free, open source (you pay infra + ops) | Forgejo Actions, runs GitHub-Actions-compatible workflow YAML | Full REST API; community MCP servers; agents work over git + API | **Easiest.** Single Go binary, runs on a tiny VPS (~256 MB RAM). Community/nonprofit governed |
|
||||
| **Gitea** | Free, open source | Gitea Actions (GitHub-Actions-compatible YAML) | Full REST API; community MCP servers | Single Go binary, same light footprint as Forgejo; company-backed |
|
||||
| **GitLab CE** | Free, open source | Full GitLab CI/CD + container registry + more, in one install | Same first-party AI direction as GitLab SaaS, self-hosted | **Heaviest.** Wants ~8 GB+ RAM (Postgres/Redis/Sidekiq/Gitaly); upgrades can't skip versions |
|
||||
| **Gogs** | Free, open source | None built in | API only | Lightest of all; single binary, runs on a Raspberry Pi. Slower development; no CI |
|
||||
@@ -214,7 +214,7 @@ the forge; you just use it) and **self-hosted** (you run the forge on your own i
|
||||
Two things to read out of those tables rather than memorize the numbers:
|
||||
|
||||
- **GitLab spans both camps.** It's a hosted SaaS *and* a self-hostable Community Edition from the
|
||||
same project — useful if you want SaaS now and the *option* to bring it in-house later without
|
||||
same project; useful if you want SaaS now and the *option* to bring it in-house later without
|
||||
changing tools.
|
||||
- **"Self-hosted" trades a per-user bill for an ops bill.** The license is free; your cost is the
|
||||
server, the upgrades, the backups, and the on-call. Forgejo/Gitea make that bill small (a single
|
||||
@@ -224,10 +224,10 @@ Two things to read out of those tables rather than memorize the numbers:
|
||||
### The self-hosted-forge track (optional)
|
||||
|
||||
If you're in the air-gapped/on-prem audience, you can run this module's lab against a forge you stand
|
||||
up yourself instead of a SaaS account. The teaching point is precisely that **nothing changes** — you
|
||||
up yourself instead of a SaaS account. The teaching point is precisely that **nothing changes**: you
|
||||
create an empty repo on your forge, copy its URL, `git remote add origin <URL>`, and `git push`. The
|
||||
lab below flags exactly where the only difference is (the URL and how you authenticate to your own
|
||||
box). Standing the forge up is its own exercise — Forgejo or Gitea is a single binary and the fastest
|
||||
box). Standing the forge up is its own exercise; Forgejo or Gitea is a single binary and the fastest
|
||||
path; the *git* half is identical to the hosted track.
|
||||
|
||||
### Backup thesis, part one: distribution is the backup
|
||||
@@ -241,8 +241,8 @@ Recall the standard **3-2-1 backup rule**: keep **3** copies of your data, on **
|
||||
with **1** offsite. Now look at what a normal team doing normal work ends up with, without anyone
|
||||
"doing backups":
|
||||
|
||||
- Your laptop has a full copy — **complete history**, not just current files.
|
||||
- The remote has a full copy — **offsite**, on someone else's hardware (or your other box).
|
||||
- Your laptop has a full copy: **complete history**, not just current files.
|
||||
- The remote has a full copy: **offsite**, on someone else's hardware (or your other box).
|
||||
- Every teammate who has cloned the repo has *another* full copy, each with the entire history,
|
||||
because **clone copies everything**, not a snapshot.
|
||||
|
||||
@@ -255,13 +255,13 @@ a forge and a working team almost for free.
|
||||
Be precise about the division of labor, because the course is honest about where analogies stop:
|
||||
|
||||
- **Recovery power comes from commits (Module 2, and Module 12 for the harder cases).** That's your
|
||||
point-in-time restore — go back to any checkpoint.
|
||||
point-in-time restore: go back to any checkpoint.
|
||||
- **Backup power comes from remotes and distribution (this module).** That's your offsite,
|
||||
redundant, survives-the-disk copy.
|
||||
|
||||
You need both. Commits without a remote survive a mistake but not a dead drive. A remote without good
|
||||
commits survives a dead drive but gives you a junk drawer to restore from. Module 12 picks up the
|
||||
*recovery* half in full and is just as honest about what Git is **not** a backup for — your database,
|
||||
*recovery* half in full and is just as honest about what Git is **not** a backup for: your database,
|
||||
your secrets, your uncommitted work, your large binaries. We'll hold that thought there.
|
||||
|
||||
---
|
||||
@@ -275,14 +275,14 @@ A remote isn't only about durability. It's what the AI parts of this course run
|
||||
operate on the *remote* repo through its API and web UI. Until your history is pushed, none of that
|
||||
machinery has anything to act on. A remote is the precondition for every agent-in-the-loop module
|
||||
that follows.
|
||||
- **GitHub's "integrates first" status is a real, current bias — name it, then decide.** Because the
|
||||
- **GitHub's "integrates first" status is a real, current bias; name it, then decide.** Because the
|
||||
largest forge is where AI tooling lands first, picking a less-common host or self-hosting can mean
|
||||
thinner first-class agent support and more wiring-it-yourself over the API. That's a legitimate cost
|
||||
to weigh against control and data-residency — *not* a reason to abandon the choice. The git
|
||||
to weigh against control and data-residency; *not* a reason to abandon the choice. The git
|
||||
mechanics are identical everywhere; it's the AI ecosystem maturity that varies, and that gap is the
|
||||
thing to check (it narrows constantly).
|
||||
- **The committed AI config from Module 5 only pays off once it's pushed.** Locally, your agent's
|
||||
instructions file just configures *your* agent. Pushed to the remote, it configures *everyone's* —
|
||||
instructions file just configures *your* agent. Pushed to the remote, it configures *everyone's*:
|
||||
every teammate who clones, and every automated agent that later operates on the repo, inherits the
|
||||
same conventions instead of each drifting into a private setup. The remote is what turns "my AI
|
||||
config" into "the project's AI config."
|
||||
@@ -308,13 +308,13 @@ WSL, or Git Bash on Windows. Continues the `tasks-app` repo from Module 2.
|
||||
to your account. This is the one part you set up by hand in the host's web UI, since it's account
|
||||
security, not git. Do it first; failure mode #1 above is the most common first-push wall.
|
||||
- Claude Code (or sub your own agent) in your terminal, set up as in Module 4. In this lab you
|
||||
*direct the agent* to do the git work — add the remote, push, clone, fetch, pull — and you verify
|
||||
*direct the agent* to do the git work (add the remote, push, clone, fetch, pull) and you verify
|
||||
each result yourself. You don't type the git commands by hand.
|
||||
|
||||
### Part A — Create the empty remote and push
|
||||
### Part A: Create the empty remote and push
|
||||
|
||||
1. On your host's web UI, create a **new, empty** repository named `tasks-app`. Do **not** add a
|
||||
README, license, or `.gitignore` — leave it empty so your local history goes in clean. Copy the URL
|
||||
README, license, or `.gitignore`; leave it empty so your local history goes in clean. Copy the URL
|
||||
it shows you (HTTPS or SSH).
|
||||
|
||||
> **Self-hosted track:** identical step, on your own forge's UI. The only thing that differs from
|
||||
@@ -342,10 +342,10 @@ WSL, or Git Bash on Windows. Continues the `tasks-app` repo from Module 2.
|
||||
commit history from Module 2 are now sitting on hardware that is not your laptop. **That is the
|
||||
backup half the course promised.**
|
||||
|
||||
### Part B — Prove distribution is redundancy
|
||||
### Part B: Prove distribution is redundancy
|
||||
|
||||
You're going to demonstrate the 3-2-1 claim with your own eyes: that a clone is a *complete,
|
||||
independent* copy, history and all — not a snapshot.
|
||||
independent* copy, history and all, not a snapshot.
|
||||
|
||||
4. Direct your agent to make a change and ship it in one go:
|
||||
|
||||
@@ -379,16 +379,16 @@ independent* copy, history and all — not a snapshot.
|
||||
|
||||
The script confirms (a) you have a remote configured, (b) your local branch is fully pushed
|
||||
(nothing stranded only on your disk), and (c) a fresh clone of the remote carries the exact same
|
||||
commit count as your local repo — i.e. the offsite copy is complete, not partial. Read its output;
|
||||
commit count as your local repo, i.e. the offsite copy is complete, not partial. Read its output;
|
||||
the green line is your evidence that the backup is real.
|
||||
|
||||
> On the **HTTPS + token** path with a *private* repo, the clone check (c) needs your credential
|
||||
> helper to have cached the token from your earlier push — otherwise it can't authenticate to clone.
|
||||
> helper to have cached the token from your earlier push; otherwise it can't authenticate to clone.
|
||||
> The script won't hang waiting for a prompt (it disables interactive credential prompts); it just
|
||||
> reports a `NOTE` that it couldn't clone, and the push checks above still stand. SSH and public
|
||||
> repos clone with no credential at all.
|
||||
|
||||
### Part C — The everyday loop
|
||||
### Part C: The everyday loop
|
||||
|
||||
7. From the *teammate* clone, direct your agent to make and ship a change:
|
||||
|
||||
@@ -415,7 +415,7 @@ independent* copy, history and all — not a snapshot.
|
||||
you let it touch your files. You've now pushed *and* pulled across two independent copies through
|
||||
one remote, the complete remotes mechanic.
|
||||
|
||||
### Part D (optional) — A second remote
|
||||
### Part D (optional): A second remote
|
||||
|
||||
9. Direct your agent to add a *second* remote (a personal fork on another host, or even a bare repo on
|
||||
a USB drive or a box on your LAN) and push to it too:
|
||||
@@ -430,20 +430,20 @@ independent* copy, history and all — not a snapshot.
|
||||
|
||||
## Where it breaks
|
||||
|
||||
The honest limits — the backup analogy especially needs them.
|
||||
The honest limits; the backup analogy especially needs them.
|
||||
|
||||
- **A remote backs up what you *pushed*, nothing else.** Uncommitted edits, untracked files, and
|
||||
anything `.gitignore` excludes (like `tasks.json` runtime state) never leave your laptop. "I pushed"
|
||||
is not "everything is safe" — it's "every *committed and pushed* change is safe." The defense is the
|
||||
is not "everything is safe"; it's "every *committed and pushed* change is safe." The defense is the
|
||||
Module 2 habit: commit often, and now, push often too.
|
||||
- **Git is not a backup for non-Git things.** Your database, your secrets (which shouldn't be in the
|
||||
repo anyway — Module 17), large binaries, and build artifacts are not covered by pushing code. The
|
||||
repo anyway, see Module 17), large binaries, and build artifacts are not covered by pushing code. The
|
||||
3-2-1-by-accident win applies to your *versioned source*, full stop. Module 12 is blunt about this.
|
||||
- **One remote is one vendor.** Distribution across a team is great redundancy against *disk* failure;
|
||||
it's weaker against *account* failure. If your whole team only ever pushes to one host and that
|
||||
account is suspended, locked, or the provider has an outage, your offsite copy is temporarily out of
|
||||
reach (your local clones are fine). Part D's second remote, or a periodic clone to storage you
|
||||
control, is the answer for anyone who needs it — and it's the on-ramp to the self-hosting argument.
|
||||
control, is the answer for anyone who needs it. It's also the on-ramp to the self-hosting argument.
|
||||
- **"GitHub integrates first" is true today and a moving target.** Don't treat the AI-ecosystem gap
|
||||
between hosts as permanent; it's exactly the kind of claim that ages. Re-check it for your tooling
|
||||
before you let it decide your host.
|
||||
@@ -461,16 +461,16 @@ The honest limits — the backup analogy especially needs them.
|
||||
- You have pushed at least one commit and pulled at least one commit back, across two copies of the
|
||||
repo through one remote.
|
||||
- `verify-backup.sh` reports a clean, fully-pushed state and a clone whose commit count matches your
|
||||
local repo's — you've *seen* that the offsite copy is complete.
|
||||
local repo's: you've *seen* that the offsite copy is complete.
|
||||
- You can explain, in your own words, why a four-person team pushing to one remote roughly satisfies
|
||||
3-2-1 without running a backup tool — and name two things that win does *not* cover.
|
||||
3-2-1 without running a backup tool, and name two things that win does *not* cover.
|
||||
- You can state why the choice of host is a logistics decision, not a Git one, and name at least one
|
||||
hosted alternative to GitHub and one self-hostable forge.
|
||||
|
||||
When pushing feels like the natural end of "commit" and you trust that your history is no longer
|
||||
trapped on one disk, you have the *backup* half of the backup-and-recovery thread. Module 9 starts
|
||||
using the remote for more than storage — issues, the task layer where humans and agents pick up
|
||||
work — and Module 12 returns to finish the *recovery* half.
|
||||
using the remote for more than storage (issues, the task layer where humans and agents pick up
|
||||
work), and Module 12 returns to finish the *recovery* half.
|
||||
|
||||
---
|
||||
|
||||
@@ -479,27 +479,27 @@ work — and Module 12 returns to finish the *recovery* half.
|
||||
This module makes dated pricing and feature claims that drift. Re-check each before relying on the
|
||||
tables, and update the "as of" date when you do.
|
||||
|
||||
- [ ] **GitHub** tiers and prices — Free / Team / Enterprise per-user/month, and the Free-tier CI
|
||||
- [ ] **GitHub** tiers and prices: Free / Team / Enterprise per-user/month, and the Free-tier CI
|
||||
minutes allowance for private repos.
|
||||
- [ ] **GitLab** tiers — Free (user/namespace caps, CI allowance), Premium, Ultimate per-user/month,
|
||||
- [ ] **GitLab** tiers: Free (user/namespace caps, CI allowance), Premium, Ultimate per-user/month,
|
||||
and the SaaS-vs-self-managed price split.
|
||||
- [ ] **Bitbucket** tiers — Free user cap, Standard (~$3.65), Premium (~$7.25) per-user/month, and
|
||||
- [ ] **Bitbucket** tiers: Free user cap, Standard (~$3.65), Premium (~$7.25) per-user/month, and
|
||||
free build-minute allowance. (Reconciled against Atlassian's own pricing page on 2026-06-22;
|
||||
stale third-party listings still quote ~$2/$5 — trust Atlassian's page, and re-confirm.)
|
||||
- [ ] **Azure DevOps** — free-user count, Basic per-user/month, and the per-parallel-job pipeline
|
||||
stale third-party listings still quote ~$2/$5; trust Atlassian's page, and re-confirm.)
|
||||
- [ ] **Azure DevOps**: free-user count, Basic per-user/month, and the per-parallel-job pipeline
|
||||
price plus free job/minutes.
|
||||
- [ ] **Codeberg** — that it remains FOSS-only and free, and its current soft repo/storage caps.
|
||||
- [ ] **SourceHut** — paid-to-host tiers ($5/$10/$15): the 2026 prices are now *in effect* for new
|
||||
- [ ] **Codeberg**: that it remains FOSS-only and free, and its current soft repo/storage caps.
|
||||
- [ ] **SourceHut** paid-to-host tiers ($5/$10/$15): the 2026 prices are now *in effect* for new
|
||||
accounts (confirmed 2026-06-22), so they're no longer "proposed." Note all tiers buy the same
|
||||
service ("pay what's fair"), with a reduced rate (~the earlier minimum) and financial aid for
|
||||
hardship — re-confirm before relying on it.
|
||||
- [ ] **Self-hosted forges** — that Forgejo/Gitea still ship GitHub-Actions-compatible CI, GitLab CE's
|
||||
hardship; re-confirm before relying on it.
|
||||
- [ ] **Self-hosted forges**: that Forgejo/Gitea still ship GitHub-Actions-compatible CI, GitLab CE's
|
||||
current minimum resource footprint, and whether OneDev/Gogs CI status has changed.
|
||||
- [ ] **"GitHub integrates first" / AI-ecosystem maturity** — re-assess which forges are first-tier
|
||||
- [ ] **"GitHub integrates first" / AI-ecosystem maturity**: re-assess which forges are first-tier
|
||||
agent and MCP targets; this gap narrows fast.
|
||||
- [ ] **Self-host/hosted spans** — confirm GitLab still offers CE self-host, and Bitbucket/Azure DevOps
|
||||
- [ ] **Self-host/hosted spans**: confirm GitLab still offers CE self-host, and Bitbucket/Azure DevOps
|
||||
still offer their self-hostable editions, before describing either as spanning both camps.
|
||||
- [ ] **Credential/token UI** — the "Getting a credential" callout names menu paths and the
|
||||
- [ ] **Credential/token UI**: the "Getting a credential" callout names menu paths and the
|
||||
write-scope label (`repo` / "read and write") generically; confirm the current wording and
|
||||
scope name on the default-example host before publishing.
|
||||
- [ ] Update the comparison's **"as of" date** to the build date.
|
||||
|
||||
Reference in New Issue
Block a user