Fri, 13 Jan 2012 09:03:00 GMT

Reference Is Not a Tree

Git is an excellent version control system. However, it does not offer much hand-holding. Linus expects you to read the documentation and understand what you are doing. How rude! One of Git’s primary features includes: making you feel less intelligent than you thought you were! It satisfies this feature quite well. This can prove especially true when dealing with submodules.

Have you ever seen something like this when working with submodules?

fatal: reference is not a tree: d001e26744dab4b92014a77a4552a535b8fddad8

(Your SHA may vary.) Reference is not a tree?

Dangling Commits

When you clone a repository (from now on: repo for short) as submodules within a super-repo, you can initialise and update any submodules recursively using

git submodule update --init --recursive

After doing so however, your submodules will not sit on a branch. Verify this using

git submodule foreach --recursive git branch

You will notice that all the submodules report “no branch.” They all sit on a ‘detached head’ corresponding to the commit for the branch you originally added as a submodule. (Following it so far?)

So here is the problem: commit any changes to the submodules and you commit to a detached head. When you push the submodule to its origin, Git reports “everything up-to-date” because it pushes the master by default. “Everything up-to-date” refers to the master and not to the detached head. This can easily catch you out, and doubly so if you use a GUI tool where you might not so easily notice the lack of ‘pushing noise’ so to speak.

Prevention Better Than Cure

What to do? When pushing commits within submodules, make sure you move the submodule to a branch, e.g.

git submodule foreach --recursive git checkout master

moves all repos to their master branch for the submodules and sub-submodules recursively. Do this before committing if you can remember.

Reattaching Heads

If you forget, you can conveniently verify that you have dangling commits by checking out the master branch within your submodule. Git warns you about ‘leaving commits behind.’ You can also verify the dangling commit using

git submodule foreach --recursive git fsck --no-reflog

which outputs things like:

dangling commit d001e26744dab4b92014a77a4552a535b8fddad8

(Of course, your SHA may vary again.)

The fix for detached heads temporarily adds a branch, merges it with master and discards the temporary branch. Use the following Git command sequence within your detached head.

git branch detached
git checkout master
git merge detached
git branch -d detached

You can use any name for the detached branch. Hereafter, you can happily push your formerly orphaned changes.


Trackbacks

Use the following link to trackback from your own site:
http://blog.pioneeringsoftware.co.uk/trackbacks?article_id=34

Comments

Leave a comment

(never displayed)

Markdown enabled