Step 1 of 5 · Reading · ~4 min
Read
Refs & History
Checkout: Updating the Working Tree
Checkout has a scary reputation it does not deserve. Strip the porcelain and it is a pure function: given the snapshot you have and the snapshot you want, compute the minimal file operations that turn one into the other, refuse if that would destroy work, then do them. You write the computing half, the plan, and that is where all the intelligence lives.
Two snapshots in, operations out
Switching from commit A to commit B means the working tree must stop looking like A's tree and start looking like B's. Flatten both trees (the ls-tree -r walk) into maps from path to (mode, hash) and compare path by path:
| in A | in B | compare | plan |
|---|---|---|---|
| yes | yes | same mode and hash | nothing: the file is already right |
| yes | yes | different mode or hash | update: write B's blob, set B's mode |
| yes | no | delete | |
| no | yes | create: write B's blob |
That table is checkout. After applying it git points HEAD at B and makes the index equal to B's tree.
Why the "nothing" row matters
A naive checkout could delete everything and re-extract B. It would be correct, and unusable: switching branches in a 100,000-file repository normally touches a handful of files, and the no-op row is why it takes milliseconds. Same hash means same content, guaranteed, so no bytes need comparing. Content addressing from the first lesson pays off here as speed.
Order and directories
Operations have to happen in a sensible order, because the file system has a rule trees do not: a path cannot be a file and a directory at once.
- Deletes come first. If A has a file
docsand B hasdocs/guide.txt,docsmust be deleted beforedocs/guide.txtcan be created. - Directories left empty are removed. Git trees do not store empty directories, so after deleting the last file under
old/dir, the directoriesold/dirand thenoldhave to go as well, deepest first. A directory stays if B still has any file under it. - Creates and updates then follow, in path order. Writing a file creates any missing parent directories.
The safety rule
Real git refuses to check out over work it would destroy. A change that exists only in the working tree has no object, no ref and no reflog, so overwriting it is the one data loss git cannot undo. The rule is precise:
- A path that the plan would update or delete, and whose working file differs from A's version, blocks the checkout (your uncommitted edit would be overwritten or lost). If the working file is missing, there is nothing to destroy.
- A path that the plan would create, but where an untracked file already exists, blocks it too, even if that file happens to match B's version. Git cannot know the file is disposable, so it asks you to move it.
- A dirty file that is identical in A and B is never touched, so it never blocks. The no-op row also protects uncommitted work.
When anything blocks, git changes nothing and lists the files. Your program prints the blocking paths and no plan.
The same plan runs everything
reset --hard is this plan applied without moving a branch; the working-tree update after a merge is this plan from the merge result; clone is this plan from an empty tree; stash pop is this plan in reverse. Git has one working-tree updater, and you are writing it.
Common mistakes
- Iterating only B's paths, so files that exist only in A are never deleted.
- Calling a file
docsand a directorydocs/the same thing and creating before deleting. - Forgetting that the executable bit is part of the comparison: the same hash with a different mode is an update.
- Treating every dirty file as a blocker, including ones identical in both snapshots.
- Printing part of the plan and then the blockers. When something blocks, print only the blockers.
Your exercise
The starter parses the three file lists and prints the result lines. You write plan, which returns either the blocking paths or the ordered operations. The scenarios in the tests were checked against what real git checkout did to a real repository.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…