Question

So I had two branches on github - master & refactor. I checked out refactor locally, and went to town. At some point, I screwed up and did a git push origin master instead of pushing to origin refactor, and furthermore, didn't notice the issue until two weeks later after committing further valid changes to master.

/me facepalms

To attempt to un-bork things, I checked out master locally, and did a git revert <some tag>, which fixed master by deleting the various files I added, and so forth. Happy ending! Pushed to origin master, all was well. Kept working on my local refactor branch, pushing to origin refactor occasionally.

Today, I'm done with the first pass of my refactor, and want to push my changes to master. I git add, git commit, git push origin refactor. All is well. Then I try to push to origin master. Fail! Not surprising, needs a manual merge due to the shenanigans, right? So I git pull origin master in my local refactor branch... and all heck breaks loose. All my new files are deleted, conflicts everywhere.

I think what's happening is that that revert push is trying to be applied, and is conflicting with my perfectly happy changes that should cleanly apply on top of master, if only.

So, as I'm still a git newb, any suggestions on how to rescue my lameness? Bonus points if you can provide some general guidance/education on how to avoid this class of error in my future workflow. Thanks!

Was it helpful?

Solution

On how to avoid this in the future: set push.default to upstream and only ever run git push without further arguments, unless you explicitly want to push to a different branch (which I personally never did). Do not push to other branches. Check out master, merge refactor, push.

You might also want to think about the parent order in merges. Your workflow causes a total mess there.

On fixing your problem: You guessed right: You are merging your revert commit in, so that is what git does. Here’s how to prevent that:

  • Create a new branch master-fix-revert of master and check it out:

    git checkout -b master-fix-revert master
    
  • Revert you revert:

    git revert **SHA-of-revert-commit**
    
  • check out your refactor branch and merge your master-fix-revert:

    git checkout refactor
    git merge master-fix-revert
    
  • delete the temp branch:

    git branch -d master-fix-revert
    

OTHER TIPS

git revert undoes changes by adding new commits which apply reverse changes of what was done in previous commits. It's useful when you want to undo changes without re-writing the history of branches which you have pushed publicly and which other may already have pulled into their own repositories.

If that's not your case, I suggest to undo changes using more intuitive techniques, such as git reset. Let's say your master branch had commits A, B, C, and you accidentally committed D and E on top of that.

                       master
 A <-- B <-- C <-- D <-- E

If D and E were your unwanted, superfluous commits, you could simply do:

Go on your local master branch:

git checkout master

Make it point to a particular commit using --hard. This is a very general-purpose command, the commit can be anything in your object base, it doesn't necessarily have to be a commit in master's history. In your case:

git reset --hard <sha1 of C>

           master           
 A <-- B <-- C

Then push to your repo using force, since you have re-written history and it is thus non-fast-forward:

git push origin master -f

Then, checkout refactor and keep working on it. If you want to pickup from where your master branch was pointing (i.e. with the extra superfluous commits), you can use git reset to set it there:

git checkout refactor
git reset --hard <sha1 of E>

           master      refactor
 A <-- B <-- C <-- D <-- E

This is optional, of course, you could decide to use another way such as branching refactor from the new master and adding the previous modifications manually, or by cherrypicking, etc.

Then just keep adding commits to refactor, then merge to master and push master:

git checkout master
git merge refactor
git push origin master

                            master  
                            refactor
 A <-- B <-- C <-- D <-- E <-- F

There, it's still a very basic workflow. My suggestion would be to use a tool like gitk:

gitk --all

as often as possible to see what's happening on your different branches.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top