{"id":19,"date":"2013-10-06T11:15:17","date_gmt":"2013-10-06T18:15:17","guid":{"rendered":"http:\/\/colinschimmelfing.com\/blog\/?p=19"},"modified":"2013-10-21T22:54:07","modified_gmt":"2013-10-22T05:54:07","slug":"gits-empty-tree","status":"publish","type":"post","link":"http:\/\/colinschimmelfing.com\/blog\/gits-empty-tree\/","title":{"rendered":"Git’s empty tree"},"content":{"rendered":"

It’s late. You’ve been coding up a greenfield project and it needs to be done by tomorrow. Yes, the team could have gone with a similar tool that has some of the necessary features, but damn, that thing written in PHP! This is your chance to write a totally new project and to show the company that python\/ruby\/go is the future. I mean, PHP, really? No, didn’t think so.<\/p>\n

Ok, ready for reviewboard.
\ndiff --full-index --oh-crap-you-forgot-to-make-an-initial-commit<\/code><\/p>\n

Oops. This is dumb. You can’t believe you forgot to do an initial commit, and your first commit was only after 2 hours of work- totally useless to your coworkers\u2026 Damn it, why didn’t you create an alias for git init?<\/p>\n

Here’s my stream-of-consciousness from solving this one:<\/h3>\n

Hmm- if only there was a way to diff against a totally empty commit, a magic empty git repository\u2026<\/p>\n

Well, how about we check out the first commit in the internals of git:<\/p>\n

> cat .git\/logs\/refs\/heads\/master
\n0000000000000000000000000000000000000000 a7726d5201b0e56bf6e15e9ed72ea42192013d09 Colin P. Schimmelfing <theboss@colinschimmelfing.com> 1369722239 -0700 commit (initial): adds money-printing functionality to our app. biz-dev should be happy
\n<\/code><\/p>\n

those zeros look good as some sort of magic original empty commit\u2026 lets try that:<\/p>\n

> git diff 0000000000000000000000000000000000000000
\nfatal: bad object 0000000000000000000000000000000000000000<\/code><\/p>\n

Nope, no go.<\/p>\n

What if we init a new repo and see what a blank repo is like:
\n> git init test2
\nInitialized empty Git repository in \/Users\/cschimmelfing\/code\/blog\/empty_git\/test2\/.git\/
\n> cd test2
\n> git show
\nfatal: bad default revision 'HEAD'
\n> git log
\nfatal: bad default revision 'HEAD'
\n> cat .git\/logs\/refs\/heads\/master
\ncat: .git\/logs\/refs\/heads\/master: No such file or directory<\/code><\/p>\n

Damn, no commits means normal ways I’d look at the repo are pretty useless. Looking elsewhere in the .git directory gives just as little insight.<\/p>\n

At this point, you hit up stackoverflow, and when I ran into this problem I was able to find a few items mentioning the magic commit I was looking for.\u00a0(From\u00a0this thread<\/a>\u00a0or this Stack Overflow<\/a> post)<\/p>\n

drum rolllllllll:<\/p>\n

4b825dc642cb6eb9a060e54bf8d69288fbee4904<\/strong><\/h2>\n

Huh. Well that’s random.<\/p>\n

> git show 4b825dc642cb6eb9a060e54bf8d69288fbee4904
\ntree 4b825dc642cb6eb9a060e54bf8d69288fbee4904
\n(END)<\/code><\/p>\n

Well, let’s try it out:
\ndiff --git a\/test1.txt b\/test1.txt
\nnew file mode 100644
\nindex 0000000..95f29d0
\n--- \/dev\/null
\n+++ b\/test1.txt
\n@@ -0,0 +1 @@
\n+hi HN
\n(END)<\/code><\/p>\n

So now you are thinking: “Colin, that looks good, but where does this magic hash come from?”<\/p>\n

Well, we can see that it’s a tree, so let’s try:<\/p>\n

> git init test2
\nInitialized empty Git repository in \/tmp\/test3\/.git\/
\n> cd test3
\n> git write-tree
\n4b825dc642cb6eb9a060e54bf8d69288fbee4904<\/code><\/p>\n

Aha! there it is, the hash is simply the value git creates when you ask for the hash of an empty directory. For more on this, check out this breakdown on the internals of git\u00a0<\/a>.<\/p>\n

In both of the links that mentioned the special hash, it looks like there is another way to find the magic value, a little faster:<\/p>\n

> git hash-object -t tree --stdin < \/dev\/null
\n4b825dc642cb6eb9a060e54bf8d69288fbee4904<\/code><\/p>\n

So there we go! A little window into the internals of git, and a useful trick. If you don’t use review board (or always remember to touch an empty README, etc), you may also find it useful in other contexts, for instance creating a patch that can recreate the whole repo. Yes, you could tar the whole repo up, but maybe there are some embarrassing commits you’d like your colleague not to see, or a FUBAR-ed history that you might want to totally nuke before starting to collaborate.<\/p>\n

Of course, this is git, so there are probably three other ways to do the same thing. Please comment, internet points will be awarded to the best answer!<\/p>\n

Share this, if you like it:<\/h3>