Chapter 8: Git Without Tears
If you have heard programmers complain bitterly about something called “git,” and you have no idea what they were talking about, this chapter is for you.
This chapter starts further back than any other chapter in the book, because most clinicians have never met git, and the rest of this book gets harder if you haven’t.
The medical-records analogy
Imagine if every time you saved a chart in the EMR, the EMR also kept a copy of what the chart looked like before you saved. And the copy was tagged with who made the change, when they made it, and a short note explaining why. And the copies stretched back to the day the chart was created. And you could, at any time, ask the EMR, “show me what this chart looked like last Tuesday,” and the EMR would show you. And if a change turned out to be a mistake, you could roll back to the version before — without losing anything else.
That is git. It is a version-controlled backup system, originally built for source code, that keeps the full history of every file in a project. Every saved change is permanent. Every saved change is reversible. Every saved change is attributed to a person and a moment in time.
For software, this turns out to be life-changing. Every line of every file in the project has a recorded history. If a bug appears, you can find the exact change that introduced it. If two people edit the same file at the same time, git helps merge their work. If you want to try an experimental change without disturbing the working version, git lets you do that in a parallel copy and switch between them.
🧠 Remember. Git is version-controlled history for the files in your project. It is the safety net that lets you experiment without fear.
The vocabulary — one sentence each
You will hear these words in every git-flavoured conversation. Memorize the meaning, not the word.
- Repository (often shortened to repo) — a project whose history is tracked by git. Usually one folder on your computer.
- Commit — one saved snapshot in the history. Each commit has a message explaining what changed and why.
- Branch — a parallel line of work. The default branch is usually called
main. You can make a new branch, work on it, then merge it back intomainwhen ready. - Merge — combining the work from one branch into another.
- Remote — a copy of the repository that lives somewhere else (usually a service like GitHub).
- Push — send your local commits up to the remote.
- Pull — fetch new commits from the remote down to your local copy.
- GitHub — the most popular service for hosting remote repositories. Has a website where you can view history, review changes, and collaborate.
- Pull request (or PR) — a proposal to merge one branch into another, with a place for teammates to comment and approve before the merge happens.
That’s the whole vocabulary you need to start. Everything else builds on those nine words.
The good news: Claude Code does almost all of this for you
If that vocabulary list looked intimidating, here is the good news. Claude Code knows git. You will rarely type a git command yourself. You will mostly tell Claude what you want, in plain English, and Claude will run the right git commands.
You can ask Claude to:
- Stage your changes (mark which files to include in the next commit).
- Write a commit message that actually reflects what you changed.
- Commit.
- Push the commits up to GitHub.
- Show the history.
- Create a new branch.
- Open a pull request.
All of those happen under the hood as ordinary git commands run by Claude through the Bash tool. There is no proprietary magic.
Stage the changes in @notebooks/aki_extraction.py and write
a commit message that explains why the baseline computation
changed.
Claude reads the diff, drafts a commit message that reflects the actual change, shows you both, and waits for you to approve before committing.
🧠 Remember. Claude knows what the code changed. It does not know why you changed it. The commit message will be only as good as the diff makes the intent obvious. If the change is half-finished and Claude writes a vague message, the fix is to finish the change, not to rewrite the message.
Reading the diff before you approve
Here is the single most important habit in this chapter.
Always read the diff before you say “commit.”
A “diff” is a side-by-side view of what changed: lines removed in red, lines added in green. Claude will show it to you. You read it. You catch:
- The print statement Claude left in for debugging.
- The unrelated whitespace change that crept into a file Claude was supposed to only read.
- The hardcoded path that should have been a variable.
- The accidental deletion of a comment that explained something important.
If you don’t read the diff, none of those land where they should — they land in your main branch, and then you spend Friday afternoon undoing them.
⚠️ Warning. It is faster to read a diff than to revert a commit. Always. No exceptions.
A first real session
Let’s walk through what it actually looks like, with a complete example. Suppose you are working on the AKI Notification Pipeline (Chapter 0.5). You have just fixed a small bug in the baseline-creatinine calculation.
You tell Claude:
Stage the change. Show me the proposed commit message before
committing.
Claude runs git diff to see what changed, drafts a message, and prints something like:
fix(aki): use median of pre-admission creatinine for baseline
Previously the baseline used the minimum value, which underestimated
baseline in patients with a single low outlier. Switched to median
over the 90-day pre-admission window. KDIGO 2024 conformance
unchanged.
Files changed: notebooks/aki_extraction.py
Lines: +4 / -2
You read it. The message is accurate. The lines reported match what you remember changing. You say:
Commit it.
Claude runs git commit with the message. Done. The change is now in your history.
Now you decide to push it up to GitHub:
Push to the remote.
Claude runs git push. The commit travels up to the GitHub server.
You open your browser, go to github.com/khcc-aidi/aidi-extractions, and the new commit is sitting there at the top of the history. You can click it and see the diff Claude just committed. Anyone on your team can see it now too.
That is a complete git workflow. Total time: under a minute. Time you spent typing git commands yourself: zero.
💡 Tip. Put your team’s commit-message conventions in
CLAUDE.md(Chapter 10): “Use conventional commits. Subject under 70 chars. Body explains the why, not the what.” Claude will follow this forever after.
Pull requests, briefly
Once you have multiple commits on a branch and you want to merge them into main, the polite way to do it — especially on a shared project — is to open a pull request (PR). A PR is a proposal: “here are my changes; please review and approve before they go into main.”
Claude can open a PR for you:
Push the current branch, open a draft PR against main, and
write a description summarizing the three commits I just made.
Title under 70 chars.
Claude will:
- Push your branch to the remote.
- Read the commits you have made.
- Run
gh pr create --draft(the GitHub command-line tool) with a title and description. - Print the URL of the new PR.
You click the URL. You see the PR in your browser. You finish the description if needed, and when you are ready you click “ready for review.” A teammate looks at it, comments, approves, and merges.
We don’t dive deeper into PRs in this chapter. The full picture — code review, branching strategies, multiple parallel branches — is covered later, especially in Chapter 16 on git worktrees. For now, know that a PR exists and Claude can open one for you.
🔧 Technical Stuff.
ghis GitHub’s official command-line tool — a free install, separate from git itself, though many developer setups already include it. Claude prefersghover more elaborate integrations because the output is cleaner and uses less of the context window.
Two things Claude will not do without an explicit instruction
There are two git operations powerful enough that Claude Code is deliberately cautious about them.
git commit --amend— this rewrites the previous commit. If you have already pushed that commit and a teammate has based work on it, an amend will rewrite history in a way that breaks their copy.git push --force— this rewrites the remote branch’s history. Same problem, bigger blast radius. Onmain, it can erase teammates’ work.
Claude will warn you if you ask for either. On a shared branch (especially main), Claude will push back. You can override, but you have to mean it.
⚠️ Warning.
git push --forcetomainhas ended careers. Don’t ask Claude to do it. If you absolutely must rewrite shared history, do it yourself, slowly, with the team aware.
A related one: --no-verify is a flag that skips pre-commit hooks. Pre-commit hooks are little safety checks that run before each commit (lint your code, run a quick test). They exist for a reason. Claude will not bypass them by default. If a hook is failing, the answer is to fix what the hook is complaining about, not to skip it.
The checkpoint system vs. git
Recall from Chapter 6 that Claude Code has its own local checkpoint system: every file edit creates a snapshot, and /rewind or Esc-Esc lets you roll back without using git.
Checkpoints and git are not the same thing.
- Checkpoints are local and temporary. They live on your machine, get cleaned up automatically after a few weeks, and capture only Claude’s own file edits — not changes made by shell commands.
- Git is durable, shareable, and permanent. It survives a laptop crash. It travels to GitHub. It is reviewable by your team months later.
Use checkpoints liberally — they cost you nothing. Use commits deliberately — each one is a permanent record.
🧠 Remember. Checkpoint first, commit second. Checkpoint when you want to be able to undo the last fifteen minutes. Commit when the work has reached a state worth keeping forever.
A KHCC walkthrough: a clinician’s git day on aidi-extractions
You start the morning with a bug report: the Chemotherapy Preparation Checker (Chapter 0.5) is missing the protocol name for cyclophosphamide-based regimens. You open Claude Code.
/clear
Open @notebooks/chemo_prep_extractor.py. There's a bug:
cyclophosphamide protocols are returning null for protocol_name.
Find the cause, fix it, and explain what you changed.
Claude reads the file, finds the regex that misses “cyclo-“ prefixed names, proposes a one-line fix, and shows you the diff. You read it. It is clean — one line of regex, one line in the test. You approve.
Stage the change. Show me the proposed commit message.
Claude proposes:
fix(chemo): handle cyclo-prefixed protocol names
The protocol-name regex required a word boundary that excluded
hyphen-prefixed variants like "cyclo-CHOP". Loosened the boundary
and added a unit test for the variant.
You approve. Claude commits.
Run the test suite.
Claude runs the tests. All green.
Push the branch and open a draft PR against main. Title under
70 chars. Include a test plan with three boxes: unit tests
pass, eval cohort re-run, downstream alert volume check.
Claude pushes the branch, opens the draft PR, prints the URL. You click it. You review it in the browser. You toggle “ready for review.” You go get coffee.
Total time: about eight minutes. Time spent on git plumbing: zero. Time spent reading the diff and judging the change: about three minutes. That is the right ratio.
🧠 Remember. You are the reviewer. Claude is the typist. Don’t reverse those roles.
Try This
- In any repository, make a small change — a typo fix in a comment, even. Ask Claude to stage the change, write a commit message, and show you the message before committing. Read the message. Edit if needed. Then commit.
- After the commit, open the project on GitHub.com (if it has a remote). See the commit in the history. Click it. See the diff. This is what your teammates will see.
- Open a draft PR through Claude. Read the body Claude wrote. Notice whether it tells you something useful or whether it is too vague (if too vague, the underlying changes probably need a clearer story, not the PR description).
- Practice the discipline: every time Claude proposes a commit, read the diff first. Build the muscle.
Watch Out
- Don’t trust a commit message without reading the diff. The message reflects the diff, not your intent. If the diff is wrong, the message will be confidently wrong.
- Don’t
--forcepush on a shared branch. If Claude proposes it, push back. Find out why. - Don’t
--no-verifyto skip a failing hook. Fix what the hook is complaining about. - Don’t confuse checkpoints with commits. Checkpoints rescue you during a session. Commits are the durable record. You need both.
- Don’t let Claude do git on a project that has no remote backup. If you are new to this, push your repo to GitHub (or another remote) before doing serious work. Git is your safety net only if it actually exists in two places.