git's "detached head"

git is just the best version control tool, ever, period. Most of times, it's straightforward. Sometimes you have to really understand what happens. A few day ago I synchronized with another repository on a USB key. Then I resumed my work. While requesting git status I saw many times there was no current branch. I decided to fix that by forcing the current branch, issuing a git checkout master. Then all the work I did since the synchronization appeared to be lost on both git repository and my local filesystem! As those commits happened, I was pretty sure they were somewhere inside my git repository. Reading git doc carefully, I learned that I was working with a "detached head" (poor myself).
It is sometimes useful to be able to checkout a commit that is not at the tip of one of your branches. [...] The state you are in while your HEAD is detached is not recorded by any branch (which is natural --- you are not on any branch). What this means is that you can discard your temporary commits and merges by switching back to an existing branch.
Clearly, I messed the merge in some way. The way to recover was mentioned: the "reflog" kept track of every changes (including those not attached to a branch) until a git prune or a git gc. Here is what I did. First, read the reflog and find last "lost" commit with my bare eyes:
$ git log -g --after=2008-08-14
Appeared to be:991ee3ebc11e1dc3434fab4c22e261b7e0711346. This time I created a branch:
$ git branch rescue_2008-08-23 
$ git checkout rescue_2008-08-23
Now get back every "lost" stuff with one single command (commits are chained):
git checkout 991ee3ebc11e1dc3434fab4c22e261b7e0711346
This looked good. I committed inside the "rescue_2008-08-23" and switched back to the "master" branch:
$ git commit -a
$ git checkout master
Merge happened seamlessly as a "fast forward", wow!
$ git merge rescue_2008-08-23

Updating 13d16f3..31626f8
xxx: needs update
Fast forward
[every "lost" change listed here, there were many!]
This mess happened because I had some problems during the merge I didn't try to understand. Next time if I get such problems I'll do all the mess in a new branch of the target repository, and then perform a second merge.

No comments: