Why did my Git repo enter a detached HEAD state?
Asked Answered
A

15

481

I ended up with a detached head today, the same problem as described in: git push says everything up-to-date even though I have local changes

As far as I know I didn't do anything out of the ordinary, just commits and pushes from my local repo.

So how did I end up with a detached HEAD?

Anguiano answered 19/10, 2010 at 5:54 Comment(7)
Checking out a remote branch seems like the most common way to accidentally do this; another common way is to check out branch-name@{n}, the nth previous position of branch-name. But no matter what, at some point there must've been a git checkout <rev>. If that doesn't ring a bell, then probably you did what Will mentioned - tried to do git checkout <file> and managed to specify a revision by accident.Tangible
For undoing a detached HEAD state, see Fix a Git detached head?.Roybal
Also happens if you accidentally type git checkout remotes/origin/my-branch instead of git checkout my-branch or git checkout origin/my-branch.Battat
@adam Libusa,Thanks it worked for me. What is the difference between git checkout remotes/origin/my-branch and git checkout my-branch. Is it not the same. but what you said worked for me. Out of curiosity I am asking.Unhandy
@karunakarbhogyari The difference between git checkout my-branch and git checkout origin/my-branch is explained here: https://mcmap.net/q/11941/-can-39-t-do-a-checkout-with-multiple-remotes. As for the first case, remotes/origin/my-branch, I'd find it reasonable for git to behave similarly for all its commands. git show handles such branch names fine. I'd go as far as call it a bug, or at least an inconsistency in git-cli.Battat
I often run into a detached HEAD state when I work with submodules. Unfortunately, I cannot reproduce such a state nor do I remember the exact sequence of commands that lead to the detached state. If someone had a hint on that, I'd be very grateful.Echolocation
tl;dr -- you probably checked out a remote branch instead of the local one -- (or it doesn't exist) -- use this command to create the local branch and switch it: git switch -c <branch> --track <remote>/<branch>Claqueur
G
406

Any checkout of a commit that is not the name of one of your branches will get you a detached HEAD. A SHA1 which represents the tip of a branch still gives a detached HEAD. Only a checkout of a local branch name avoids that mode.

See committing with a detached HEAD

When HEAD is detached, commits work like normal, except no named branch gets updated. (You can think of this as an anonymous branch.)

alt text

For example, if you checkout a "remote branch" without tracking it first, you can end up with a detached HEAD.

See git: switch branch without detaching head

Meaning: git checkout origin/main (or origin/master in the old days) would result in:

Note: switching to 'origin/main'.

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 switching back to a branch.

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

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at a1b2c3d My commit message

That is why you should not use git checkout anymore, but the new git switch command.

With git switch, the same attempt to "checkout" (switch to) a remote branch would fail immediately:

git switch origin/main
fatal: a branch is expected, got remote branch 'origin/main'

To add more on git switch:

With Git 2.23 (August 2019), you don't have to use the confusing git checkout command anymore.

git switch can also checkout a branch, and get a detach HEAD, except:

  • it has an explicit --detach option

To check out commit HEAD~3 for temporary inspection or experiment without creating a new branch:

git switch --detach HEAD~3
HEAD is now at 9fc9555312 Merge branch 'cc/shared-index-permbits'
  • it cannot detached by mistake a remote tracking branch

See:

C:\Users\vonc\arepo>git checkout origin/master
Note: switching to 'origin/master'.

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 switching back to a branch.

Vs. using the new git switch command:

C:\Users\vonc\arepo>git switch origin/master
fatal: a branch is expected, got remote branch 'origin/master'

If you wanted to create a new local branch tracking a remote branch:

git switch <branch> 

If <branch> is not found but there does exist a tracking branch in exactly one remote (call it <remote>) with a matching name, treat as equivalent to

git switch -c <branch> --track <remote>/<branch>

No more mistake!
No more unwanted detached HEAD!

And if you git switch <tag> instead of git switch --detach <tag>, Git 2.36 will help you to remember the missing --detach option.

Genipap answered 19/10, 2010 at 6:4 Comment(24)
Another way you can enter detached head state is if you're in the middle of an interactive rebase, and you want to edit one of the commits. When Git drops you at the commit to edit, you'll be in a detached head state until you finish the rebase.Roybal
In this visual guide, there's this explanation: git commit files creates a new commit containing the contents of the latest commit, plus a snapshot of files taken from the working directory. Additionally, files are copied to the stage. What does it mean by "files are copied to the stage"? I thought the files are committed, which means the stage is cleared?Desuetude
@max: this extract you mention is for a git commit -a: the stage isn't so much 'cleared' as 'made identical to the new commit', which means any new modification will be detected in a git diff, because git diff compares the working tree to the index. So that is why the git commit man page describes the -a option as "Tell the command to automatically stage files that have been modified and deleted"Genipap
In fact, you will get a detached HEAD whenever you checkout any commit by its SHA1, whether or not it's at the tip of a branch; the only kind of thing you can checkout without getting a detached HEAD is a branch name. For example, even though master is at ed489 on the diagram above, git checkout ed489 will give you a detached HEAD, while git checkout master will not.Monoceros
"You can think of this as an anonymous branch" :) I like the analogyUnman
I did git checkout origin/552 and got Note: checking out 'origin/552 You are in 'detached HEAD' state... Then a few days later I did such and didn't get that error. Can you explain why? (FYI I haven't downloaded that branch itself locally...)Khasi
@Honey Not sure: asking that as a new question (with more details, like Git version and OS, and shell used when checking out the branch) should help. In particular, the output of git branch -avv is important.Genipap
"A SHA1 which represents the tip of a branch still gives a detached HEAD." I wonder what's the reason behind this design.Smaltite
@Smaltite The commit itself has no idea it resents the tip of a branch. Only the branch itself (in .git/refs/heads/<aBranchName>) knows which commit represents its HEAD.Genipap
Sure, but it would be trivial to check whether the checked out commit is referenced by one of the files in .git/refs/heads. So with my limited knowledge not doing this still seems odd.Smaltite
@Smaltite The idea is to differentiate a checkout of a SHA1 (referenced or not by one of the files in .git/refs/heads from a checkout of a branch (referencing in turn a commit as its HEAD). Those are two different use cases.Genipap
Thanks. What are those use cases you speak of? Do you have a real world example where I would want to do something different with checkout <branch X> and checkout <hash branch X points to>?Smaltite
@Smaltite Simple: when you checkout "aBranch", you don't know what you get. If you did any pull, that branch SHA1 could have changed. When you check out a SHA1, you know precisely what you get, a fixed content which won't change in time. A branch can be updated, renamed, deleted, in short transient. A commit is immutable. A CI/CD tool usually works with SHA1, especially when you need to replay an old build which has failed.Genipap
Thanks. I need to think about that a little. I can see why checking out a branch can and should give different results depending on where that branch points to at the moment. I'm not quite convinced yet that detached head mode makes sense if you check out a commit that happens to be a branch.Smaltite
@Smaltite Example: simonberner.rocks/2019/10/01/Jenkins-In-Detached-HEAD , devcenter.bitrise.io/jp/faq/…, thenewstack.io/…Genipap
What are the steps to get into a detached head when doing checking out a remote branch? Because when I do 1. git fetch 2. git checkout <name-of-remote-branch> I successfully create a new local branch, like git just knows what I intended as discussed hereKhasi
@Honey That is expected, because the guess mode is the default: git-scm.com/docs/git-switch#Documentation/… (see also the last part of https://mcmap.net/q/12259/-git-change-branch-when-file-of-same-name-is-present). Any branch name which exists in the remote namespace means a git switch/git checkout would create a local branch tracking the remote one. Detached HEAD means you switch to a commit SHA1, not a branch name.Genipap
Thanks, I'm still confused a bit about what sequence of git commands result in 'if you checkout a "remote branch" without tracking it first, you can end up with a detached HEAD' Can you share that please?Khasi
@Honey Sure. I have edited the answer to add an example where I do checkout a remote branch... and end up with a detached HEAD.Genipap
How do you check out a remote branch without detaching? git switch doesn't allow this, and git checkout leads to a detached head.Psid
@AaronFranke You create a new local branch: git switch -c abranch: if origin/abranch exists, it will be checked out and tracked automatically for you.Genipap
But I already have a local branch with the same name (there's local master, origin/master, upstream/master, and local has origin set as the remote). I want to reset my local master to upstream's master.Psid
@AaronFranke To reset a branch to another: git switch -C master upstream/master: you force the recreation of master, starting from upstream/masterGenipap
@Monoceros using the name of a branch is not a guarantee that you won't get a detached head. The word "your" in the first sentence of this answer needs more emphasis. I kept getting a detached head when checking out a remote branch, never using a hash at all. I'm still not sure I'll be able to avoid it next time I try.Prologue
F
177

I reproduced this just now by accident:

  1. lists the remote branches

    git branch -r
          origin/Feature/f1234
          origin/master
    
  2. I want to checkout one locally, so I cut paste:

    git checkout origin/Feature/f1234
    
  3. Presto! Detached HEAD state

    You are in 'detached HEAD' state. [...])
    

Solution #1:

Do not include origin/ at the front of my branch spec when checking it out:

git checkout Feature/f1234

Solution #2:

Add -b parameter which creates a local branch from the remote

git checkout -b origin/Feature/f1234 or

git checkout -b Feature/f1234 it will fall back to origin automatically

Frisk answered 23/4, 2015 at 15:43 Comment(5)
This is almost a great answer, but fails to explain why you got into a detached head state.Fiord
I agree but it does provide the solution i was looking for. Thanks!!Sistrunk
I saw in this other answer that git checkout -b Feature/f1234 <=> git branch Feature/f1234 and git checkout Feature/f1234.Humic
by default it looks in origin, so when you give origin/branchname, it looks for origin/origin/branchname to tell that first one is remote name you use -b, if u don't it creates a anonymous branch which is detached. Similarly for checking out from a different remote you would have to mention -b parameter otherwise git doesn't have a way to know it is from a new remote, it will look for origin/remote/branchname.Sunset
The hint about omitting "origin/" worked like a charm. Thanks!Colb
P
13

Detached HEAD means that what's currently checked out is not a local branch.

Some scenarios that will result in a Detached HEAD state:

  • If you checkout a remote branch, say origin/master. This is a read-only branch. Thus, when creating a commit from origin/master it will be free-floating, i.e. not connected to any branch.

  • If you checkout a specific tag or commit. When doing a new commit from here, it will again be free-floating, i.e. not connected to any branch. Note that when a branch is checked out, new commits always gets automatically placed at the tip.

    When you want to go back and checkout a specific commit or tag to start working from there, you could create a new branch originating from that commit and switch to it by git checkout -b new_branch_name. This will prevent the Detached HEAD state as you now have a branch checked out and not a commit.

Pedo answered 25/11, 2019 at 22:9 Comment(0)
G
12

try

git reflog 

this gives you a history of how your HEAD and branch pointers where moved in the past.

e.g. :

88ea06b HEAD@{0}: checkout: moving from DEVELOPMENT to remotes/origin/SomeNiceFeature e47bf80 HEAD@{1}: pull origin DEVELOPMENT: Fast-forward

the top of this list is one reasone one might encounter a DETACHED HEAD state ... checking out a remote tracking branch.

Guenther answered 4/5, 2015 at 14:58 Comment(0)
J
11

It can happen if you have a tag named same as a branch.

Example: if "release/0.1" is tag name, then

git checkout release/0.1

produces detached HEAD at "release/0.1". If you expect release/0.1 to be a branch name, then you get confused.

Jayjaycee answered 28/9, 2017 at 13:57 Comment(3)
Yes. But how to you fix that? How do you du a checkout of the branch?Harberd
I fixed that with this https://mcmap.net/q/11950/-how-do-you-rename-a-git-tag. The last command (git pull --prune --tags) didn't work so I did git tag -l | xargs git tag -d to remove local tags and git fetch --tags to refetch remote tagsGunshy
This was exactly my problem. The Git warning message doesn't give any clues as to this being a possibility.Unproductive
K
8

If git was to rename detached HEAD I would have it named as a HEAD that isn’t identified by a branch and will soon be forgotten.

We as people can easily remember branch names. We do git checkout new-button-feature / git checkout main. main and new-button-feature are easy to remember. And we can just do git branch and get a list of all branches. But to do the same with just commits you'd have to do git reflog which is very tedious. Because you have thousands of commits but only very few branches.

A detached commit’s identifier is just its SHA. So suppose you checked out a commit (not a branch) i.e. you did git checkout d747dd10e450871928a56c9cb7c6577cf61fdf31 you'll get:

Note: checking out 'd747dd10e450871928a56c9cb7c6577cf61fdf31'.

You are in 'detached HEAD' state.

...

Then if you made some changes and made a commit, you're still NOT on a branch.

Do you think you'd remember the commit SHA? You won't!

git doesn't want this to happen. Hence it's informing your HEAD is not associated to a branch so you're more inclined to checkout a new branch. As a result below that message it also says:

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


To go a bit deeper a branch is built in a way that it's smart. It will update its HEAD as you make commits. Tags on the other hand are not meant to be like that. If you checkout a tag, then you're again on a detached HEAD. The main reason is that if you make a new commit from that tag then given that that commit is not referenced by anything (not any branch or tag) then still its considered a detached HEAD.

Attached HEADs can only happen when you're on a branch.

For more see here

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.

To look at from another angle, if you're on a branch and do cat .git/HEAD you'd get:

ref: refs/heads/Your-current-branch-name

Then if you do cat refs/heads/Your-current-branch-name then you'd also see the SHA of the commit that your branch is pointing/referencing to.

However if you were on a detached HEAD you and cat .git/HEAD you'd just get the SHA of the commit and nothing more:

639ce5dd952a645b7c3fcbe89e88e3dd081a9912

By nothing more I mean the head isn't pointing to any branch. It's just directly pointing to a commit.


As a result of all this, anytime you checkout a commit (without using the branch name to checkout), even if that commit was the latest commit of your main branch, you're still in a detached HEAD because your HEAD is not pointing to any of your local branches. Hence even checking out a tag will put you in a detached HEAD. To add onto that, even checking out a remote branch that you have fetched into your computer would result in a detached head ie git checkout origin main would also end up as a detached head...

Summary

All of the following will cause detached head:

  • checkout any commit
  • checkout any tag
  • checkout any remote branch

You're only on an attached head, if you've checked out a local branch


Special thanks to Josh Caswell & Saagar Jha in helping me figure this out.

Khasi answered 22/1, 2021 at 14:51 Comment(1)
This is a nice blog post by SO on some internals of git. Branches are just pointers to commits and how switching branches, changes where HEAD is pointing to. It’s worth the read, but if you just wanted to skip to the internals of git then scroll down to ‘How do branches work technically, under the hood?’. It has some nice screenshotsKhasi
V
6

It can easily happen if you try to undo changes you've made by re-checking-out files and not quite getting the syntax right.

You can look at the output of git log - you could paste the tail of the log here since the last successful commit, and we could all see what you did. Or you could paste-bin it and ask nicely in #git on freenode IRC.

Volitant answered 19/10, 2010 at 6:8 Comment(0)
P
4

A simple accidental way is to do a git checkout head as a typo of HEAD.

Try this:

git init
touch Readme.md
git add Readme.md
git commit
git checkout head

which gives

Note: checking out 'head'.

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>

HEAD is now at 9354043... Readme
Papist answered 8/6, 2017 at 12:45 Comment(2)
Also mentioned in longair.net/blog/2012/05/07/the-most-confusing-git-terminology (look for "“HEAD” and “head”")Genipap
@VonC: thanks for that link. I'm preparing a Git training and I also want to point out why it's sometimes so confusing. I have a lot of examples already (like checkout -b which looks like a checkout but actually branches) but another list is just welcome.Papist
D
4

Detached HEAD

HEAD is a pointer to the currently checked out branch or commit, it answers the question: Where am I right now in the repository? HEAD can be in either of two states, attached (default) or detached, depending on if you've checked out a local branch or not.

OP: How did I end up with a detached HEAD?

Operations than leave HEAD in detached state

Ending up in detached HEAD state can be due to various reasons, below are 5 common cases (perhaps did you do any of the following):

  • Checking out a particular commit using its hash, i.e.
    $ git checkout 14ko3
    
  • Explicitly checking out a remote branch, i.e.
    $ git checkout origin/master
    
  • Switching to a branch using the detached flag (Git 2.23), i.e.
    $ git switch master --detached
    
  • Checking out a tag, i.e.
    $ git checkout v1.0.1
    
  • Performing an interactive rebase (or a regular rebase containing conflicting changes), i.e.
    $ git rebase master feature-1 --interactive
    

In detached state experimental changes can be made without impacting any existing branch. See infographic below illustrating the difference between committing in attached vs detached state.

Comparison between detached and attached HEAD state

A common misconception is that the message You are in 'detached HEAD' state is of erroneous tone, when in fact it just describes how HEAD is referencing the current snapshot.

Moving from detached to attached state

To move from detached to attached state, you can either create a new branch from where you're at, or switch back to an existing branch.

Note: any commits created in detached state will eventually (post garbage collection) be discarded if you switch to another existing branch, without first persisting your changes in a new branch.

Source: Above excerpt is taken from this full length post on the subject: What is HEAD in Git?

Dorfman answered 30/9, 2021 at 7:37 Comment(0)
L
3

The other way to get in a git detached head state is to try to commit to a remote branch. Something like:

git fetch
git checkout origin/foo
vi bar
git commit -a -m 'changed bar'

Note that if you do this, any further attempt to checkout origin/foo will drop you back into a detached head state!

The solution is to create your own local foo branch that tracks origin/foo, then optionally push.

This probably has nothing to do with your original problem, but this page is high on the google hits for "git detached head" and this scenario is severely under-documented.

Lapierre answered 27/5, 2016 at 21:41 Comment(1)
This situation seems to be what Owen's answer above talks about -- where cutting and pasting "origin/foo" makes git think of it as "origin/origin/foo".Mariquilla
Y
2

When you checkout to a commit git checkout <commit-hash> or to a remote branch your HEAD will get detached and try to create a new commit on it.

Commits that are not reachable by any branch or tag will be garbage collected and removed from the repository after 30 days.

Another way to solve this is by creating a new branch for the newly created commit and checkout to it. git checkout -b <branch-name> <commit-hash>

This article illustrates how you can get to detached HEAD state.

Yee answered 7/5, 2018 at 12:40 Comment(0)
U
1

Following VonC's comment, here is the short version of how I resolved this same 'detached HEAD' issue.

  1. Created a branch in my remote; origin/feature/dev
  2. In my local run git fetch, so now my local will be aware of this new remote branch
  3. Now run git switch feature/dev, and we are done!
Upwind answered 31/5, 2021 at 19:59 Comment(0)
S
1

For others who may be looking into a way of getting the branch name but are getting HEAD instead, here is what I came up with:

const { execSync } = require('child_process');

const getBranchName = () => {
  let branch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
  if (branch === 'HEAD') branch = execSync(`git branch -a --contains HEAD | sed -n 2p | awk '{ printf $1 }'`).toString().trim();
  return branch;
}
Stockinet answered 14/9, 2022 at 17:4 Comment(0)
C
0

For my case it happens this way:

  • Create a new branch (feb_debugging).
  • Run git fetch
  • I see new branch (feb_debugging) pulled
  • Now, I use git checkout origin/feb_debugging

Here it gets me to HEAD is now at....

For fixing I just need another checkout

  • git checkout feb_debugging
  • Now git says that I am at feb_debugging branch.
Cinchonine answered 28/3, 2021 at 9:49 Comment(0)
B
-1

If you cannot use git switch, use 'git checkout -b [branch]' instead of 'git checkout [branch]'.

Blind answered 8/12, 2022 at 3:48 Comment(1)
The question was about why/how the OP is getting a "detached HEAD" state. This seems to be a comment on the answers that say to use git switch. Other answers already mention using git checkout -b.Aerodontia

© 2022 - 2024 — McMap. All rights reserved.