Engineering

Git for People Who Use Agents: Branches, Small Commits and How to Go Back

Agents edit code very fast, and sometimes get it wrong very fast. This post explains Git with the picture of save points in a game: one branch per task, small commits, reading the diff before you accept, and safe ways to go back, with real output from a practice repository.

  • #git
  • #AI agent
  • #branches
  • #commits
  • #undo
  • #worktree
  • #checklist

Slide deck

Click the slides, then use the arrow keys to move. Press L to change language and F for full screen.

Open full screen

For anyone who hands code work to an AI agent, including people who have never used Git. No background needed. Every term comes with an everyday picture, and the parts with commands are marked so you can copy them or skip them.

Every command and output in the worked example was really run in a practice repository (Git version 2.56.0, 30 October 2026). Scenarios marked "illustration" are made up and name no real person or company. How an agent goes wrong inside is not fully understood by anyone, so the pictures below are memory aids only.


Quick summary#

  • An agent can edit many files in minutes. Without a way back, one bad edit can swallow a whole working session. Git is the save point: it remembers only what you have committed.
  • The core habit: one branch per task you give the agent, ask the agent for small commits, and read git status and then git diff before accepting the result.
  • There are four ways back, each for its own situation: git restore (not committed yet), git revert (already committed, the safest), git reflog (rescue after a slip), git worktree (let the agent work in its own folder from the start).
  • The biggest blind spot: uncommitted changes that are discarded with git restore cannot be recovered. In this post's practice repository, the reflog had no entry for them.
  • Save points only cover files in the repository. A deleted database or a sent email lies outside Git.
  • Destructive commands (push --force, reset --hard, clean) belong in the agent's instructions as do not run without asking.

Hard words, plain meaning#

Term Plain meaning
Repository The project folder plus the whole history of its saves.
Commit (save point) One save with a name and a note, like pressing "save game" at one spot. You can always return to it.
Branch A separate path split off from the main copy, for trying things without breaking the main copy.
Diff The exact list of which lines were added and which were removed since the last save point.
Revert Make a new save point that does the opposite of an older one. The history stays intact.
Reset Move the branch back to an older save point. With --hard, uncommitted changes are deleted.
Reflog (movement log) A notebook listing in order where the HEAD pointer has stood, used to find a save point that seems to have vanished.
Stash Put work in progress into a temporary drawer so your hands are free, and take it out later.
Worktree A second folder of the same repository, standing on another branch, like a separate desk.

1. A picture first: a game with save points#

Picture a long game. If you never save, dying once costs you an hour of play. If you save every few minutes, dying costs a few minutes.

Handing work to an agent is the same. An agent is a very fast, slightly hasty player: it can edit ten files before you finish reading the first. It is good but not always right, and the documentation of agent tools says as much (see section 6). A save point does not make the agent err less. It makes the error cheaper.

Git plays that role, with one important rule: Git remembers only what has been committed. Changes sitting in the folder without a commit are like playing mid-level without saving.

Takeaway: before you hand over a task, have a clean save point. While the agent works, ask it to save often.


2. The five-step routine: one branch per task#

Picture a dinner table with several trays: you do not try a new dish on the main plate, you put it on a separate plate. If it fails, you throw the plate away and the main plate is untouched.

Everything below was run in a practice repository with one file, prices.py, which adds up an order total. There is one first save point on the branch main.

Step 1. Make a branch for this task#

git switch -c agent/add-discount
Switched to a new branch 'agent/add-discount'

The naming habit agent/task-name lets you see at a glance which branches belong to the agent. It is my habit, not a Git rule.

Step 2. Hand over the task and let the agent work#

You ask the agent: "add an optional discount parameter to the total function". The agent edits the file.

Step 3. Read git status and then git diff before accepting#

git status -sb
git diff
## agent/add-discount
 M prices.py
diff --git a/prices.py b/prices.py
index de87eb8..d7bc76f 100644
--- a/prices.py
+++ b/prices.py
@@ -1,2 +1,3 @@
-def total(items):
-    return sum(item["price"] * item["qty"] for item in items)
+def total(items, discount=0):
+    subtotal = sum(item["price"] * item["qty"] for item in items)
+    return subtotal * (1 - discount)

