ReadbackLesson 03In progress
2 steps · 25 minutes · one terminal

THE THREETREES

Staging looks like a formality git makes you perform before it will accept a commit. It is not. It is a third copy of your project, stored in a third place — and git status is a report comparing all three.

The model you carry

Claim · no terminal needed

When an agent stops mid-task — because it hit a conflict, ran out of context, or asked you a question — the first command you run is git status. It is also the command most people read wrong, because it appears to answer “what did you change?” and in fact answers something narrower and more useful.

Answer before you move on

First, from lessons 01–02, because you have not been asked in a while: an agent rewrites the oldest of five commits on a branch. How many of the five keep their original hash?

Now the new material. Most people carry a two-place model of git: there are your files, and there is the repository. Committing moves work from the first into the second, and git add is an irritating extra keystroke on the way — a formality, a checkbox, a thing agents do for you with git add . so you never think about it.

Here is the part everyone has backwards

There is no extra keystroke. There is a third copy of your project, called the index, stored in its own file. git add writes to it, git commit reads from it, and git status exists to report the two ways it can disagree with its neighbours.

Git manages three trees, in Pro Git’s naming: HEAD, the last commit snapshot; the index, the proposed next commit; and the working tree, the files on your disk. Pro Git calls the third one the working directory; git’s own documentation says working tree, and so will this course.

Read that middle definition again, because it is the one that pays: the index is not a queue, a list of filenames, or a set of flags. It is a complete proposed snapshot — the same shape of thing as a commit, sitting one step from becoming one.

What you can check after this step

Nothing yet. The next step opens the index and reads a version of a file that exists in neither your editor nor your history.

One file, three versions

Claim + proof · git cat-file, git ls-files

Here is a repository in the state an agent leaves constantly: one file was edited and staged, then edited again before anything was committed. Nothing about this is exotic — it is what happens when an agent stages its work and then keeps going.

Git gives you a way to name a file inside each tree. HEAD:a.txt is the committed version, :a.txt — with nothing before the colon — is the version in the index, and the plain path is whatever is on disk:

an honest state, not a theme
The same path, read three waysStep 02
$ git cat-file -p HEAD:a.txt
$ git cat-file -p :a.txt
$ cat a.txt
hello
hello
staged line
hello
staged line
working line

Three commands, one filename, three different answers. The middle one is in no editor and in no commit — it exists only in the index.

The index itself is a real file — .git/index, binary, so you cannot cat it the way you read a branch in lesson 02. git ls-files -s prints it as text. One line per tracked file: mode, blob hash, merge stage, path.

Every tracked file, and the blob it proposes
$ git ls-files -s
100644 450ef9a7e0ac4c37839655d37dabef592b441cb3 0	a.txt

Note what is missing: notes.md exists on disk but has no line here. That is the entire meaning of “untracked” — not in the index.

The blob the index proposes for a.txt450ef9a7e0ac4c37839655d37dabef592b441cb3

That hash is doing more work than it appears to. A hash in git names content that exists in the object database — that was lesson 01’s lesson. So if the index holds a blob hash, the staged content has already been written into .git/objects. Staging is not a note-to-self. It is a save.

Predict before you read on

Two hashes from the readout above: 450ef9a (staged) and 347f90c (on disk). Both name content that exists somewhere right now. Ask git what type of object each one is. What comes back?

Plumbing, the second time

Lesson 01 promised you would look at plumbing exactly twice in this course. This is the second time — ls-files, cat-file, hash-object and write-tree are all script-facing commands. From here on the course stays in porcelain, because you will have seen the thing underneath it.

Run this on a repo an agent left mid-task

Pick a file the agent touched and run git rev-parse :path/to/file then git hash-object path/to/file. If the two hashes differ, the agent staged one version and then changed it — and the staged one is not the one you are reading in your editor.

3 of 5 steps remain

Status is two diffs, not one

You have read the first 2 steps in full — a claim and the verification that settles it. The rest of this lesson, and the 9 lessons after it, open when subscriptions do. Nothing that is free today will be taken away then.

Read the free reference
Subscriptions open soon
the free preview stays