0

I commited my changes into detached head and moved to master. Is it possible to checkout the detached head again?

2 Answers 2

2

I committed my changes into detached head ...

Technically, you committed (files) while on a detached HEAD or in detached-HEAD mode, rather than "into a detached HEAD". The important thing, though, is that you did commit. That's the key.

... and [then] moved to master.

This left the commit you made earlier behind. That commit, like every commit, has a unique hash ID: a big ugly string of letters and numbers like c7a62075917b3340f908093f63f1161c44ed1475.

Is it possible to checkout the detached head again?

Again, "detached HEAD" is a mode—a way of using Git—not a commit. The question you need here is: Can I get this commit again somehow? The answer is yes, but you must find its hash ID, or something that finds its hash ID.

The easiest way to find its hash ID is if it's still on your screen. If you can scroll back just a bit and see it, you can grab it with your mouse, with cut-and-paste, the way I grabbed the hash ID I quoted above. Hash IDs are too big and ugly for humans to type in correctly, which is why we don't use them, but they're Git's "true name" for each commit, which is why Git does use (and need) them.

Normally, we have Git store them for us. Just like using cut-and-paste, we don't try to type them in at all: we just tell Git using a name like master, find me a commit hash ID and do something with that commit. But if you didn't, well, there are several ways to find it.

I already mentioned the scroll-back-and-look-at-your-screen method. Another one is to use what Git calls reflogs. Every time you check out some commit, whether by branch name, or tag name, or hash ID, and every time you make a new commit, so that there is a new unique hash ID in your repository, Git saves this hash ID as an entry in the reflog for the name HEAD. Run:

git reflog

to have Git print out the entire log, one line at a time. You will get output similar to this:

$ git reflog
c7a6207591 (HEAD -> master, origin/master, origin/HEAD) HEAD@{0}: reset: moving to HEAD
c7a6207591 (HEAD -> master, origin/master, origin/HEAD) HEAD@{1}: merge refs/remotes/origin/master: Fast-forward
083378cc35 HEAD@{2}: checkout: moving from 1d2375ddfee18bd3effd2c1f98527cc2f8b1df0a to master

The leftmost string is an abbreviated hash ID. Note that c7a6...(something), for instance, starts with the same letters and numbers as the hash ID I pasted near the top of this answer (c7a62...(something)). An abbreviated hash ID is almost1 as good as the full hash ID. Or, you can use the HEAD@{number} string, but remember: every time you run git checkout or git commit, all the numbers go up by one, because Git just added another entry to the log.2

Once you find the hash ID, or a shortened version of it or a name like HEAD@{2}, you can run:

git checkout <hash>       # or git checkout HEAD@{2}

and you'll be in "detached HEAD" mode again, at that commit. You can now create a branch or tag name to have Git remember the hash ID for you.

If you're not sure which commit is which, run git reflog to see the hash IDs (and HEAD@{...} names) and then run:

git log <hash-id>       # or git log HEAD@{3} or whatever

and git log will show you that commit, and its predecessor commits, as usual. Use git show hash-id or git show HEAD@{number} to show that commit in detail.


1It falls short when it, well, falls short: the full hash ID definitely matches the actual hash ID, but a shortened one might match two or more hash IDs. For instance, if we shorten c7a6...something to just c, that would match c10b...something too. Git has a minimum of 4 characters for a shortened hash ID, and usually starts at out 7 and as the repository grows, starts adding more characters to hope that the shortened ID is always sufficient.

2Periodically, Git will clean out the reflogs. There's one reflog for each ref: a branch name, or a tag name, or any other such name is a ref or reference. Each holds one hash ID. The branch names hold a hash ID that changes over time, while your tag names should never change.

Reflog entries generally last for at least 30 days by default, and at least 90 days by default in most cases. So after you "lose" a commit, you can usually get it back for at least a month. You can explicitly enable or disable reflogs in your own repository, but usually the default—enabled, for you—is right. Server-side repositories as stored on commercial servers like GitHub usually don't have reflogs enabled, so that there's no 30-day grace period there.

0

A good alternative would be to use the git rebase -i or the interactive rebasing in case you want to make changes in a previous commit, delete it, or meld it into other commits.

I commited my changes into detached head and moved to master. Is it possible to checkout the detached head again?

Yup it is possible :)

Not the answer you're looking for? Browse other questions tagged or ask your own question.