[git] How do I fix a Git detached head?

I was doing some work in my repository and noticed a file had local changes. I didn't want them anymore so I deleted the file, thinking I can just checkout a fresh copy. I wanted to do the Git equivalent of

svn up .

Using git pull didn't seem to work. Some random searching led me to a site where someone recommended doing

git checkout HEAD^ src/

(src is the directory containing the deleted file).

Now I find out I have a detached head. I have no idea what that is. How can I undo?

This question is related to git git-detached-head

The answer is


Git told me how to do it.

if you typed:

git checkout <some-commit_number>

Save the status

git add .
git commit -m "some message"

Then:

 git push origin HEAD:<name-of-remote-branch>

When you check out a specific commit in git, you end up in a detached head state...that is, your working copy no longer reflects the state of a named reference (like "master"). This is useful for examining the past state of the repository, but not what you want if you're actually trying to revert changes.

If you have made changes to a particular file and you simply want to discard them, you can use the checkout command like this:

git checkout myfile

This will discard any uncommitted changes and revert the file to whatever state it has in the head of your current branch. If you want to discard changes that you have already committed, you may want to use the reset command. For example, this will reset the repository to the state of the previous commit, discarding any subsequent changes:

git reset --hard HEAD^

However, if you are sharing the repository with other people, a git reset can be disruptive (because it erases a portion of the repository history). If you have already shared changes with other people, you generally want to look at git revert instead, which generates an "anticommit" -- that is, it creates a new commit that "undoes" the changes in question.

The Git Book has more details.


Detached head means:

  1. You are no longer on a branch,
  2. You have checked out a single commit in the history

If you have no changes: you can switch to master by applying the following command

  git checkout master

If you have changes that you want to keep:

In case of a detached HEAD, commits work like normal, except no named branch gets updated. To get master branch updated with your committed changes, make a temporary branch where you are (this way the temporary branch will have all the committed changes you have made in the detached HEAD), then switch to the master branch and merge the temporary branch with the master.

git branch  temp
git checkout master
git merge temp

Addendum

If the branch to which you wish to return was the last checkout that you had made, you can simply use checkout @{-1}. This will take you back to your previous checkout.

Further, you can alias this command with, for example, git global --config alias.prev so that you just need to type git prev to toggle back to the previous checkout.


To further clarify @Philippe Gerber's answer, here it is:

git cherry-pick

Before cherry-pick, a git checkout master is necessary in this case. Furthermore, it is only needed with a commit in detached head.


Since "detached head state" has you on a temp branch, just use git checkout - which puts you on the last branch you were on.


Here's what I just did after I realized I was on a detached head and had already made some changes.

I committed the changes.

$ git commit -m "..."
[detached HEAD 1fe56ad] ...

I remembered the hash (1fe56ad) of the commit. Then I checked out the branch I should have been on.

$ git checkout master
Switched to branch 'master'

Finally I applied the changes of the commit to the branch.

$ git cherry-pick 1fe56ad
[master 0b05f1e] ...

I think this is a bit easier than creating a temporary branch.


When you're in a detached head situation and created new files, first make sure that these new files are added to the index, for example with:

git add .

But if you've only changed or deleted existing files, you can add (-a) and commit with a message (-m) at the the same time via:

git commit -a -m "my adjustment message"

Then you can simply create a new branch with your current state with:

git checkout -b new_branch_name

You'll have a new branch and all your adjustments will be there in that new branch. You can then continue to push to the remote and/or checkout/pull/merge as you please.


The detached HEAD means that you are currently not on any branch. If you want to KEEP your current changes and simply create a new branch, this is what you do:

git commit -m "your commit message"
git checkout -b new_branch

Afterwards, you potentially want to merge this new branch with other branches. Always helpful is the git "a dog" command:

git log --all --decorate --oneline --graph

This works for me, It will assign a new branch for detached head :

git checkout new_branch_name detached_head_garbage_name


Normally HEAD points to a branch. When it is not pointing to a branch instead when it points to a commit hash like 69e51 it means you have a detached HEAD. You need to point it two a branch to fix the issue. You can do two things to fix it.

  1. git checkout other_branch // Not possible when you need the code in that commit hash
  2. create a new branch and point the commit hash to the newly created branch.

HEAD must point to a branch, not a commit hash is the golden rule.


Realizing I had a detached head without knowing how I managed to get it (like three commits away), I also found out that trying to merge, rebase or cherry-pick triggered hundreds of merge-conflicts, so I took a different approach:

  1. (Assuming everything is committed (working tree is "clean"))

  2. Save my commit messages: git log > /tmp/log

  3. Save my working tree: mkdir /tmp/backup && cp -a all_my files_and_directories /tmp/backup

  4. Revert to master: git checkout master

  5. Remove all the working files and directories: rm ...

  6. Use the backup: cp -a /tmp/backup/. .

  7. git add and git commit using messages from saved /tmp/log, maybe repeating it with different sub-sets of files...

