1650
votes

I'm new at the branching complexities of Git. I always work on a single branch and commit changes and then periodically push to my remote origin.

Somewhere recently, I did a reset of some files to get them out of commit staging, and later did a rebase -i to get rid of a couple recent local commits. Now I'm in a state I don't quite understand.

In my working area, git log shows exactly what I'd expect-- I'm on the right train with the commits I didn't want gone, and new ones there, etc.

But I just pushed to the remote repository, and what's there is different-- a couple of the commits I'd killed in the rebase got pushed, and the new ones committed locally aren't there.

I think "master/origin" is detached from HEAD, but I'm not 100% clear on what that means, how to visualize it with the command line tools, and how to fix it.

26
Have you pushed the commits before the rebase?manojlds
@manojlds: Not sure what you mean. I pushed some time before the rebase, but not immediately before.Ben Zotto
As in did you previously push the commits that you removed in the rebase -i.. From your answer I think not.manojlds
@manojlds: Correct. I only killed commits that were more recent than the most recent push. (Although as I mentioned, I have since pushed, since I thought everything was OK)Ben Zotto
Can you explain what you did in I did a reset of some files to get them out of commit staging part? sorry for the questions :)manojlds

26 Answers

2656
votes

First, let’s clarify what HEAD is and what it means when it is detached.

HEAD is the symbolic name for the currently checked out commit. When HEAD is not detached (the “normal”1 situation: you have a branch checked out), HEAD actually points to a branch’s “ref” and the branch points to the commit. HEAD is thus “attached” to a branch. When you make a new commit, the branch that HEAD points to is updated to point to the new commit. HEAD follows automatically since it just points to the branch.

  • git symbolic-ref HEAD yields refs/heads/master
    The branch named “master” is checked out.
  • git rev-parse refs/heads/master yield 17a02998078923f2d62811326d130de991d1a95a
    That commit is the current tip or “head” of the master branch.
  • git rev-parse HEAD also yields 17a02998078923f2d62811326d130de991d1a95a
    This is what it means to be a “symbolic ref”. It points to an object through some other reference.
    (Symbolic refs were originally implemented as symbolic links, but later changed to plain files with extra interpretation so that they could be used on platforms that do not have symlinks.)

We have HEADrefs/heads/master17a02998078923f2d62811326d130de991d1a95a

When HEAD is detached, it points directly to a commit—instead of indirectly pointing to one through a branch. You can think of a detached HEAD as being on an unnamed branch.

  • git symbolic-ref HEAD fails with fatal: ref HEAD is not a symbolic ref
  • git rev-parse HEAD yields 17a02998078923f2d62811326d130de991d1a95a
    Since it is not a symbolic ref, it must point directly to the commit itself.

We have HEAD17a02998078923f2d62811326d130de991d1a95a

The important thing to remember with a detached HEAD is that if the commit it points to is otherwise unreferenced (no other ref can reach it), then it will become “dangling” when you checkout some other commit. Eventually, such dangling commits will be pruned through the garbage collection process (by default, they are kept for at least 2 weeks and may be kept longer by being referenced by HEAD’s reflog).

1 It is perfectly fine to do “normal” work with a detached HEAD, you just have to keep track of what you are doing to avoid having to fish dropped history out of the reflog.


The intermediate steps of an interactive rebase are done with a detached HEAD (partially to avoid polluting the active branch’s reflog). If you finish the full rebase operation, it will update your original branch with the cumulative result of the rebase operation and reattach HEAD to the original branch. My guess is that you never fully completed the rebase process; this will leave you with a detached HEAD pointing to the commit that was most recently processed by the rebase operation.

To recover from your situation, you should create a branch that points to the commit currently pointed to by your detached HEAD:

git branch temp
git checkout temp

(these two commands can be abbreviated as git checkout -b temp)

This will reattach your HEAD to the new temp branch.

Next, you should compare the current commit (and its history) with the normal branch on which you expected to be working:

