First, how big is a brand new empty Git directory (.git)?
$ git init Initialized empty Git repository in /home/dave/tmp/foo/.git/ $ du -sb .git 64828 .git
(The du options are: s to summarize and b to display bytes.)
Now I’m going to make a bunch of tiny files in directories with a pair of nested shell loops:
$ for d in {1..5};do
mkdir $d;
for f in {1..50};do
echo foo > $d/$f;
done;
done
Now I have 250 files in 5 directories containing the string "foo":
$ ls 1 2 3 4 5 $ cat 2/45 foo
$ git add . $ git commit -m 'initial commit'
Let’s see how big .git is now:
The commit has added about 47 Kb to the initial blank repo.
Aside: I calculated this in the geekiest way I could think of, using the standard Unix command dc, the arbitrary precicision reverse-polish notation desk calculator (note that 'p' is the print command so we can see the result!):
$ dc -e '112468 64828 - p' 47640
Now I’ll make one tiny change to one file and commit it:
$ echo bar > 1/1 $ git commit -am 'changed 1/1' $ du -sb .git 129613 $ dc -e '129613 112468 - p' 17145
So that’s 17 Kb to store about 3 bytes of changes to my repo.
Where is that weight coming from?
I’m gonna do another little commit. Here’s what it looks like before:
$ du -b .git 4096 .git/objects/info 4096 .git/objects/pack 4115 .git/objects/25 4155 .git/objects/7b 4225 .git/objects/af 4115 .git/objects/57 4271 .git/objects/07 4177 .git/objects/61 4255 .git/objects/bb 4299 .git/objects/a8 45900 .git/objects 4336 .git/info 4096 .git/refs/tags 4137 .git/refs/heads 12329 .git/refs 4096 .git/branches 4411 .git/logs/refs/heads 8507 .git/logs/refs 12918 .git/logs 27538 .git/hooks 129613 .git
Then I modify file 1/1 again to contain the string 'baz' and commit that.
4096 .git/objects/info 4096 .git/objects/pack 4115 .git/objects/25 4253 .git/objects/81 <-- new 4 Kb 4155 .git/objects/7b 4225 .git/objects/af 4115 .git/objects/57 4271 .git/objects/07 4177 .git/objects/61 4302 .git/objects/fc <-- new 4 Kb 4255 .git/objects/bb 4115 .git/objects/76 <-- new 4 Kb 4299 .git/objects/a8 4177 .git/objects/92 <-- new 4 Kb 62747 .git/objects 4336 .git/info 4096 .git/refs/tags 4137 .git/refs/heads 12329 .git/refs 4096 .git/branches 4561 .git/logs/refs/heads <-- added 0.1 Kb 8657 .git/logs/refs 13218 .git/logs 27538 .git/hooks 146759 .git
That’s 4 new objects for a single-file commit.
Although these files are all zlib compressed data, I figured out that git show will show the value of any object by hash identifier, not just commits!
So to view these objects, I did:
$ ls .git/objects/81 b1a9d27494b40679d612b96bb6acaac83afa9c $ git show 81b1a9d27494b40679d612b96bb6acaac83afa9c
-
81… is my actual commit
-
fc… is the tree file for the changed directory
1., listing all of the files in that directory (1 through 50). -
76… is the actual contents of file 1/1 (which is now the string 'baz')
-
92… is another tree for the root directory of the repo
That makes sense. There’s a commit, two trees, and one file.