AndroidDev
AndroidDev

Reputation: 21237

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://[email protected]/xxx/xxx.git ! [rejected] HEAD -> master (non-fast-forward)
error: failed to push some refs to 'https://[email protected]/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://[email protected]/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://[email protected]/xxx/xxx.git
! [rejected] master -> master (non-fast-forward)
error: failed to push some refs to 'https://[email protected]/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?

Upvotes: 3

Views: 1059

Answers (1)

Tim Biegeleisen
Tim Biegeleisen

Reputation: 521249

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.

Since you rewrote the history of the master branch, you will now have to push it to the remote via:

git push --force origin master

Keep in mind that this may not be desirable if master is shared by many people.

Upvotes: 3

Related Questions