git log --graph --decorate --pretty=oneline --abbrev-commit master origin/master temp
git diff master temp
git diff origin/master temp

(You will probably want to experiment with the log options: add -p, leave off --pretty=… to see the whole log message, etc.)

If your new temp branch looks good, you may want to update (e.g.) master to point to it:

git branch -f master temp
git checkout master

(these two commands can be abbreviated as git checkout -B master temp)

You can then delete the temporary branch:

git branch -d temp

Finally, you will probably want to push the reestablished history:

git push origin master

You may need to add --force to the end of this command to push if the remote branch can not be “fast-forwarded” to the new commit (i.e. you dropped, or rewrote some existing commit, or otherwise rewrote some bit of history).

If you were in the middle of a rebase operation you should probably clean it up. You can check whether a rebase was in process by looking for the directory .git/rebase-merge/. You can manually clean up the in-progress rebase by just deleting that directory (e.g. if you no longer remember the purpose and context of the active rebase operation). Usually you would use git rebase --abort, but that does some extra resetting that you probably want to avoid (it moves HEAD back to the original branch and resets it back to the original commit, which will undo some of the work we did above).

644
votes

Just do this:

git checkout master

Or, if you have changes that you want to keep, do this:

git checkout -b temp
git checkout -B master temp
144
votes

I ran into this issue and when I read in the top voted answer:

HEAD is the symbolic name for the currently checked out commit.

I thought: Ah-ha! If HEAD is the symbolic name for the currenlty checkout commit, I can reconcile it against master by rebasing it against master:

git rebase HEAD master

This command:

  1. checks out master
  2. identifies the parent commits of HEAD back to the point HEAD diverged from master
  3. plays those commits on top of master

The end result is that all commits that were in HEAD but not master are then also in master. master remains checked out.


Regarding the remote:

a couple of the commits I'd killed in the rebase got pushed, and the new ones committed locally aren't there.

The remote history can no longer be fast-forwarded using your local history. You'll need to force-push (git push -f) to overwrite the remote history. If you have any collaborators, it usually makes sense to coordinate this with them so everyone is on the same page.

After you push master to remote origin, your remote tracking branch origin/master will be updated to point to the same commit as master.

84
votes

Look here for basic explanation of detached head:

http://git-scm.com/docs/git-checkout

Command line to visualize it:

git branch

or

git branch -a

you will get output like below:

* (no branch)
master
branch1

The * (no branch) shows you are in detached head.

You could have come to this state by doing a git checkout somecommit etc. and it would have warned you with the following:

You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may do so (now or later) by using -b with the checkout command again. Example:

git checkout -b new_branch_name

Now, to get them onto master:

Do a git reflog or even just git log and note your commits. Now git checkout master and git merge the commits.

git merge HEAD@{1}

Edit:

To add, use git rebase -i not only for deleting / killing commits that you don't need, but also for editing them. Just mention "edit" in the commit list and you will be able to amend your commit and then issue a git rebase --continue to go ahead. This would have ensured that you never came in to a detached HEAD.

39
votes

Get your detached commit onto its own branch

Simply run git checkout -b mynewbranch.

Then run git log, and you'll see that commit is now HEAD on this new branch.

27
votes

I found this question when searching for You are in 'detached HEAD' state.

After analyzing what I had done to get here, as compared with what I had done in the past, I discovered that I had made a mistake.

My normal flow is:

git checkout master
git fetch
git checkout my-cool-branch
git pull

This time I did:

git checkout master
git fetch
git checkout origin/my-cool-branch
# You are in 'detached HEAD' state.

The problem is that I accidentally did:

git checkout origin/my-cool-branch

Rather than:

git checkout my-cool-branch

The fix (in my situation) was simply to run the above command and then continue the flow:

git checkout my-cool-branch
git pull
24
votes

If you want to push your current detached HEAD (check git log before), try:

git push origin HEAD:master

