Always Start With An Empty Commit

Whenever you start a new git repo, pop an empty commit onto it before you do anything else!

git init new-repo
cd new-repo
git commit -m 'initial empty commit' --allow-empty
git tag init

I first encountered this idea in Tim Pettersen’s 2016 blog entry, Lesser known Git commands.  I’ve since traced this idea’s lineage back to Kevin Deldycke’s 2010 post, How I Initialize My Git Repositories, which makes a passing reference to an appendix in the 2008 version of Ben Lynn’s git manual, Git Magic.

This idea has been around a long time, but the reasons people cite for doing it don’t make sense.

Let’s look at those reasons.

1. “git log” and other commands blow up with terrifying error messages.

This was true a couple years ago:

$ git --version
git version 2.5.1

$ git log
fatal: bad default revision 'HEAD'

But things have gotten better as of git version 2.5.2:

$ git --version
git version 2.5.2

$ git log
fatal: your current branch 'master' does not have
any commits yet

I tried switching my computer to Korean to see if that makes a difference:

$ git log
fatal: 현재 'master' 브랜치에 아직 아무 커밋도 없습니다

I cannot read or understand Korean, but seeing ‘master’ in there suggests that even in Korean the message is now less terrifying.

2. You can’t “git reset” back to that initial state.

Stackoveflow doesn’t appear to know this trick yet, but you can do this from your repository’s root directory:

git checkout --orphan primordial_nothingness
git rm -rf .
git commit --allow-empty -m 'floating empty void'
git push origin refs/heads/primordial_nothingness

Run the commands above (once per repo), and from then on the void is just a quick 46 keystrokes away: “git reset –hard origin/primordial_ nothingness”. Unless of course some jerk goes and commits against your primordial_nothingness branch. But if that ever happens, you know how to get the void back! Run the same steps above, but end with a force-push.

It does look funny on commit graphs:

G. Sylvie Davies was either having a good day with git, or a very very bad day.

3. You can’t rebase the initial commit.

“I think we’re gonna be stuck with this commit forever.  I can’t seem to rebase it.”

If you are profoundly unhappy with your first few commits, you could just refuse to push them.  Sweep them under the rug via “rm -rf .git” and never tell a soul.  Here’s an example:

$ git log --oneline
261e747 c
39b91e3 b
212a17d a

Not happy with those initial three commits above? Blast away the “.git” directory, re-init, recommit:

$ rm -rf .git
$ git init
$ git add .
$ git commit -m 'a b c'

$ git log --oneline
d3b7ca4 a b c

Et voilà, the commit exactly as you dreamed it.  Sure, it’s a little bit of typing, but it uses vanilla git commands that any beginner should know.  The only trick is deleting the “.git/” directory.

Now, if the current date is after July 25th, 2012, then there is another way.  You can take advantage of git’s very own commit “7b9f29c4”:

commit 7b9f29c40f52084c4e3abf7d2a4212c15aa63ae6
Merge: b00445bc3 2147f844e
Author: Junio C Hamano <gitster@pobox.com>
Date:   Wed Jul 25 15:46:59 2012 -0700

    Merge branch 'cw/rebase-i-root'
    
    Finishing touches to the "rebase -i --root"
    (new feature for 1.7.12).
    
    * cw/rebase-i-root:
      rebase -i: handle fixup of root commit correctly

The trick here is to remember to use “–root” instead of “HEAD~N” or “@{u}” or however it is you typically reference the commit you’re rebasing to.  So instead of this:

git rebase --interactive HEAD~3

Or instead of this:

git rebase --interactive @{u}

Try this!

git rebase --interactive --root

But we would eat Kraft Dinner

Nonetheless, I still try to initialize my repos with empty root commits. I just have different reasons.

  1. I find the initial empty commit more compatible with my mental model of git. When I run into problems #2 and #3 (above), instead of trying to remember the “–root” flag of “git rebase”, I remember the “init” tag I created. And since all my repos always contain that initial empty commit, this is easy to remember.
     
  2. My condensed git graph add-ons for Jira and Bitbucket blow up if the matching commits span orphan branches. An initial empty commit prevents this, since orphan branches can claim that same empty commit for their own parentage.  This approach also makes the “git merge-base” command happier when faced with orphan branches.
     
    Note: my regular graph is fine. It’s only my condensed graph that has problems here.
     
    Is this over-engineering? I’ve never actually seen an orphan branch in the wild. If you know of sensible examples of orphan branches in industrial git repos, I would love to know about them (tweet me @gsylviedavies).
     
  3. Nothing else quite says “git ninja was here” better than an empty root commit.
     

Exercises For The Reader

I only have one for you this time. I haven’t tried it myself yet. But I’ll post a solution in a couple weeks. My solution will probably use a combination of “git log –reverse –pretty=email” piped into “git am”. Here’s the exercise:

  1. Take an existing repository (that doesn’t already have an empty initial commit) and redo the repo’s history to forcibly inject one. What sequence of commands did you use? Tweet your solutions to @gsylviedavies. Uses: Handy if you’re migrating repos to git from other source control system (like cvs or svn), but also want all your repos to start with an empty root commit.

    Comments

    Discussion threads on HN and Reddit.

    Author: G. Sylvie Davies

    Founder at bit-booster.com software engineering.