Why Your Push Was Rejected, and the One Push That Destroys Work
Last timeNothing Is Lost Yet
A second copy is another object store with the same names and different labels, which makes a transfer a set difference and a rejection a refusal to drop a commit.
A copy is just another store
Take the repository worked through so far, with its three files, its main line
of four commits 6f74b13, 5c79a65, 2c74519 and a2f7109, and its side line of
three leaving the second of those and ending at f512f47. Copy it to another
machine and look at what arrived.
Twenty-three objects, which is seven commits, seven directory listings and nine
file contents, and every one of them under exactly the name it had in the
original. The commit at the tip of the main line is a2f7109 on both machines.
The contents of readme.md at that commit are 33769db on both machines. Nothing
was negotiated to make that true. The name is a fingerprint of the contents, so
two machines that have never exchanged a message will file identical contents
under an identical name, and would do so even if neither knew the other existed.
This is worth stating as the whole content of what a second copy is, because it
removes a question people expect to be hard. The two stores cannot disagree
about content. If both hold a2f7109, both hold the same bytes, and no comparison
is needed to establish it. What the two copies genuinely have of their own is
their labels. Where main points, where the side branch points, what local
branches exist that the other has never heard of: all of that is a handful of
small files holding names, and all of it is private to one copy until something
moves it.
What a transfer has to move
Now the cheapness, derived rather than asserted. When a copy asks another for
what it does not have, the exchange begins with names. The asking side says
which names it already holds; the sending side works out what is reachable from
the label being asked for, subtracts what the asker said it has, and sends the
difference.
- the name the asking side already holds for this label, from its last exchange
- the name the label holds on the other side now
- every object reachable from x, which is x, its listings, its file contents and all of its ancestors
- the objects actually put on the wire
Work it on the toy repository first, where the numbers are small enough to
check by hand. Ben commits once, changing settings.ini, which produces one new
commit, one new directory listing and one new version of one file, so three new
objects, taking the shared store from twenty-three to twenty-six. Ada then
fetches. She already holds twenty-three of those twenty-six, so the difference
is three objects out of twenty-six, which is under one eighth of a store that
was already tiny.
Then scale it with the project fixed earlier in this chain: two hundred files
totalling 8 MB, with a hundred commits that each change one line of one 50 KB
file, which packs to under 9 MB. Cloning that moves the pack once, under 9 MB.
Three more commits of the same shape then add three file versions at 50 KB
each, which is 150 KB, three directory listings of two hundred entries at about
30 bytes an entry, which is 6 KB each and 18 KB in all, and three commits of
about 250 bytes, which is under 1 KB. The transfer is 150 plus 18 plus 1, so
169 KB against a project of 8192 KB.
The lesson stops here
5 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 contentsThis 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