to send your detached HEAD into master branch at origin. If your push gets rejected, try git pull origin master first to get the changes from origin. If you don't care about the changes from origin and it's rejected, because you did some intentional rebase and you want to replace origin/master with your currently detached branch - then you may force it (-f). In case you lost some access to previous commits, you can always run git reflog to see the history from all branches.


To get back on a master branch, while keeping the changes, try the following commands:

git rebase HEAD master
git checkout master

See: Git: "Not currently on any branch." Is there an easy way to get back on a branch, while keeping the changes?

22
votes

if you have just master branch and wanna back to "develop" or a feature just do this :

git checkout origin/develop

Note: checking out origin/develop.

You are in detached HEAD state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout...

then

git checkout -b develop

It works :)

13
votes

The following worked for me (using only branch master):

git push origin HEAD:master
git checkout master        
git pull

The first one pushes the detached HEAD to remote origin.

The second one moves to branch master.

The third one recovers the HEAD that becomes attached to branch master.

Problems might arise at the first command if the push gets rejected. But this would no longer be a problem of detached head, but is about the fact that the detached HEAD is not aware of some remote changes.

12
votes

I just ran into this issue today and am pretty sure I solved it by doing:

git branch temp
git checkout master
git merge temp

I was on my work computer when I figured out how to do this, and now I'm running into the same problem on my personal computer. So will have to wait till Monday when I'm back at the work computer to see exactly how I did it.

9
votes

If you are completely sure HEAD is the good state:

git branch -f master HEAD
git checkout master

You probably can't push to origin, since your master has diverged from origin. If you are sure no one else is using the repo, you can force-push:

git push -f

Most useful if you are on a feature branch no one else is using.

7
votes

All you have to do is 'git checkout [branch-name]' where [branch-name] is the name of the original branch from which you got into a detached head state. The (detached from asdfasdf) will disappear.

So for example, in branch 'dev' you checkout the commit asdfasd14314 ->

'git checkout asdfasd14314'

you are now in a detached head state

'git branch' will list something like ->

* (detached from asdfasdf)
  dev
  prod
  stage

but to get out of the detached head state and back to dev ->

'git checkout dev'

and then 'git branch' will list ->

* dev
  prod
  stage

but that is of course if you do not intend on keeping any changes from the detached head state but I find myself doing this a lot not intending to make any changes but just to look at a previous commit

6
votes

As pointed by Chris, I had following situation

git symbolic-ref HEAD fails with fatal: ref HEAD is not a symbolic ref

