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.
I did a reset of some files to get them out of commit staging
part? sorry for the questions :)
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 HEAD
→ refs/heads/master
→ 17a02998078923f2d62811326d130de991d1a95a
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 HEAD
→ 17a02998078923f2d62811326d130de991d1a95a
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).
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
git reset
should come with a warning "If you have no idea what you're doing, stop it". Just recovered from an hour of terror thinking I'd lost the last week of work. Thanks!
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:
checks out master identifies the parent commits of HEAD back to the point HEAD diverged from master 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
.
git reflog
then reset your branch to that commit with git rest —hard $commit
master
on top of the detached HEAD
. In other words, the commits naively done on the detached HEAD
are exactly where I intended them to be, namely somewhere in history and not on top of master
. I would normally use interactive rebase for this. Side note: git rebase master HEAD
does the opposite and plays the commits on the detached HEAD
on top of master
, as described in this answer.
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.
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.
mynewbranch
attach to anything?
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
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 :)
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
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.
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.
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.
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
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!
Instead of doing git checkout origin/master
just do git checkout master
then git branch
will confirm your branch.
I had the same problem and I have resolved it by going through the following steps.
If you need to keep your changes
First you need to run git checkout master command to put you back to the master branch. 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
To removes all untracked files from your branch run git clean -df. Then you need to clear all unstaged changes within your repository. In order to do that you have to run git checkout -- Finally you have to put your branch back to the master branch by using git checkout master command.
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
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
That creates a new branch named master, even if it exists already (which is like moving master and that's what we want). The newly created branch is set to point to HEAD, which is where you are. 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.
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.
if you want to save changes made on detached head simply do this: make temporary branch and commit it with your changes done and then go to YOUR-BRANCH and merge the temp with it. Finally, delete temporary branch.
git checkout -b temp
git add . && git commit -m 'save changes'
git checkout YOUR-BRANCH
git merge temp
git branch -d temp
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
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.
Simplest solution is create a new branch,
git checkout -b new-branch-name
then check your commit logs by command,
git log
if everything matches then quit by :q
now push all your changes to new branch by command
git push --set-upstream origin new-branch-name
Now, problem resolved and your local git HEAD attached to new branch, you can raise pull request from portal.
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
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'.
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).
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.
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.
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
Success story sharing
man git-symbolic-ref
: "In the past,.git/HEAD
was a symbolic link pointing atrefs/heads/master
. When we wanted to switch to another branch, we didln -sf refs/heads/newbranch .git/HEAD
, and when we wanted to find out which branch we are on, we didreadlink .git/HEAD
. But symbolic links are not entirely portable, so they are now deprecated and symbolic refs (as described above) are used by default."git branch -f master HEAD && git checkout master
is enough -- assuming your goal is to keep your current head but to designate it asmaster
. Other goals also make sense, and call for other recipes.