Claude Code can change forty files in ninety seconds. Command+Z in your editor undoes changes in one file, in one window, until you close it.
That gap is why version control matters more to you than to a developer typing every line by hand. You are approving work you did not write, at a speed you cannot proofread.
The idea
Git takes a snapshot of your entire project whenever you ask, attaches a message and a timestamp, and keeps it. A snapshot is a One saved snapshot of the whole project, with a message saying what changed and why., and the folder holding your project plus all of its snapshots is a A project folder that git is tracking, including the full history of every snapshot you have made in it.. Returning to any snapshot is one command and about a second.
main A ----- B ----- C ----- D <- history, oldest to newest. D is where you are.
|
\-- E ----- F branch: risky-refactor
same history up to C, then separate
git merge brings E and F back into main
Working tree -> git add -> Staging -> git commit -> History
(your files) (chosen (saved)
changes)How it works
- The working tree is your files as they are right now. Git watches them and records nothing
until you tell it to. Your line of commits has a name, and by default that name is
main. - Staging is the holding area you put changes into before saving them. It exists so you can save
two unrelated fixes as two commits, and until you need that,
git add -Abefore each commit stages everything. - A commit writes the staged changes into history with your message:
git commit -m "add waitlist form". The message is for the you of next month, so write what changed, not "update". git log --onelinelists your commits with a short id each.git checkout 4f2a1cputs the project back to how it looked at that one, andgit checkout mainreturns you to the present. Git calls the state in between a "detached HEAD", which is not an error. Look, do not edit: a commit made there disappears when you leave.- A A separate line of commits that starts from your history and does not
affect it until you merge it back. lets you try something without touching the version that
works.
git checkout -b risky-refactorcreates one and moves you onto it. When the experiment is good,git checkout mainthengit merge risky-refactorcopies the work back. git statusis the one you run constantly. It names the files that changed, which are staged, and which branch you are on.
What to do
-
Deal with
.gitignorefirst, before anything is recorded. It lists what git must never save, one per line, and most starter projects write one for you. Open it, or create it, and check for these:textnode_modules/ .env .env.local .next/ .DS_Store -
Now put the project under git, before the first AI-written line. In the project root:
git init,git add -A, thengit status. Read that list. If a.envfile ornode_modulesis in it, add it to.gitignore, thengit resetandgit add -Aagain, because an ignore rule does not reach a file git has already been handed. Once the list is clean:git commit -m "starting point". On a new machine git refuses that last one until you say who you are, and prints the two commands that fix it. -
Commit before you hand over a task, every time. A clean
git statusat the start means one command puts everything back if the session goes badly. Asking Claude Code to make that commit for you is fine. Asking it whether the work was any good is not. -
Undo with the smallest tool that works.
git restore src/app/page.tsxthrows away the unstaged changes to one file, andgit restore :/does it for every tracked file in the project, wherever you are standing. Neither touches staged changes or new files. To put everything back to the last commit:git reset --hard, then deal with the new files in two steps.git clean -ndlists what would go, and only thengit clean -fddeletes it. That is a real deletion off your disk, not a stash, so read the list. If the assistant already committed, name the commit you want:git log --oneline, thengit reset --hard 4f2a1c. All of these are irreversible, so readgit statusfirst. -
Work on a branch for anything you expect to go wrong:
git checkout -b try-new-auth. If it fails,git checkout mainleaves the experiment behind.
Where it breaks
Git only protects what you committed. An assistant that rewrites a file you never snapshotted has
destroyed the previous version, and no git command brings it back. Two things help beforehand.
git stash -u parks uncommitted work where git stash pop retrieves it, and the -u matters:
plain git stash skips files git has never seen. VS Code and Cursor also keep a per-file Local
History in the Timeline panel.
The history also keeps what you wish it would not. An API key committed once is still in there after
you delete the line, which is what the .gitignore step is for.
What to do when one has already gone in is a section of
its own in section 5.