Git-command chain hygiene (#33,#34,#35) (#63)

Co-authored-by: claude <claude@jpaul.io>
Co-committed-by: claude <claude@jpaul.io>
This commit was merged in pull request #63.
This commit is contained in:
2026-06-22 17:06:58 -04:00
committed by Claude (agent)
parent c34052665f
commit 6d28567c12
4 changed files with 33 additions and 15 deletions
@@ -11,6 +11,10 @@
- **Module 2 — Version Control as a Safety Net.** You can `init`, `commit`, read `git diff`/`git
log`/`git status`, and `git restore` an unwanted change. Branches build directly on commits: a
branch is just a label on the commit history you already understand.
- **Module 3 — Version Control for Words.** You first met `git branch`, `git switch -c`, `git merge`,
and `git branch -d` there — on a markdown doc, where a mistake costs nothing and the merge always
fast-forwarded. This module takes those same verbs to *code*, where branches actually diverge and
merges can conflict.
- **Module 4 — Getting the AI Out of the Browser.** The AI now edits your real files directly from
your editor. That's exactly the capability that makes branches matter — you're about to let it edit
files *fast and confidently*, and you want a wall around the blast radius.
@@ -43,6 +47,10 @@ By the end of this module you can:
### What a branch actually is
You already drove this loop once — `git switch -c`, `git merge`, `git branch -d` on a doc in Module 3,
where the merge always fast-forwarded because nothing else had moved. Here the same verbs meet code
that diverges and conflicts, so it's worth pinning down what a branch really is before we lean on it.
Strip the mystique and a branch is **a named, movable pointer to a commit.** That's the whole
definition. Your commit history is a chain of snapshots (Module 2); a branch is a sticky label that
points at one of them and *moves forward* every time you commit on it.
@@ -65,10 +73,11 @@ git branch -d experiment # delete a branch you've already merged
git branch -D experiment # FORCE-delete a branch, merged or not (the "throw it away" button)
```
> **Naming note.** `git switch` (create/move between branches) and `git restore` (the Module 2 undo)
> were split out of the older, overloaded `git checkout` command. You'll still see `git checkout -b
> experiment` everywhere online — it does the same thing as `git switch -c experiment`. Both work;
> this module uses `switch`/`restore` because they say what they mean.
> **Naming note** (you saw the short version in Module 3). `git switch` (create/move between branches)
> and `git restore` (the Module 2 undo) were split out of the older, overloaded `git checkout` command.
> You'll still see `git checkout -b experiment` everywhere online — it does the same thing as
> `git switch -c experiment`. Both work; this module uses `switch`/`restore` because they say what they
> mean.
### The reframe: a branch is a sandbox you can blow away
+7 -4
View File
@@ -111,10 +111,13 @@ everywhere.
**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. Fix: either recreate the remote empty, or
reconcile once with `git pull --rebase origin main` and then push. (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.)
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
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
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.
**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:
@@ -103,9 +103,10 @@ correctness *and plausibility* — the skill Module 10 is built around. They app
or comment. For AI-generated diffs this gate is doing more work than it used to: the code compiles,
reads cleanly, and is still wrong in a way only review catches.
**6 — Merge is the commitment.** Approved, the PR merges into `main`. Squash, merge-commit, or
rebase — your team picks one; the effect is the same: the branch's work is now part of the shared
trunk. Delete the branch after; its job is done and its name lives on in the merge.
**6 — Merge is the commitment.** Approved, the PR merges into `main`. Hosts offer a couple of merge
styles — a squash or a merge commit; your team picks one and the effect is the same: the branch's work
is now part of the shared trunk. (You'll also see a *rebase-merge* option; it rewrites history and is
out of scope here.) Delete the branch after; its job is done and its name lives on in the merge.
**7 — The issue closes — ideally by itself.** If you linked the PR correctly, merging closes the
issue automatically. The receipt is written without anyone touching the issue. That's the satisfying
@@ -286,9 +287,13 @@ git switch main
echo "# direct edit" >> README.md
git commit -am "try to push straight to main"
git push # expect: remote rejects the push to a protected branch
git reset --hard HEAD~1 # undo the local commit; we'll do it the right way
git reset --hard HEAD~1 # undo the local commit; we'll add the feature the right way, via a PR
```
(That `git reset --hard HEAD~1` is a sharp, history-rewriting command from a later module — it drops
your most recent commit *and* its changes. It's safe here only because that commit was a throwaway to
test the guardrail; its full treatment and its real dangers are **Module 12**.)
If the push went through, protection isn't on — fix that before continuing. Feeling the server say
*no* is the point: "never commit to `main`" is now a rule, not a resolution.
@@ -428,8 +433,9 @@ own branch.
upstream is ongoing work, and PRs *from* forks are deliberately limited by hosts (for example, they
often can't access the upstream repo's CI secrets — relevant once you reach Module 14). For repos
you own, prefer branches; reach for forks only when you genuinely lack push access.
- **The loop diagram is the happy path.** Real PRs get change requests, need a rebase onto a moved
`main`, or hit a merge conflict (Module 6) when two contributors touched the same lines — exactly
- **The loop diagram is the happy path.** Real PRs get change requests, need updating when `main`
moves underneath them, or hit a merge conflict (Module 6) when two contributors touched the same
lines — exactly
the parallel-agent scenario worktrees mitigate but don't eliminate. The stations are fixed; the
number of trips around them isn't.
- **Squash-merge collapses authorship.** If your team squashes, the agent's (or your) individual
@@ -190,7 +190,7 @@ The pattern is **fan-out, then fan-in through the front door, one branch at a ti
first pass that lets you spend your scarce review attention only on PRs that already build and pass
tests. CI reviews *all* of them in parallel for free; you review the survivors.
3. **You merge them into `main` in a deliberate order**, not finish-order. Merge the foundational one
first (the agent that touched the joint), then rebase/merge the others on top so any conflict
first (the agent that touched the joint), then merge the others on top so any conflict
surfaces against settled code. Each merge is a small, calm, Module-6 conflict resolution — on your
terms, once, instead of two live agents corrupting each other in real time.
4. **An assistive reviewer (Module 24) can take the first pass** on each PR — comment on the obvious