The disadvantage is that you loose your commit history if one file was changed multiple times since master, but in the end I had a clean master.


A solution without creating a temporary branch.

How to exit (“fix”) detached HEAD state when you already changed something in this mode and, optionally, want to save your changes:

  1. Commit changes you want to keep. If you want to take over any of the changes you made in detached HEAD state, commit them. Like:

    git commit -a -m "your commit message"
    
  2. Discard changes you do not want to keep. The hard reset will discard any uncommitted changes that you made in detached HEAD state:

    git reset --hard
    

    (Without this, step 3 would fail, complaining about modified uncommitted files in the detached HEAD.)

  3. Check out your branch. Exit detached HEAD state by checking out the branch you worked on before, for example:

    git checkout master
    
  4. Take over your commits. You can now take over the commits you made in detached HEAD state by cherry-picking, as shown in my answer to another question.

    git reflog
    git cherry-pick <hash1> <hash2> <hash3> …
    

I wanted to keep my changes so, I just fix this doing...

git add .
git commit -m "Title" -m "Description"
(so i have a commit now example: 123abc)
git checkout YOURCURRENTBRANCH
git merge 123abc
git push TOYOURCURRENTBRANCH

that work for me


git pull origin master

worked for me. It was just about giving remote and branch name explicitly.


Detached head means you have not checked out your branch properly or you have just checked out a single commit.

If you encounter such an issue then first stash your local changes so that you won't lose your changes.

After that... checkout your desired branch using the command:

Let's say you want branch MyOriginalBranch:

git checkout -b someName origin/MyOriginalBranch


you probably did git reset --hard origin/your-branch.

Try to just git checkout your-branch


This approach will potentially discard part of the commit history, but it is easier in case the merge of the old master branch and the current status is tricky, or you simply do not mind losing part of the commit history.

To simply keep things as currently are, without merging, turning the current detached HEAD into the master branch:

  1. Manually back up the repository, in case things go unexpectedly wrong.
  2. Commit the last changes you would like to keep.
  3. Create a temporary branch (let's name it detached-head) that will contain the files in their current status:
git checkout -b detached-head
  1. (a) Delete the master branch if you do not need to keep it
git branch -D master
  1. (b) OR rename if you want to keep it
git branch -M master old-master
  1. Rename the temporary branch as the new master branch
git branch -M detached-head master

Credit: adapted from this Medium article by Gary Lai.


Being in "detached head" means that HEAD refers to a specific unnamed commit (as opposite to a named branch) (cf: https://git-scm.com/docs/git-checkout section Detached head)

To fix the problem, you only need to select the branch that was selected before by

git checkout @{-1}


If you have changed files you don't want to lose, you can push them. I have committed them in the detached mode and after that you can move to a temporary branch to integrate later in master.

git commit -m "....."
git branch my-temporary-work
git checkout master
git merge my-temporary-work

Extracted from:

What to do with commit made in a detached head


If you made changes and then realized that you are on a detached head, you can do: stash -> checkout master -> stash pop:

git stash
git checkout master   # Fix the detached head state
git stash pop         # Or for extra safety use 'stash apply' then later 
                      #   after fixing everything do 'stash drop'

You will have your uncommited changes and normal "attached" HEAD, like nothing happened.


HEAD is a pointer, and it points — directly or indirectly — to a particular commit:

Attached  HEAD means that it is attached to some branch (i.e. it points to a branch).
Detached HEAD means that it is not attached to any branch, i.e. it points directly to some commit.

enter image description here

In other words:

  • If it points to a commit directly, the HEAD is detached.
  • If it points to a commit indirectly, (i.e. it points to a branch, which in turn points to a commit), the HEAD is attached.

To better understand situations with attached / detached HEAD, let's show the steps leading to the quadruplet of pictures above.

We begin with the same state of the repository (pictures in all quadrants are the same):

enter image description here


Now we want to perform git checkout — with different targets in the individual pictures (commands on top of them are dimmed to emphasize that we are only going to apply those commands):

enter image description here


This is the situation after performing those commands:

enter image description here

As you can see, the HEAD points to the target of the git checkout command — to a branch (first 3 images of the quadruplet), or (directly) to a commit (the last image of the quadruplet).

The content of the working directory is changed, too, to be in accordance with the appropriate commit (snapshot), i.e. with the commit pointed (directly or indirectly) by the HEAD.


So now we are in the same situation as in the start of this answer:

enter image description here