Basis Lab

How a Repository Remembers

Every Commit Names Its Parent, and a Branch Is One Line in a File

Last timeA Snapshot, Not a Change

A commit holds its parent's name inside the bytes that give the commit its own name, which makes history a graph, a branch a 41 byte file, and a rewrite unavoidably a set of new commits.

What is actually inside a commit

Everything in the store is named by a fingerprint of its own contents, and a

commit is no exception to that. So the useful question is not what a commit

means but which bytes it is made of, because the name is a function of those

bytes and of nothing else.

The repository behind these examples has three files, four commits on the main

line, and a side line of three commits that branches off the second. Here is the

third commit on the main line, read straight back out of the store.

FIG 1One commit object, its length, and its name recomputed from its own bytes
bash
$ git cat-file -p 2c74519
tree f4db054a3709a8b5298a1e007e884b08c6e85a7b
parent 5c79a65d0318ae221e939eddc831adc7952477c6
author A Writer <[email protected]> 1767603600 +0000
committer A Writer <[email protected]> 1767603600 +0000

Raise the default width
$ git cat-file -s 2c74519
230
$ (printf 'commit 230\0'; git cat-file commit 2c74519) | shasum
2c74519cfeecfef02a58771338350ba0abe652db  -
$ old=5c79a65d0318ae221e939eddc831adc7952477c6
$ new=6f74b130bc453e3eac1436ca41795df6c3d5e583
$ git cat-file commit 2c74519 | sed s/$old/$new/ | git hash-object -t commit --stdin
0ca058495cfc9d00ed6334e5c60410802f9a09c3
The middle pair of commands is the proof that nothing is hidden in the name. Put the eleven byte header in front of the 230 bytes of the object, hash the lot, and out comes the name the object was filed under. The last command changes 40 of those 230 bytes, the parent and nothing else, and a completely unrelated name comes back.

Six lines of content and that is the entire object. The first names a tree,

which is the whole directory as it stood at that moment. The second names the

parent, which is the commit this one came after. Then two identity lines, a

blank line, and the message.

Read the list again for what is missing. There is no record of which files

changed. There is no difference against anything. And there is nothing pointing

forwards, no field naming the commits that came later, because at the moment

those 230 bytes were written the later commits did not exist and this name was

already settled.

Those three absences are the whole of what follows. Branching, merging and

rewriting all behave the way they do because a commit has exactly one backward

link and no forward one.

The parent is part of the name

The parent is not metadata hung off the side of a commit. It is 48 of the 230

bytes that go through the hash.

The lesson stops here

8 more paragraphs to go

You have read the opening. The rest of the argument, the problems that check whether it landed, and the lines worth keeping at the end all come with a plan.

The first lesson of every course in the library reads the whole way through, free, so you can see exactly what the rest of them are.

See the planThe contents

This is the reading half

Starting the course gives you your own copy of it. Every idea on every page has problems standing under it, marked with a reason rather than a tick, and any sentence you do not believe can be opened and argued with. None of that can happen on a page nobody owns.

The contents

The rest of this course

  1. 01What a Git Hash Is Actually a Hash Of
  2. 02Why a Commit Is a Whole Snapshot and Still Costs Almost Nothingopening only
  3. 03Every Commit Names Its Parent, and a Branch Is One Line in a Fileyou are here
  4. 04Why the Same File Is Reported as Both Staged and Not Stagedopening only
  5. 05Why a Merge Only Stops to Ask About Some of Your Changesopening only
  6. 06Why Your Commits Get New Names When You Rebaseopening only
  7. 07A Hard Reset Deletes Nothing, and You Have About Thirty Daysopening only
  8. 08Why Your Push Was Rejected, and the One Push That Destroys Workopening only

Read alongside