However git rev-parse refs/heads/master was pointing to a good commit from where I could recover (In my case last commit and you can see that commit by using git show [SHA]

I did a lot messy things after that, but what seems to have fixed is just,

git symbolic-ref HEAD refs/heads/master

And head is re attached!

4
votes

Instead of doing git checkout origin/master

just do git checkout master

then git branch will confirm your branch.

4
votes

For me it was as easy as deleting the local branch again, since I didn't have any local commits that I wanted to push:

So I did:

git branch -d branchname

And then checking the branch out again:

git checkout branchname
3
votes

If you did some commits on top of master and just want to "backwards merge" master there (i.e. you want master to point to HEAD), the one-liner would be:

git checkout -B master HEAD
  1. That creates a new branch named master, even if it exists already (which is like moving master and that's what we want).
  2. The newly created branch is set to point to HEAD, which is where you are.
  3. The new branch is checked out, so you are on master afterwards.

I found this especially useful in the case of sub-repositories, which also happen to be in a detached state rather often.

3
votes

I had the same problem and I have resolved it by going through the following steps.

If you need to keep your changes

  1. First you need to run git checkout master command to put you back to the master branch.
  2. If you need to keep your changes just run git checkout -b changes and git checkout -B master changes

If you don't need your changes

  1. To removes all untracked files from your branch run git clean -df.

  2. Then you need to clear all unstaged changes within your repository. In order to do that you have to run git checkout --

  3. Finally you have to put your branch back to the master branch by using git checkout master command.

3
votes

I had this problem today, where I had updated a submodule, but wasn't on any branch. I had already committed, so stashing, checkout, unstashing wouldn't work. I ended up cherry-picking the detached head's commit. So immediately after I committed (when the push failed), I did:

git checkout master
git cherry-pick 99fe23ab

My thinking went: I'm on a detached head, but I want to be on master. Assuming my detached state is not very different from master, if I could apply my commit to master, I'd be set. This is exactly what cherry-pick does.

1
votes

When I personally find myself in a situation when it turns out that I made some changes while I am not in master (i.e. HEAD is detached right above the master and there are no commits in between) stashing might help:

git stash # HEAD has same content as master, but we are still not in master
git checkout master  # switch to master, okay because no changes and master
git stash apply  # apply changes we had between HEAD and master in the first place
1
votes

In simple words, the detached HEAD state means you are not checked out to HEAD (or tip) of any branch.

Understand With an Example

A branch in most of the cases is sequence of multiple commits like:

Commit 1: master-->branch_HEAD(123be6a76168aca712aea16076e971c23835f8ca)

Commit 2: master-->123be6a76168aca712aea16076e971c23835f8ca-->branch_HEAD(100644a76168aca712aea16076e971c23835f8ca)

As you can see above in case of sequence of commits, your branch points to your latest commit. So in that case if you checkout to commit 123be6a76168aca712aea16076e971c23835f8ca then you would be in detached head state since HEAD of your branch points to 100644a76168aca712aea16076e971c23835f8ca and technically you are checked out at HEAD of no branch. Hence, you are in the detached HEAD state.

Theoretical Explanation

In this Blog it's clearly stating a Git repository is a tree-of-commits, with each commit pointing to its ancestor with each commit pointer is updated and these pointers to each branch are stored in the .git/refs sub-directories. Tags are stored in .git/refs/tags and branches are stored in .git/refs/heads. If you look at any of the files, you'll find each tag corresponds to a single file, with a 40-character commit hash and as explained above by @Chris Johnsen and @Yaroslav Nikitenko, you can check out these references.

0
votes

I got into a really silly state, I doubt anyone else will find this useful.... but just in case

git ls-remote origin
0d2ab882d0dd5a6db93d7ed77a5a0d7b258a5e1b        HEAD
6f96ad0f97ee832ee16007d865aac9af847c1ef6        refs/heads/HEAD
0d2ab882d0dd5a6db93d7ed77a5a0d7b258a5e1b        refs/heads/master

which I eventually fixed with

git push origin :HEAD
0
votes

This worked for me perfectly:

1.git stash to save your local modifications

If you want to discard changes
git clean -df
git checkout -- .
git clean removes all untracked files (warning: while it won't delete ignored files mentioned directly in .gitignore, it may delete ignored files residing in folders) and git checkout clears all unstaged changes.

2.git checkout master to switch to the main branch (Assuming you want to use master)
3.git pull to pull last commit from master branch
4.git status in order to check everything looks great

On branch master
Your branch is up-to-date with 'origin/master'.
0
votes

In my case, I ran git status, and I saw that I had a few untracked files in my working directory.

To make the rebase work, I just had to clean them (since I didn't need them).

0
votes

If you are using EGit in Eclipse: assume your master is your main development branch

  • commit you changes to a branch, normally a new one
  • then pull from the remote
  • then right click the project node, choose team then choose show history
  • then right click the master, choose check out
  • if Eclipse tells you, there are two masters one local one remote, choose the remote

After this you should be able to reattach to the origin-master.

-1
votes

I had the same problem. I stash my changes with git stash and hard reset the branch in local to a previous commit(I thought it caused that) then did a git pull and I am not getting that head detached now. Dont forget git stash apply to have your changes again.

-2
votes
git checkout checksum  # You could use this to peek previous checkpoints
git status # You will see HEAD detached at checksum
git checkout master # This moves HEAD to master branch