-
Notifications
You must be signed in to change notification settings - Fork 0
03 version control for words
📖 This page is generated from
modules/03-version-control-for-words/README.md. Edit the source, not the wiki; edits here are overwritten on the next sync. Run the hands-on labs from the repo, linked inline.
⬅ Previous: Module 2: Version Control as a Safety Net
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.
-
Module 1: you have the
tasks-appproject, an editor, and a terminal. -
Module 2: you can
init,commit, read adiff, andrestore. This module adds two new verbs to that vocabulary:branchandmerge. They're introduced here, in the lowest-stakes setting possible (a markdown file), and picked up again for real code work in Module 6 (Branches: Sandboxes for Experiments).
You're still working the way you did in Modules 1–2: AI in a browser tab, copy-paste into the file. Editor-integrated AI is Module 4. That's deliberate; practicing branch/merge on documents is exactly the low-risk on-ramp that makes the copy-paste friction tolerable one more time.
By the end of this module you can:
- Explain why plain-text formats (markdown, AsciiDoc) version cleanly while
.docx/.pptxversion uselessly, and make the case to move a runbook or ADR out of Word. - 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.
- Have an AI draft a real engineering document (an ADR or a runbook) and review its work as a diff before accepting it.
- 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.
Module 1 named the three places the copy-paste loop breaks: more than one file, more than one day, no undo. Documents have every one of those problems, and most teams feel them worse than they feel them in code:
- More than one document. A runbook references an ADR that references a spec. Change the decision and three documents are now subtly out of sync, with no record of which changed when.
- More than one day. "Why did we decide to store state as JSON instead of SQLite?" The answer lived in a meeting, or a Slack thread, or someone's head. Six months later it's gone.
-
No undo. Someone edits the runbook during an incident, gets it wrong, and there's no clean way
back to the version that was correct an hour ago.
runbook-final-v2-ACTUAL-use-this.docxis what "no undo" looks like when it metastasizes.
Git fixes all three for documents the same way it fixes them for code, but only if the documents are in a format Git can actually work with. That "if" is the whole argument.
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 built on that one capability. So a format versions well in exact proportion to how well it maps onto lines of text.
Markdown and AsciiDoc are just text. Change one sentence in a markdown runbook and git diff shows
you exactly that:
-Restart the worker with `systemctl restart tasks-worker`.
+Restart the worker with `systemctl restart tasks-worker`, then tail the log for 30s to confirm.That is a perfect change record. A reviewer reads it in two seconds. Two people can edit different sections and Git merges them automatically, because the changes touch different lines.
Now do the same edit in a .docx. A Word document isn't text; it's a zipped bundle of XML, styles,
and metadata. Git happily tracks it, but it can't diff it meaningfully. Ask for the diff and you get:
Binary files a/runbook.docx and b/runbook.docx differ
That's it. That's the entire change record: something changed. You can't see what, you can't
review it, and you can't merge two people's edits; Git will force you to pick one whole file and
throw the other away. The version history exists and is completely useless. .pptx is worse,
because slide decks are even more structure and even less text.
This is a real, defensible engineering argument, not a style preference:
Runbooks, ADRs, specs, and changelogs belong in markdown in the repo, not in Word on a shared 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.
You don't need to convert everything. These are the high-value targets, all naturally plain text:
-
READMEs: how to run the thing. Already markdown by convention; you saw
tasks-app/README.mdin Module 1. - ADRs (Architecture Decision Records): short documents that capture one decision: the context, the choice, and the consequences. The point is to make the reasoning survive the meeting. An ADR lives next to the code, gets versioned with it, and answers "why is it like this?" long after everyone's forgotten.
- Runbooks: the step-by-step for an operational task (deploy, restore, rotate a key, respond to an alert). These get edited under pressure, which is exactly when you want clean history and undo.
-
Changelogs: what changed in each release. A markdown
CHANGELOG.mdis the standard. - Specs / PRDs: what you're going to build and why, before you build it.
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.
Module 2 worked on a straight line of commits. A branch is a second line you can work on without
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.
Creating a branch is one command, and git branch shows you which line you're on:
$ git switch -c docs/adr-storage
Switched to a new branch 'docs/adr-storage'
$ git branch
* docs/adr-storage
mainThe * 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 usegit checkout -b <name>;switchis the newer, clearer verb for the same thing. Either works.) -
git diffshows nothing for a brand-new file until Git is tracking it; new files are "untracked," andgit diffonly compares tracked changes. That's why the loop above doesgit addthengit diff --staged(also spelled--cached): staging tells Git "track this," and--stagedshows you what's staged. For a new file the diff is all-additions, which is fine; you're still reading every line before it lands.
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
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.
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.
It isn't. On essentially every one of these hosts, the wiki is itself a Git repository, a
separate repo, usually addressable as something like your-project.wiki.git, full of markdown files.
Every page is a .md file. Every "save" in the web UI is a commit. The web editor is just a
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 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 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.)
Here's why this module is more than "learn Git on easy mode":
- LLMs are native markdown writers. Markdown is arguably the most fluent output format these 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" 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
.mdfile, 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 the AI starts editing code, opening PRs, and running unattended later on.
Starting point (this lab is skip-friendly). You do not need to have done the earlier labs. To begin from a clean, known state, copy this module's snapshot into a fresh
tasks-appand make the first commit:mkdir -p ~/ai-workflow-course/tasks-app cp -r ~/ai-workflow-course/modules/03-version-control-for-words/lab/start/. ~/ai-workflow-course/tasks-app/ cd ~/ai-workflow-course/tasks-app && git init -b main && git add -A && git commit -m "start: module 3"Already carrying your
tasks-appfrom earlier modules? Keep using it and ignore this box. Lab language: shell (Git commands) plus a little markdown writing, on thetasks-appfrom Modules 1–2. The AI stays in the browser; you copy its draft into the file yourself, exactly as in Module 2.
In this lab you'll branch the repo, have the AI draft an Architecture Decision Record, review it
as a diff, and merge it into main. The document is real and the workflow is real; only the risk is
zero.
You'll need:
- Your
tasks-appfolder, already a Git repo with a clean working tree from Module 2 (git statusshould say "nothing to commit, working tree clean"). - Git installed and your AI assistant open in a browser tab.
- The ADR template from this module's
lab/adr-template.md(andlab/runbook-template.mdif you want to do the variant at the end).
-
Confirm you're starting clean, then create a branch for the ADR:
cd ~/ai-workflow-course/tasks-app git status # want: "working tree clean" git switch -c docs/adr-storage # new branch, named for what it's for git branch # the * shows you're on docs/adr-storage now
You're now working on a copy. Nothing you do here touches
mainuntil you merge.
-
Make a home for decision records:
mkdir -p docs/adr
-
Open
adr-template.mdfrom this module'slab/folder in the course repo (wherever you downloaded it; it lives in the course repo, not insidetasks-app). In your browser chat, give the AI that template plus the context and ask for the draft:"Here's an ADR template (paste the contents of
adr-template.md). Fill it out for this decision: thetasks-appCLI stores its state in a plaintasks.jsonfile 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." -
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.mdPaste 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.
-
A brand-new file is untracked, so
git diffshows nothing yet. Stage it, then review:git status # the new file shows as "untracked" git add docs/adr/0001-task-storage-format.md 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 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 addagain. -
When it's right, commit it on the branch:
git commit -m "Add ADR 0001: store tasks as JSON" git log --oneline # your new checkpoint, on this branch
-
Edit one sentence in the ADR (tighten a line, fix a claim, whatever). Save, then:
git diff
Notice the diff shows only the line you changed, in context. That clean, surgical record is the thing a
.docxcan never give you. Commit it:git add docs/adr/0001-task-storage-format.md git commit -m "Tighten ADR 0001 rationale"
-
First, switch back to
mainand prove the document isn't there yet. You created the wholedocs/adr/directory on the branch, so onmainit doesn't exist:git switch main ls docs/adr/ # error: "No such file or directory", only on the branch git log --oneline # and your ADR commits aren't here either
That's branch isolation: the work is real and committed, but completely invisible to
mainuntil you merge. Now fold it in and watch the file appear: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
-
Clean up the branch. Its work now lives in
main:git branch -d docs/adr-storage
You just ran the complete branch → draft → diff → commit → merge loop on a real document, with the AI doing the writing and you doing the reviewing. That's the loop the rest of the course runs on.
Repeat the loop on a different branch (git switch -c docs/runbook-restore) using
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.
-
Line-based diffs punish reflowed paragraphs. Git diffs lines. If you (or the AI) rewrap a
paragraph so every line shifts, the diff shows the whole paragraph as changed even if you altered
three words; the clean diff degrades toward
.docx-style noise. The fix the technical-writing world uses is semantic line breaks: write one sentence (or one clause) per line, so edits stay local and diffs stay surgical. Worth knowing the AI will not do this by default; you can ask it to. -
Plain text isn't free of binaries. A markdown doc with screenshots still carries
.pngfiles, and Git diffs those as "binary files differ" just like a.docx. Git tracks and stores them fine; it just can't show you what changed inside them. Diagrams-as-code (text formats that render to pictures) sidestep this, but that's beyond this module. - Word and PowerPoint still exist for reasons. A pixel-precise client deliverable, a slide deck with heavy layout, a document a non-technical stakeholder must edit in a tool they already know. These are real constraints. The argument isn't "markdown for everything." It's "anything that needs history, review, or multiple authors is paying a steep tax in a binary format." Pick the targets where that tax actually bites: runbooks, ADRs, specs, changelogs.
-
Merge conflicts are real; you just didn't hit one. This lab fast-forwarded because nothing else
touched
main. The moment two branches edit the same lines, Git stops and asks you to resolve it. That's a genuine skill, deferred to Module 6 on purpose so you learn it where the stakes make it matter. - The wiki-clone aha needs a remote. You can see that a host's wiki is a Git repo now, but cloning it, editing locally, and pushing back requires remotes, which is Module 8. The realization is yours today; the round trip waits a few modules.
- The AI writes confident fiction. It will produce a fluent ADR with a rationale that sounds exactly like something a senior engineer wrote, and is sometimes simply made up. The format makes the document reviewable; it does not make the document true. Reading the diff is necessary, not sufficient. You still have to know whether the reasoning is right.
You're done when:
- Your
tasks-apprepo has andocs/adr/0001-*.mdonmain, authored by the AI and reviewed by you, arrived there via a branch and a merge. - You created a branch, committed to it, merged it back, and deleted it;
git log --onelineonmainshows the ADR commits. - You can explain, to a skeptical colleague, why the team's runbooks shouldn't be
.docxfiles on a shared drive, using the line-based-diff argument, not just "markdown is nicer." - You know that your Git host's wiki is itself a Git repo, and what that implies.
When branch/diff/commit/merge feels routine on a document, you're ready for Module 4, where the AI finally comes out of the browser and starts editing your files directly, a step that's only safe because you can now branch, diff, and revert exactly what it does.
Continue to: Module 4: Getting the AI Out of the Browser ➡
Generated from the ai-workflow-course repo • the model is the cheap, swappable part; the workflow is the durable skill.
Unit 1: Get out of the chat window
- 1 · The Copy-Paste Problem
- 2 · Version Control as a Safety Net
- 3 · Version Control for Words, Not Just Code
- 4 · Getting the AI Out of the Browser
- 5 · Commit the AI's Config, Not Just the Code
- 6 · Branches as Sandboxes for Experiments
- 7 · Worktrees for Running Agents in Parallel
Unit 2: Make it shareable, reviewable, recoverable
- 8 · Remotes and Hosting (GitHub, the Alternatives, and Owning Your Repo)
- 9 · Issues and the Task Layer
- 10 · Reviewing Code You Didn't Write
- 11 · Collaboration: Humans and Agents on One Repo
- 12 · When It Goes Wrong: Revert, Reset, and Recovery
Unit 3: Automate the checking and shipping
- 13 · Testing in the AI Era
- 14 · Continuous Integration
- 15 · Security Scanning for AI-Generated Code
- 16 · Containers and Reproducible Environments
- 17 · Secrets, Config, and Environments
- 18 · Continuous Delivery and Deployment
- 19 · Runners, the Compute Behind the Automation
Unit 4: Extend the AI into your systems
- 20 · MCP Servers, Giving the AI Hands
- 21 · Skills: Teaching the AI Your Playbook
- 22 · Securing Third-Party MCP Servers and Skills
- 23 · Working with Existing Codebases
Unit 5: AI in the Loop
- 24 · Assistive Agents (AI Review and Issue Triage)
- 25 · Module 25. Autonomous Agents: Issue-to-PR and Self-Healing CI
- 26 · Orchestrating Multiple Agents
- 27 · Module 27. Evals: Trusting an Agent That Acts Without You
Finale