M means one file was modified. A line starting with - was removed, a line starting with + is new. This reading is the "open the evidence" step from Make AI Output Prove Itself, and the first part of reviewing AI-written code.

Step 4. Commit small, like a save point#

git add prices.py
git commit -q -m "feat: add optional discount to total"
git log --oneline
c9c7cf3 feat: add optional discount to total
6dd4973 feat: add total function

The -q flag only keeps the command quiet. One job per commit, describable in a sentence, in the feat: job name style of Conventional Commits (a popular note-writing convention, not mandatory).

Step 5. Merge when you are satisfied#

When you have read the diff and run the checks, you are the one who merges the branch into main:

git switch main
git merge --no-ff -q agent/add-discount -m "merge: add discount"
git log --oneline --graph
*   04cbf8d merge: add discount
|\  
| * 5aee66b feat: add extra script
| * c5b6fbf Revert "refactor: simplify total"
| * 6f88dd0 refactor: simplify total
| * c9c7cf3 feat: add optional discount to total
|/  
* 6dd4973 feat: add total function

The main branch only receives what you have looked at. The middle save points (refactor, Revert, extra script) come from the experiments in section 3.

2.1 A calculation you can redo (illustration, skippable)#

This is an example with made-up numbers. Suppose an agent works for 3 hours (180 minutes) without a break and something goes wrong in the last minute.

session = 180
no_commit_loss = session            # never saved: lose up to 180 minutes
every = 20
saves = session // every            # 9 save points
worst_loss = every                  # lose at most 20 minutes
print(saves, worst_loss, session - worst_loss)
# 9 20 160

Reading the result: committing every 20 minutes gives 9 save points, and the worst accident costs at most 20 minutes instead of 180, so 160 minutes are kept. The 20 minutes is my assumption for the illustration. Real life has no formula, but the rule is to make steps small enough to look back at and dare to throw away.


3. Going back: the right command for the right situation#

Picture accidentally deleting a paragraph. How you get it back depends on whether you had saved the document.

Situation Command What happens Risk
The agent just edited wrongly, nothing committed git restore file-name The file goes back to the last committed version Uncommitted changes are lost for good
A commit exists and is wrong git revert HEAD A new commit undoes it, history stays Safe
Work in progress, you need free hands git stash push -m "note" Put aside, later git stash pop Safe
You need to pull the branch back to an older point git reset --hard save-point The branch moves back, uncommitted changes are deleted Dangerous, commits can be rescued with reflog
You slipped on a reset git reflog then git reset --hard HEAD@{n} Find where HEAD used to be Rescues commits, not uncommitted changes

3.1 git restore: discard uncommitted changes#

The agent edits the file into a useless function:

git status -sb
git diff --stat
git restore prices.py
git status -sb
## agent/add-discount
 M prices.py
 prices.py | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
## agent/add-discount

After restore, git status no longer shows the M line, meaning the file is back to the committed version. Warning: if the discarded change was something you wanted to keep, there is no way back. I tested it: edit the file, run git restore, then look at the reflog and the stash list.

git reflog | head -2
git stash list | wc -l
5aee66b HEAD@{0}: reset: moving to HEAD
5aee66b HEAD@{1}: reset: moving to HEAD@{1}
       0

The two reflog lines belong to earlier operations. There is no record for the discarded line, and the stash list is empty (0 entries). The git restore manual page describes the command as restoring content from a source, so the current content is replaced. To keep it, git stash first, or commit first.

3.2 git revert: undo an existing commit#

The agent commits a "simplification" that breaks the function:

git commit -qam "refactor: simplify total"
git revert --no-edit HEAD
git log --oneline
[agent/add-discount c5b6fbf] Revert "refactor: simplify total"
 Date: Fri Oct 30 17:31:17 2026 +0700
 1 file changed, 2 insertions(+), 1 deletion(-)
c5b6fbf Revert "refactor: simplify total"
6f88dd0 refactor: simplify total
c9c7cf3 feat: add optional discount to total
6dd4973 feat: add total function

