Git push resolving deltas "completed with local objects"
Note: the message itself (completed with %d local objects
) is not new, and was introduced in commit a984a06, Nov. 2007, Git v1.5.4-rc0
nicer display of thin pack completion
In the same spirit of prettifying Git's output display for mere mortals, here's a simple extension to the progress API allowing for a final message to be provided when terminating a progress line, and use it for the display of the number of objects needed to complete a thin pack, saving yet one more line of screen display.
Bryan Pendleton's comment has the correct answer in it: your git push
made a "thin pack". All fetch and push operations over smart protocols use thin packs all the time, to minimize network traffic.
Any pack file uses delta compression. Normal Git pack files only delta-compress objects against other objects in the same pack (these other objects may also be delta-compressed, but only against yet more objects in the same pack). A "thin pack" is a pack file that deliberately violates this rule: it delta-compresses objects against other (loose or packed) objects stored elsewhere. Upon receiving a thin pack, a Git must "fix" the thin pack by "fattening it up" with the missing objects, or simply destroy it (exploding the thin pack into individual, not-delta-compressed, objects).
Suppose your Git and some other Git are negotiating to send a gigabyte of data (in however many files—let's just say 1 for simplicity), but the two Gits discover that you both already have a gigabyte of file data, and the new data can be represented as: "copy the old data, delete the letter a
from the middle, and insert the
instead", or something equally short and simple. Whichever Git is doing the sending makes a delta-compressed object saying "starting from object with hash h, delete 1 byte at offset x, add 3 bytes the
at offset x". This delta-compressed object takes a lot of CPU time—maybe even a whole second—to figure out, but just a few dozens of bytes of space. The resulting pack file is tiny and goes across the wire in microseconds. The receiving Git fattens it up by adding the missing 1GB object, and the transfer is complete.
In this particular case, completed with 12 local objects
means the thin pack relied on 12 objects your Git told their Git you already had. Because of Git's DAG, your Git may be able to tell their Git that you have these objects by sending just one hash ID: if you have commit C, you have every tree and blob that commit C has, and—as long as you don't have a "shallow" repository—you also have every ancestor to commit C, and every tree and blob that goes with those ancestor commits.
This kind of compression is thus a straightforward consequence of graph theory. It's also why, even for very large projects, the initial clone may be slow, but most git fetch
updates tend to be quite fast. The main exception to this rule is when you give Git data objects that do not delta-compress well against previous data objects. This includes already-compressed binary files, such as JPG images or compressed tarballs. (Ironically, uncompressed tarballs could, in theory at least, compress much better, although Git's modified xdelta did not do a great job on them in a few cases I tested in the past.)