16

I decided to go back a few commits because the path I followed was wrong. So I checked out Added cordova to .gitignore commit, and made some modifications. Like illustrated below :

enter image description here

Now when I push the new modifications, an error message shows up :
error: src refspec (detached from aad6423) does not match any.

How can I tell git to discard the previous commits (in purple) and continue with my local HEAD as master ?

Mehdiway
  • 8,380
  • 7
  • 29
  • 66
  • 1
    If you are working with other people, the proper way of handling this would probably be to revert your changes on top of `master`. see http://stackoverflow.com/a/1470452/671543 – njzk2 Nov 12 '14 at 16:47
  • possible duplicate of [Git: move branch pointer to different commit](http://stackoverflow.com/questions/5471174/git-move-branch-pointer-to-different-commit) – Andrew C Nov 12 '14 at 16:50
  • 1
    Yet another simple task made difficult by Git. The Git devs should use Stack Overflow as feedback in their SDLC loop. They need to hire a UX expert because they clearly cannot git it right on their own. – jww Aug 22 '17 at 21:03

5 Answers5

21

Make HEAD your new local master:

$ git checkout -B master

Force-push your changes:

$ git push -f
Tavian Barnes
  • 11,679
  • 3
  • 41
  • 107
  • This can be dangerous if you are working with others. Be aware of that force pushing will rewrite history, causing others to need to handle the new history. – Brian J Nov 12 '14 at 16:48
  • 2
    @BrianJ Agreed, Max's answer is what you should do in 99% of cases. But this is how you do exactly what the OP asked. – Tavian Barnes Nov 12 '14 at 16:50
  • This is like magic to me. :) I use Sourcetree btw. Dangerous to others, but I had the same case with OP. I needed my HEAD to be the master. Thanks! – Glenn Posadas Dec 28 '17 at 16:37
  • This is the correct answer if you don't care about devs and history and all that other mumbo jumbo. I just want to get MY repo back on track easily ... this does it nicely. – d'Artagnan Evergreen Barbosa Apr 15 '20 at 18:08
20

Even though you don't want that old branch anymore, git really doesn't like rewriting history or discarding changes. Just revert and merge.

git branch new_master              # name current detached HEAD
git checkout master                # switch back to master
git revert --no-edit HEAD~4..HEAD  # create commits reverting back to where the history split
git merge new_master               # merge
git branch -d new_master           # don't need it anymore
Max
  • 18,333
  • 4
  • 38
  • 54
  • I think this is the correct answer, although I haven't tried it. Basically, if you've already pushed to the remote repository, you can overwrite your changes using `git push -f`, but that's somewhat anti-social, especially if other developers have already synced to your changes. At this point, you need to apply a reverse patch to `master` that gets it back to the way it was before the fork, and then apply your new `HEAD` commit to that, then push. – Edward Falk Nov 12 '14 at 16:48
  • 1
    you can rebase `topic` if you don't like diamonds (or even cherry-pick it as apparently there is only 1 commit) – njzk2 Nov 12 '14 at 16:49
  • 2
    Yet another simple task made difficult by Git. The Git devs should use Stack Overflow as feedback in their SDLC loop. They need to hire a UX expert because they clearly cannot git it right on their own. – jww Aug 22 '17 at 21:03
  • I think this is a pretty complicated task actually. You have two completely contradictory branches of code, one of which is already pushed to a remote repository (which other devs might have already pulled) and you want to reconcile them. There are several possible ways to do it, so I don't expect git to handle it automatically. – Max Aug 24 '17 at 22:22
2

So, I would do this in a couple steps:

git checkout -b new_master

to get a nice ref to what you want the new master to be.

git checkout master ; git checkout -b old_master

to keep a ref to the old master in case you want to go back or something later ; you can always delete that branch later once you're sure.

git checkout master ; git reset --hard new_master

this will reset the HEAD of the branch you're on (master) to the specified reference (new_master).

git push -f origin

this will do a force-push of your new master branch to the remote. NOTE that this is bad practice if anyone else is using your remote repo as it will potentially break their fetches/pulls.

pjz
  • 38,171
  • 5
  • 45
  • 60
1

Because you have divergence, you'll need to destroy the remote master and push up the local version. Depending on the security in place, you may not be able to do so. This has other implications as well, depending on who else is doing work based on master. It should be done with extreme caution.

git push origin :master // deletes remote master
git push origin master  // pushes local master to remote

Another (probably better) approach would be to revert the commits to master and commit the reverts (which themselves are commits). Then cherry-pick the work you've done on your local. First, create a new topic branch locally to save your work.

git checkout -b <topic_branch_name>  // create new branch to save local work
git checkout master
git reset --hard HEAD // sync local master to remote HEAD

git revert <last commit to master>
git revert <second-to-last commit to master>
...
git revert <Added cordova to .gitignore commit>
git push

git cherry-pick <commit hash from topic branch commit(s)>
isherwood
  • 46,000
  • 15
  • 100
  • 132
0

Since you pushed the changes upstream, the better approach is to revert them with another commit. A commit that will undo the changes. Removing commits or branches from upstream is bad practice. See this answer for more details.

Community
  • 1
  • 1
dan
  • 12,532
  • 3
  • 34
  • 44
  • @EdwardFalk Only the push to the new commit failed. But if branch will be changed (remove the commits that are already pushed) it will trigger conflicts for all other developers. – dan Nov 12 '14 at 16:47