The broken commit stays in the history, and a new commit undoes it. According to the Git documentation, git revert creates new commits that undo earlier ones instead of deleting them. Because it does not rewrite history, it is the safe choice on a shared branch.

3.3 git reset --hard then git reflog: a slip can still be rescued#

This is the scariest part, so I ran it for real. Add one more commit, then step back two:

git reset --hard HEAD~2
git log --oneline
ls
HEAD is now at 6f88dd0 refactor: simplify total
6f88dd0 refactor: simplify total
c9c7cf3 feat: add optional discount to total
6dd4973 feat: add total function
prices.py

The file extra.py disappeared from the folder, and the function in prices.py went back to the broken version. But the reflog remembers:

git reflog | head -8
6f88dd0 HEAD@{0}: reset: moving to HEAD~2
5aee66b HEAD@{1}: commit: feat: add extra script
c5b6fbf HEAD@{2}: revert: Revert "refactor: simplify total"
6f88dd0 HEAD@{3}: commit: refactor: simplify total
c9c7cf3 HEAD@{4}: commit: feat: add optional discount to total
6dd4973 HEAD@{5}: checkout: moving from main to agent/add-discount
6dd4973 HEAD@{6}: commit (initial): feat: add total function

The save point 5aee66b is still there. Set the branch back to it:

git reset --hard HEAD@{1}
git log --oneline
ls
HEAD is now at 5aee66b feat: add extra script
5aee66b feat: add extra script
c5b6fbf Revert "refactor: simplify total"
6f88dd0 refactor: simplify total
c9c7cf3 feat: add optional discount to total
6dd4973 feat: add total function
extra.py
prices.py

Everything is back. According to the Git documentation, reflog entries are kept for 90 days by default, and 30 days for entries no longer on any branch, so rescue early. The reflog is a notebook on your machine and is not pushed to the server.

3.4 git stash: put work in progress aside#

git stash push -m "half done idea"
git stash list
git stash pop
Saved working directory and index state On agent/add-discount: half done idea
stash@{0}: On agent/add-discount: half done idea
Dropped refs/stash@{0} (377cf291f166fc06e84e9ac41e27da37fa79d8d9)

Between the two commands, git status was clean. After pop, the changes came back. Use it when you want free hands to let the agent do something else, without making a half-baked commit.

Takeaway: remember one sentence: what is committed can almost always be rescued, what is not committed cannot. That is why you commit small.


4. Worktree: give the agent its own desk#

Picture a kitchen with two counters: you cook at one, the assistant cooks at the other. Same kitchen, same pantry, but you do not bump elbows.

A worktree is a second working folder of the same repository. According to the Git documentation, it shares the repository with the main folder but has its own HEAD and index, and by default Git does not let two worktrees stand on the same branch.

git worktree add ../demo-git-wt -b agent/refactor-names
git worktree list
Preparing worktree (new branch 'agent/refactor-names')
HEAD is now at 5aee66b feat: add extra script
/path/to/demo-git    5aee66b [agent/add-discount]
/path/to/demo-git-wt 5aee66b [agent/refactor-names]

(I shortened the paths to /path/to/ for readability.) Now the agent works in demo-git-wt while you keep editing in the main folder. When it is done, clean up:

git worktree remove ../demo-git-wt
git branch -d agent/refactor-names
Deleted branch agent/refactor-names (was 5aee66b).

Without --force, git worktree remove only removes a clean folder. Claude Code has a shortcut, claude --worktree job-name, that opens a session in a new worktree, according to its Common workflows page. Other tools may have their own way, so check the documentation of the tool you use.


5. House rules for the agent#

Picture handing a house key to a helper: you say which rooms they may enter and which not.

5.1 Habits worth writing down as rules#

  • Do not commit straight to main. One branch per task.
  • No push --force, and no pushing without asking. Pushing to a server is an action other people see.
  • No reset --hard, no clean, no deleting branches without asking. git clean deletes files Git is not tracking, so I treat them as having no copy to rescue.
  • Do not touch files that hold keys, such as .env. Let .gitignore block them, and check with git check-ignore -v .env.
git check-ignore -v .env
.gitignore:1:.env	.env

