The first few days I used Git, I messed up my repository. I had to reset and recreate it from scratch several times. With enough trials and errors, I came up with an idea of how I should initialize my repositories. Let me explain in this post why git init is not enough to me.

To create a Git repository, nothing else is absolutely necessary than these few trivial commands:

1$ mkdir kev-code
2$ cd kev-code/
3$ git init

But after reading some documentation and user experiences on the web, it looks like Git has some limitations when dealing with the root of a repository history. As I plan to heavily manipulate the commit history (to do some kind of code archaeology and history reconstruction ), I need to have the widest time latitude to play with commits.

In this situation, I came to the conclusion that it’s a good idea to create an empty commit at the start of your repository life, and date it to the start of epoch. In the future, I’ll be able to leverage this initial commit as an ordinary history point from which I can start a branch. Then in this branch I’ll be free to mess up the history, until merging my changes back in the mainline tree.

So, let’s create an empty commit:

1$ git commit --allow-empty -m 'Initial commit'

Then get the commit hash:

1$ git log
2commit 395290bcdb8ffccfbff89e42cb976077fbd3c1b7
3Author: Kevin Deldycke <[email protected]>
4Date:   Tue Dec 1 15:37:49 2009 +0100
5
6    Initial commit

We now change the commit date of our first commit to epoch start:

1$ git filter-branch --env-filter '
2>     if [ $GIT_COMMIT = 395290bcdb8ffccfbff89e42cb976077fbd3c1b7 ]
3>     then
4>         export GIT_AUTHOR_DATE="Thu, 01 Jan 1970 00:00:00 +0000"
5>         export GIT_COMMITTER_DATE="Thu, 01 Jan 1970 00:00:00 +0000"
6>     fi' -- --all
7Rewrite 395290bcdb8ffccfbff89e42cb976077fbd3c1b7 (1/1)
8Ref 'refs/heads/master' was rewritten

And check that the previous operation did what we expected:

1$ git log
2commit 8fe2934d1552c97246836987f0ea08e10ba749ae
3Author: Kevin Deldycke <[email protected]>
4Date:   Thu Jan 1 00:00:00 1970 +0000
5
6    Initial commit

Looks good!

For convenience, we’ll now attach a tag to this initial commit. Let’s call it init :

1$ git tag "init"

This will came handy later when we’ll need to create a branch from here.

It’s time to push all changes to our brand new public repository:

 1$ git remote add origin [email protected]:kdeldycke/kev-code.git
 2$ git status
 3# On branch master
 4nothing to commit (working directory clean)
 5$ git push origin master --force
 6
 7Counting objects: 2, done.
 8Writing objects: 100% (2/2), 159 bytes, done.
 9Total 2 (delta 0), reused 0 (delta 0)
10To [email protected]:kdeldycke/kev-code.git
11 + 86bd2c7...8fe2934 master -> master (forced update)

And here is the result on GitHub:

Web view of a fresh repository holding a single empty initial commit dated 1 January 1970, with no files listed underneath

Maybe this “first commit” trick is unnecessary. So, if you have a better understanding of the issue, or can explain me why this is stupid, please tell me! :)

8 archived comments

Comments are closed. These were posted on Disqus, and are archived here.

  1. Kevin Deldycke Author

    I'm starting to get an idea of the initial commit problem. And according Brandon Dimcheff, it looks like a --root option was added to Git to address this issue.

    And here is an example I found on Stack Overflow on how to use it:

    git rebase --root --onto $emptyrootcommit
    
  2. Kevin Deldycke Author

    If you need to automate the setting of the initial commit's date, then add the init tag just after the git commit command.

    This will let you get the hash of the first commit dynamically:

    $ git commit --allow-empty -m 'Initial commit'
    $ git tag "init"
    $ export GIT_TMP_INIT_HASH=`git show-ref init | cut -d ' ' -f 1`
    $ git filter-branch --env-filter '
        if [ $GIT_COMMIT = $GIT_TMP_INIT_HASH ]
          then
            export GIT_AUTHOR_DATE="Thu, 01 Jan 1970 00:00:00 +0000"
            export GIT_COMMITTER_DATE="Thu, 01 Jan 1970 00:00:00 +0000"
        fi' -- --all
    $ unset GIT_TMP_INIT_HASH
    
    1. Here's a cleaner way than using filter-branch to set the commit date of your first commit to epoch start:

      $ GIT_AUTHOR_DATE="Thu, 01 Jan 1970 00:00:00 +0000"
      $ GIT_COMMITTER_DATE="Thu, 01 Jan 1970 00:00:00 +0000"
      $ git commit --allow-empty -m 'Initial commit'
      
      1. git-commit has a --date option.

        git commit --allow-empty -m 'Initial commit' --date 1970-01-01T00:00:00
        
        1. --date option only adjusts the "authorDate" and does not adjust the "commitDate". The only way to adjust the "commitDate" is via the GIT_COMMITTER_DATE environment variable.

  3. Thanks Kevin, it's good to know that other people do it this way.

    I made https://github.com/mca-wtsi/git-yacontrib/commits/master/bin/git-iec for the purpose, but it uses current date.
    What is the advantage of putting IEC at epoch instead of repository creation?
    Have you seen disadvantages of having all repositories (made your way) share the IEC commitid?

    1. Kevin Deldycke Author

      Haven't seen any disadvantage yet.

      As for epoch, you're right, it's not necessary: Git don't requires increasing timestamp for commits. It's just that I find it makes the technical nature of that commit more obvious to a human not familiar with this convention.

  4. Thanks