fix(M1-6): apply AI-drives-git reframe, lesson=theory, de-slop, + issue fixes
Phase 1 of the reframe. M1-3 stay manual-by-hand (browser chat); M4 is the pivot to the AI agent (Claude Code as example); M5-6 are agent-driven. - M1: de-slop (em-dashes), relocate the build-note out of the lab. Seam devices kept. - M2: #78 tell learner how to paste cli.py into chat; #79 commit the delete so the tree ends clean. restore/cold-session devices kept. - M3: #80 define ADR; #81 create-file-before-add; #82 ls before/after merge to prove branch isolation; #83 drop "prose"; M3 now owns the branch-basics intro. - M4: #84 Claude Code as the worked example; #85 AI drives git (arithmetic->calculator); #86 /path/to -> ~/ai-workflow-course; #87 agent does the revert+verify. - M5: #88 ask the agent which config files to commit, then let it stage/commit (CLAUDE.md example; repo still uses AGENTS.md). - M6: #90 stop re-teaching branch basics; rescope to the AI experimenting on a branch; the engineered conflict is now AI-resolved, learner-verified. Closes #78 Closes #79 Closes #80 Closes #81 Closes #82 Closes #84 Closes #85 Closes #87 Closes #88 Closes #90 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,8 +1,8 @@
|
||||
# Module 3 — Version Control for Words, Not Just Code
|
||||
|
||||
> **The safest possible place to practice Git is on prose — and it happens to be a genuinely useful
|
||||
> skill on its own.** Branch an ADR, let the AI draft it, read the diff, merge it. Nothing breaks if
|
||||
> it's wrong, so you build the muscle before the agent ever touches code.
|
||||
> **The safest place to practice Git is on words, and it happens to be a genuinely useful skill on
|
||||
> its own.** Branch an Architecture Decision Record (ADR), let the AI draft it, read the diff, merge
|
||||
> it. Nothing breaks if it's wrong, so you build the muscle before the agent ever touches code.
|
||||
|
||||
---
|
||||
|
||||
@@ -25,12 +25,12 @@ is exactly the low-risk on-ramp that makes the copy-paste friction tolerable one
|
||||
By the end of this module you can:
|
||||
|
||||
1. Explain why plain-text formats (markdown, AsciiDoc) version cleanly while `.docx`/`.pptx` version
|
||||
uselessly — and make the case to move a runbook or ADR out of Word.
|
||||
2. Create a branch, do work on it, and merge it back — the full branch → diff → commit → merge loop —
|
||||
on a document where a mistake costs nothing.
|
||||
uselessly, and make the case to move a runbook or ADR out of Word.
|
||||
2. Create a branch, do work on it, and merge it back. That's the full branch → diff → commit → merge
|
||||
loop, run on a document where a mistake costs nothing.
|
||||
3. Have an AI draft a real engineering document (an ADR or a runbook) and review its work as a diff
|
||||
before accepting it.
|
||||
4. Recognize that the wikis on most Git hosts are themselves Git repositories — so the docs you
|
||||
4. Recognize that the wikis on most Git hosts are themselves Git repositories, so the docs you
|
||||
thought lived "in a web UI" were version-controlled all along.
|
||||
|
||||
---
|
||||
@@ -57,7 +57,7 @@ format Git can actually work with. That "if" is the whole argument.
|
||||
### Why plain text wins: the diff is line-based
|
||||
|
||||
Git's core operation is the line-based diff. It compares two snapshots and reports which **lines**
|
||||
changed. Everything good about Git — readable history, reviewable changes, automatic merges — is
|
||||
changed. Everything good about Git (readable history, reviewable changes, automatic merges) is
|
||||
built on that one capability. So a format versions well in exact proportion to how well it maps onto
|
||||
*lines of text*.
|
||||
|
||||
@@ -90,7 +90,7 @@ This is a real, defensible engineering argument, not a style preference:
|
||||
> drive.** The moment a document needs history, review, or more than one author, a binary format is
|
||||
> actively costing you the thing version control exists to provide.
|
||||
|
||||
The honest counterpoint — where binary formats still earn their place — is in *Where it breaks*.
|
||||
The honest counterpoint, where binary formats still earn their place, is in *Where it breaks*.
|
||||
|
||||
### The document types worth versioning
|
||||
|
||||
@@ -107,9 +107,9 @@ You don't need to convert everything. These are the high-value targets, all natu
|
||||
- **Changelogs** — what changed in each release. A markdown `CHANGELOG.md` is the standard.
|
||||
- **Specs / PRDs** — what you're going to build and why, before you build it.
|
||||
|
||||
For this audience the ADR is the gateway drug: small, structured, high-value, and the kind of thing
|
||||
that *never* gets written because it feels like overhead — right up until the AI will draft it for
|
||||
you in ten seconds.
|
||||
For this audience the ADR is the easiest win: small, structured, high-value, and the kind of thing
|
||||
that *never* gets written because it feels like overhead, right up until the AI drafts it for you in
|
||||
ten seconds.
|
||||
|
||||
### Branch → diff → commit → merge (the new verbs)
|
||||
|
||||
@@ -117,19 +117,21 @@ Module 2 worked on a straight line of commits. A **branch** is a second line you
|
||||
disturbing the first. The mental model: `main` is the version everyone trusts; a branch is a private
|
||||
copy where you draft something, and **merge** folds your finished work back into `main`.
|
||||
|
||||
For a document, the loop is:
|
||||
Creating a branch is one command, and `git branch` shows you which line you're on:
|
||||
|
||||
```bash
|
||||
git switch -c docs/adr-storage # create a branch and switch to it
|
||||
# ...write the doc, with the AI's help...
|
||||
git add docs/adr/0001-storage.md
|
||||
git diff --staged # review exactly what's going onto the branch
|
||||
git commit -m "Add ADR 0001: store tasks as JSON"
|
||||
git switch main # back to the trusted version
|
||||
git merge docs/adr-storage # fold the finished doc into main
|
||||
git branch -d docs/adr-storage # delete the branch; its work is now in main
|
||||
```console
|
||||
$ git switch -c docs/adr-storage
|
||||
Switched to a new branch 'docs/adr-storage'
|
||||
$ git branch
|
||||
* docs/adr-storage
|
||||
main
|
||||
```
|
||||
|
||||
The `*` marks your current branch. From there, the loop for a document is the same handful of verbs
|
||||
every time: **draft** the doc (with the AI's help), **stage** it, read the **diff**, **commit** it on
|
||||
the branch, **switch** back to `main`, then **merge** to fold the finished work in and delete the
|
||||
spent branch. You'll run that whole sequence by hand in the lab; here, just hold the shape.
|
||||
|
||||
Two new-command notes for this audience:
|
||||
|
||||
- **`git switch -c <name>`** creates and moves onto a branch. (Older docs and muscle memory use
|
||||
@@ -143,13 +145,13 @@ Two new-command notes for this audience:
|
||||
Because this is one document on its own branch, the merge is trivial: nothing else touched `main`
|
||||
while you worked, so Git **fast-forwards** — it just slides `main` up to your branch with no
|
||||
conflict. That clean case is the whole reason we practice here first. What happens when two branches
|
||||
edit the *same lines* — a merge conflict — is a real skill, and it gets its own treatment in
|
||||
edit the *same lines* (a merge conflict) is a real skill, and it gets its own treatment in
|
||||
**Module 6**, on code, where the stakes make it worth the depth. Practice the happy path now; the
|
||||
hard path is easier once the verbs are reflexes.
|
||||
|
||||
### The aha: your wiki was a Git repo all along
|
||||
|
||||
Most Git hosts — GitHub, GitLab, Gitea, and others — ship a **wiki** alongside each repository. It
|
||||
Most Git hosts (GitHub, GitLab, Gitea, and others) ship a **wiki** alongside each repository. It
|
||||
looks like a web app: you click "New Page," type in a box, hit save. It feels like a different kind
|
||||
of thing from your code.
|
||||
|
||||
@@ -159,9 +161,9 @@ Every page is a `.md` file. Every "save" in the web UI is a commit. The web edit
|
||||
convenience layer over `git commit`.
|
||||
|
||||
The consequence: the documentation you've been editing in a browser textbox has had full version
|
||||
history — diffs, blame, the works — the entire time. You can clone it, edit the markdown locally with
|
||||
history (diffs, blame, the works) the entire time. You can clone it, edit the markdown locally with
|
||||
the same branch/diff/merge loop you're learning here, and push it back. (Cloning and pushing to a
|
||||
remote repo is **Module 8** — remotes and hosting — so you can't do the clone in *this* lab yet. But
|
||||
remote repo is **Module 8** (remotes and hosting), so you can't do the clone in *this* lab yet. But
|
||||
the realization changes how you see every wiki you'll ever touch: it's not a CMS, it's a repo
|
||||
wearing a web UI.)
|
||||
|
||||
@@ -175,16 +177,16 @@ Here's why this module is more than "learn Git on easy mode":
|
||||
models have — they were trained on oceans of it, and they reach for it by default. Asking an AI to
|
||||
"write an ADR for this decision" or "turn these rough notes into a runbook" plays directly to its
|
||||
strengths. The output is genuinely good and genuinely in the right format, with zero conversion.
|
||||
- **"Draft it, branch it, diff it, merge it" is adoptable tomorrow.** You don't need new tools, a new
|
||||
model, or editor integration. The exact workflow — branch, paste the AI's draft into a `.md` file,
|
||||
read the diff, merge — works today with the browser chat you already have open. Most of the rest of
|
||||
this course unlocks capability you have to build up to. This one you can use on Monday.
|
||||
- **Prose diffs are how you review AI writing.** Same skill as reviewing AI code (Module 10), lower
|
||||
- **"Draft it, branch it, diff it, merge it" works today.** You don't need new tools, a new model, or
|
||||
editor integration. The whole workflow (branch, paste the AI's draft into a `.md` file, read the
|
||||
diff, merge) runs on the browser chat you already have open. Most of the rest of this course is
|
||||
capability you have to build up to; this part you can put to work right now.
|
||||
- **Reading the diff is how you review AI writing.** Same skill as reviewing AI code (Module 10), lower
|
||||
stakes. The AI will write an ADR that *sounds* authoritative and confidently states a rationale it
|
||||
invented. Reading the diff is how you catch "wait, that's not why we did this." The format makes the
|
||||
review possible; your judgment makes it correct.
|
||||
- **It seeds a habit the whole course depends on.** Once "the AI drafts, I review the diff, I decide"
|
||||
is reflexive on documents — where a mistake costs nothing — you'll apply it without thinking when
|
||||
is reflexive on documents, where a mistake costs nothing, you'll apply it without thinking when
|
||||
the AI starts editing code, opening PRs, and running unattended later on.
|
||||
|
||||
---
|
||||
@@ -222,28 +224,35 @@ zero.
|
||||
|
||||
### Part B — Let the AI draft the ADR
|
||||
|
||||
2. Make a home for decision records and copy in the template:
|
||||
2. Make a home for decision records:
|
||||
|
||||
```bash
|
||||
mkdir -p docs/adr
|
||||
# copy modules/03-version-control-for-words/lab/adr-template.md
|
||||
# to docs/adr/0001-task-storage-format.md
|
||||
```
|
||||
|
||||
3. In your browser chat, give the AI the context and the template, and ask for the draft. Something
|
||||
like:
|
||||
3. Open `adr-template.md` from this module's `lab/` folder in the course repo (wherever you downloaded
|
||||
it; it lives in the course repo, *not* inside `tasks-app`). In your browser chat, give the AI that
|
||||
template plus the context and ask for the draft:
|
||||
|
||||
> *"Here's an ADR template (paste `adr-template.md`). Fill it out for this decision: the `tasks-app`
|
||||
> CLI stores its state in a plain `tasks.json` file next to the code. We chose JSON over SQLite or
|
||||
> a hosted database because the app is a single-user local tool and zero-setup matters more than
|
||||
> query power. Keep it concise. Output markdown."*
|
||||
> *"Here's an ADR template (paste the contents of `adr-template.md`). Fill it out for this decision:
|
||||
> the `tasks-app` CLI stores its state in a plain `tasks.json` file next to the code. We chose JSON
|
||||
> over SQLite or a hosted database because the app is a single-user local tool and zero-setup
|
||||
> matters more than query power. Keep it concise. Output markdown."*
|
||||
|
||||
Paste the result into `docs/adr/0001-task-storage-format.md`, replacing the template body. (This is
|
||||
the copy-paste loop from Module 1 — last stretch before Module 4 removes it.)
|
||||
4. Now create the file and paste the draft in. In your editor, make a new file at this exact path
|
||||
inside `tasks-app`:
|
||||
|
||||
```
|
||||
docs/adr/0001-task-storage-format.md
|
||||
```
|
||||
|
||||
Paste the AI's markdown into it and save. (This is the copy-paste loop from Module 1, the last
|
||||
stretch before Module 4 removes it.) The file has to exist on disk before the next part can stage
|
||||
it.
|
||||
|
||||
### Part C — Review the diff before you accept it
|
||||
|
||||
4. A brand-new file is untracked, so `git diff` shows nothing yet. Stage it, then review:
|
||||
5. A brand-new file is untracked, so `git diff` shows nothing yet. Stage it, then review:
|
||||
|
||||
```bash
|
||||
git status # the new file shows as "untracked"
|
||||
@@ -251,12 +260,12 @@ zero.
|
||||
git diff --staged # every line of the new doc, as additions
|
||||
```
|
||||
|
||||
**Read it.** This is the point of the whole module: don't accept AI prose you haven't read. Check
|
||||
the *substance*, not just that it's well-formatted — did it state a rationale you actually agree
|
||||
with, or did it invent a confident-sounding reason? If it's wrong, edit the file and
|
||||
`git add` again.
|
||||
**Read it.** This is the point of the whole module: don't accept AI writing you haven't read. Check
|
||||
the *substance*, not just that it's well-formatted. Did it state a rationale you actually agree
|
||||
with, or did it invent a confident-sounding reason? If it's wrong, edit the file and `git add`
|
||||
again.
|
||||
|
||||
5. When it's right, commit it on the branch:
|
||||
6. When it's right, commit it on the branch:
|
||||
|
||||
```bash
|
||||
git commit -m "Add ADR 0001: store tasks as JSON"
|
||||
@@ -265,7 +274,7 @@ zero.
|
||||
|
||||
### Part D — Make a one-line edit and see the line-based diff
|
||||
|
||||
6. Edit one sentence in the ADR — tighten a line, fix a claim, whatever. Save, then:
|
||||
7. Edit one sentence in the ADR (tighten a line, fix a claim, whatever). Save, then:
|
||||
|
||||
```bash
|
||||
git diff
|
||||
@@ -281,17 +290,25 @@ zero.
|
||||
|
||||
### Part E — Merge it into main
|
||||
|
||||
7. Switch back to `main` and fold in the finished document:
|
||||
8. First, switch back to `main` and prove the document isn't there yet. You created the whole
|
||||
`docs/adr/` directory on the branch, so on `main` it doesn't exist:
|
||||
|
||||
```bash
|
||||
git switch main
|
||||
git log --oneline # note: your ADR commits aren't here yet
|
||||
git merge docs/adr-storage # fast-forward — no conflict
|
||||
git log --oneline # now they are
|
||||
ls docs/adr/ # the ADR is on main
|
||||
ls docs/adr/ # error: "No such file or directory" — it's only on the branch
|
||||
git log --oneline # and your ADR commits aren't here either
|
||||
```
|
||||
|
||||
8. Clean up the branch — its work now lives in `main`:
|
||||
That's branch isolation: the work is real and committed, but completely invisible to `main` until
|
||||
you merge. Now fold it in and watch the file appear:
|
||||
|
||||
```bash
|
||||
git merge docs/adr-storage # fast-forward, no conflict
|
||||
git log --oneline # the ADR commits are on main now
|
||||
ls docs/adr/ # and the file is here too
|
||||
```
|
||||
|
||||
9. Clean up the branch. Its work now lives in `main`:
|
||||
|
||||
```bash
|
||||
git branch -d docs/adr-storage
|
||||
@@ -303,9 +320,9 @@ doing the writing and you doing the reviewing. That's the loop the rest of the c
|
||||
### Optional — do it again as a runbook
|
||||
|
||||
Repeat the loop on a different branch (`git switch -c docs/runbook-restore`) using
|
||||
`lab/runbook-template.md`: ask the AI to write a runbook for "restore the tasks list after someone
|
||||
deletes `tasks.json` by accident" given that the app recreates an empty list on next run. Same five
|
||||
parts. Doing it twice is what turns the commands into reflexes.
|
||||
`runbook-template.md` from this module's `lab/` folder: ask the AI to write a runbook for "restore the
|
||||
tasks list after someone deletes `tasks.json` by accident," given that the app recreates an empty list
|
||||
on next run. Same five parts. Doing it twice is what turns the commands into reflexes.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user