Skip to content
Lesson 13 of 18

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 Ain Bcompareplan
yesyessame mode and hashnothing: the file is already right
yesyesdifferent mode or hashupdate: write B's blob, set B's mode
yesnodelete
noyescreate: 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 docs and B has docs/guide.txt, docs must be deleted before docs/guide.txt can be created.
  • Directories left empty are removed. Git trees do not store empty directories, so after deleting the last file under old/dir, the directories old/dir and then old have 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 docs and a directory docs/ 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.

Up nextComputing DiffsBranching, Diff & Merge

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…