The line says the rule on line 1 of .gitignore is blocking the file .env. (In the practice repository my environment would not let me create a real .env file, so I only checked the rule and did not try git status with a real file.)

5.2 Five lines to paste into the agent's instructions#

Put this block in AGENTS.md or your tool's instruction file:

## Git
- Work on a branch named agent/<task-name>, never commit straight to main.
- Commit small, one job per commit, run the checks before committing.
- Do not use push --force, reset --hard, clean or delete branches without asking.
- Do not push. Do not edit .env or any file that holds keys.
- At the end: paste the output of git status and git diff --stat.

This is guidance written in words, and an agent may ignore it. It is the first barrier, not the only one: also use the tool's permission settings and the branch protection of your code hosting service, if available.

5.3 What an agent's commit note should look like#

feat: add optional discount to total

- discount defaults to 0, so existing callers keep working
- checked with: python -m pytest tests/test_prices.py (3 passed)

The first line says what, the body says why and how it was checked. The note is itself a small piece of evidence, in line with way 2 in Make AI Output Prove Itself.


6. Numbers and documents used#

Source Says How to read it Caveat
Git, git-restore page Restores paths from a source, current content is replaced Basis for the warning about losing uncommitted changes The page does not say outright that it cannot be recovered, that is the result I tested
Git, git-revert page Creates new commits that undo earlier ones, without deleting them Basis for section 3.2 Needs a clean folder when reverting
Git, git-reflog page Records where references used to be. Kept 90 days by default, 30 days for entries no longer on a branch Basis for section 3.3 Only on your machine
Git, git-worktree page A linked worktree shares the repository, with its own HEAD and index. By default no two places on one branch Basis for section 4 remove needs --force if the folder is not clean
Claude Code docs, Checkpointing Checkpoints track edits made by file tools. They do not track files changed only by Bash, usually do not restore subagent edits, and are not a replacement for version control Why Git is still needed A tool maker's documentation, may change by version
Claude Code docs, Common workflows claude --worktree job-name runs a session in its own worktree, and needs a repository with at least one commit Basis for the shortcut in section 4 About this tool only
News reports (Tom's Hardware, heise) on the Replit case, July 2025 An agent was reported to have deleted a company's production database during a code freeze Git save points do not cover a database Most details come from posts by the person involved, and sources differ on recoverability
The practice repository in this post Every command in sections 2 to 5 was really run The output is real One very small repository, one machine, Git 2.56.0, not a survey

Read it correctly: the Git and Claude Code documents support using save points and separate branches. I did not find a study measuring how much a separate branch reduces incidents when using agents, so the habits above are good practice, not measured results.


7. Where save points still fail#

Picture saving the game on this machine while the character has already done something in the real world outside.

Situation Why it fails How to avoid or catch it
Uncommitted changes hit by restore or reset --hard Git has no copy Commit or stash first, commit small and often
The agent runs git clean Untracked files have no copy in Git Forbid it in the rules, add important files to Git
The agent pushes, especially --force Changes are on the server, others pull them Do not allow pushes, protect the main branch, never --force
A key leaks into a commit The key lives in the history, revert does not erase it Use .gitignore, and treat a leaked key as one you must replace
Things outside the repository: deleting a database, sending mail, calling a paid API Git stores only files Separate test environments, limit permissions, see the post on fake packages about permission to run commands
A Bash command changes a file the tool is not tracking The tool's checkpoint does not cover it Rely on Git, not only on an undo button
Too many mixed commits Hard to tell which point is good One job per commit, clear notes

7.1 Illustration: a morning with an agent#

This is an illustration, naming no real person or product.

  • 09:00. The dev creates the branch agent/add-discount and assigns the job "add a discount to the total function".
  • 09:20. The agent says it is done. The dev runs git diff --stat and sees that one file changed more than expected. On a closer look, the agent rewrote the whole old function.
  • 09:25. Nothing is committed yet, so the dev has two choices: git restore (lose everything, including the good part) or git stash and then pick what is needed. The dev chooses stash, keeps the good part, and asks the agent to redo the rest more tightly.
  • 10:10. The agent commits a second time. The dev notices this commit breaks a test and runs git revert HEAD. The history stays, the function goes back as before.
  • 10:30. The dev merges into main after reading the diff.

What to do: commit early, read the diff before accepting, and get used to stash and revert more than restore and reset. This illustration proves nothing. The evidence lies in the documents above, and in one real case worth remembering: 2025 news reports said that during a trial by a founder, an agent was reported to have deleted a production database despite a code freeze. The sources disagree on details such as recoverability, and most of the information comes from the person involved. If it happened as told, it was about a database, not files, which lies outside what Git save points cover.


8. Habits to apply from tomorrow#

8.1 Eight questions before handing over and before accepting#

  1. Am I on this task's own branch, or on main?
  2. Before handing over, is git status clean, or is there unsaved work in progress?
  3. Does the agent know the Git rules (own branch, small commits, no push)?
  4. After the agent worked, have I read git status and git diff?
  5. Was any file changed that I did not ask for?
  6. Is there anything that looks like a key or a password in the diff?
  7. If I drop this edit, do I use stash, restore or revert, and am I losing anything uncommitted?
  8. Does this job touch anything outside the repository (database, mail, API)?

8.2 Three things to do right now#

  1. Paste the five-line block from 5.2 into the instruction file of the tool you use.
  2. Try once in a scratch repository: reset --hard, then reflog, then set it back, so you do not panic when it matters.
  3. Turn on protection for the main branch on your code hosting service, if it has one.

9. A balanced view: what Git does and does not do#

What it does: gives you save points, lets you try things without fear, allows several jobs in parallel through worktrees, and turns every change the agent makes into a readable diff.

What it does not do:

  • It does not cover things outside the repository: databases, sent mail, money moved.
  • It cannot rescue uncommitted changes.
  • It does not stop an agent from doing something bad, it only helps you go back after it happens. Prevention needs permissions and rules.
  • Learning Git has a cost. For a newcomer, the few commands in this post are enough to start. Harder cases such as merge conflicts take more time to learn.
  • I have not seen a controlled trial measuring the effect of each habit. Try them in your team and adjust.

Do not exaggerate: Git is not a safety switch. Do not play it down: most accidents when using agents on files can shrink to "lost 20 minutes" if a save point is close by.


10. Conclusion#

Agents are fast, and fast even when wrong. Give each task its own branch, ask it to save often, read the diff before accepting, and remember four ways back: restore for the uncommitted part (and understand it is a real loss), revert for an existing commit, reflog to rescue after a slip, worktree so each agent has its own desk. A save point does not make the agent err less, but it makes you less afraid.


References#

Commands and facts rest on public documentation and a practice repository run on 30 October 2026 (Git 2.56.0). The news reports on the Replit case mostly retell the posts of the person involved, so open the originals before quoting.

Frequently asked questions

Why do I need Git when my agent tool already has an undo feature?
The Claude Code documentation says its checkpoints are meant for quick session-level recovery: they do not track changes made by Bash commands to files the agent has not edited with its file tools, usually do not restore subagent edits, and are not a replacement for version control. Git keeps long-term history and works with any tool.
Which command should I use to throw away what the agent just did?
If nothing is committed, git restore file-name puts the file back to the last committed version, but the uncommitted part is gone for good. If it is committed, git revert makes a new commit that undoes it and keeps the history, so it is safe. Git reset --hard moves the whole branch back and deletes uncommitted changes, so use it only when you understand it.
If I run git reset --hard by mistake, can I get my work back?
For commits, usually yes: git reflog records where the branch and HEAD used to be, and you can set it back with git reset --hard HEAD@{1} (the number depends on the entry). By default reflog entries are kept for 90 days, and for 30 days when they are no longer on any branch. Uncommitted changes leave no record to rescue.
What is git worktree good for with agents?
A worktree gives you an extra working folder tied to the same Git repository and its own branch. The agent works there without touching the files you are editing, and two jobs in parallel do not step on each other. Claude Code has a built-in option, claude --worktree job-name, for this.
Should I let an agent push to main by itself?
No. Let the agent work on its own branch and only commit. You read the diff and then push or merge yourself. Never use push --force. Many code hosting services have branch protection for the main branch, so turn it on as a second barrier.