Alex Alex - 3 months ago 27
Git Question

Git detached head - return to earlier commit and apply changes from there

I've made a mess of my git repo and am hoping that there is a fix for this. I tried to do some upgrades of a library dependency that went bad. I couldn't find a way to undo them, so I just decided to go back to an earlier commit and then work from there, thinking that I would merge things later on. However, I wound up with origin/master being detached from the head and now I am unable to push anything to the remote repo. Here is a screen shot of the current state of things:

enter image description here

I couldn't care less about that branch. I just want it to go back into the hole it crawled out of. But I can't make it happen.

I've tried to revert the commit like this:

git revert 7921869




error: revert is not possible because you have unmerged files.

hint: Fix them up in the work tree, and then use 'git add/rm
'
hint: as appropriate to mark resolution and make a
commit.
fatal: revert failed



I've also tried to push the changes:

git push origin HEAD:master



To https://xxx@bitbucket.org/xxx/xxx.git ! [rejected] HEAD ->
master (non-fast-forward)
error: failed to push some refs to
'https://xxx@bitbucket.org/xxx/xxx.git'
hint: Updates were
rejected because a pushed branch tip is behind its remote
hint:
counterpart. Check out this branch and integrate the remote
changes
hint: (e.g. 'git pull ...') before pushing again.

hint: See the 'Note about fast-forwards' in 'git push --help' for
details.



git push origin master --force



error: src refspec master does not match any.
error: failed to push
some refs to
'https://xxx@bitbucket.org/xxx/xxx.git'


And I did this:

git show-ref



79218694bc34715b3d632dc0057f01fc2df2c842 refs/remotes/origin/master


Can anyone help me unwind this so that I don't have a detached head? I need
origin/master
to be consistent with the ddf4a1f commit as if f0dd017 an 7921869 had never happened. If I just do
git checkout master
or
git checkout e416f24
I lose the 4 subsequent commits and I can't let that happen.

Thanks.

EDIT

In case I didn't explain this well, the line on the left is perfect. I just need to get the master to point to that final commit such that I can push to the remote again. Forget the pink branch. That is garbage and I don't want to use it at all.

EDIT 2

I've followed the advice below by Tim Biegeleisen and I think I'm almost there. Now I have this state:

enter image description here

So now when I do
git push origin master
I get this:


To https://xxx@bitbucket.org/xxx/xxx.git

! [rejected] master -> master (non-fast-forward)
error: failed
to push some refs to
'https://xxx@bitbucket.org/xxx/xxx.git'

hint: Updates were rejected because the tip of your current branch is
behind
hint: its remote counterpart. Integrate the remote changes
(e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note
about fast-forwards' in 'git push --help' for details.


But if I do as the message says and do
git pull ...
won't I defeat the entire purpose of this and bring back in the garbage from
origin/master
?

Can I just do
git push origin master --force
?

Answer

One approach to end this madness would be to commit any work you have in this detached head state, create a new bona-fide branch, and then cherry-pick the commits you want into master. Here is how you can do this:

git commit -m 'final commit detached HEAD'  # save any remaining work
git checkout -b master_detached             # create new branch (perhaps optional)

git checkout master                         # switch to master
git cherry-pick <SHA-1 detached #1>         # cherry-pick 1st commit
git cherry-pick <SHA-1 detached #2>         # cherry-pick 2nd commit
...

The command git cherry-pick <SHA-1> tells Git to apply a single commit whose hash is SHA-1 to the current branch, which in this case would be master. In other words, using cherry-pick you can effectively graft the commits you made while in the detached HEAD state onto your master branch for safe-keeping. A cherry-pick can be thought of as a merge of one commit, and as such, you might vet merge conflicts from each cherry-pick operation.

Update:

It appears that you made a couple of bad commits on top of your master branch in addition to the four commits you made in the detached state. In this case, you can nuke those two commits from master. So right after the git checkout master step above you can try the following:

git reset --hard HEAD~2

This will roll master back from the 7921869 commit to the e416f24 commit. After this, simple continue as above by cherry-picking the detached commits.