Question

I'm working on a git repository that has a branch off of master, we'll call it the ab branch. My team is working on the ab branch and has a pull-request workflow using github. One of my teammates made a pull request from his branch jeremy_ab_deletions to the ab branch. I was reviewing/testing his changes, but when I went to merge them into the ab branch I accidentally merged them into master instead and pushed master to github before I caught my mistake. Thinking I could just git-revert the change I did git revert SHA and it seemed to work...

I thought that had been enough and I happily switched back to my ab branch and continued working. Now, however, I realize that the previous commits from the ab branch which should never end up in master, are all in master. It's...quite the mess. Since his branch was originally split off from ab, and then I merged it into master, I should have reverted it using git revert -m 1 SHA.

Today I was trying to figure out where exactly I went wrong and I'm all kinds of confused based on the git history, and my reflog. First, I tried reverting the reverts, and then doing git revert -m 1 SHA But git tells me:

fatal: Mainline was specified but commit 4c431c345dfe0a856967c090932c32f153824085 is not a merge.

So I think ok...maybe that wasn't the merge commit and I need to target a different SHA. But looking at the history I can't for the life of me figure out which one of these was the merge commit...

This was supposed to be on AB... 
…
d985b5bcf8 Browse code
Nathan B authored 8 days ago

This was supposed to be on AB... 
…
0e01911273 Browse code
Nathan B authored 8 days ago

removed unecessary tests
4c431c345d Browse code
Nathan B authored 8 days ago
Apr 17, 2012

removing un-used views and pages
a546f90ed3 Browse code
jeremychurch authored 10 days ago

The two commits that say "this was supposed to be on AB" are the revert commits to revert the 'removed unecessary tests' and 'removing un-used views and pages' commits. The next commit to master was today, and the commit before that was on the 16th, neither of which were related. I don't see where the actual merge occurred.

I went through my reflog to see where exactly everything got messed up. I went went up and down the reflog versions using git reset --hard HEAD@{NUM} and then inspecting key files to see if the bad changes were in that spot yet. Finally I narrowed it down to these reflogs:

1fe2be2 HEAD@{79}: checkout: moving from 1fe2be29c6eda9f9fc9eb0b372ee83b7c15dfc2c to jeremy_ab_deletions
1fe2be2 HEAD@{80}: HEAD@{3}: updating HEAD
4c431c3 HEAD@{81}: HEAD@{1}: updating HEAD
47a97af HEAD@{82}: commit: removed unecessary tests, routes, and controller actions
4c431c3 HEAD@{83}: merge jeremy_ab_deletions: Fast-forward
1fe2be2 HEAD@{84}: checkout: moving from master to ab
d985b5b HEAD@{85}: revert: This was supposed to be on AB...
0e01911 HEAD@{86}: revert: This was supposed to be on AB...
4c431c3 HEAD@{87}: merge jeremy_ab_deletions: Fast-forward
c121a08 HEAD@{88}: checkout: moving from jeremy_ab_deletions to master
4c431c3 HEAD@{89}: commit: removed unecessary tests
a546f90 HEAD@{90}: checkout: moving from ab_page_changes to jeremy_ab_deletions
511b340 HEAD@{91}: checkout: moving from jeremy_ab_deletions to ab_page_changes
a546f90 HEAD@{92}: pull git@github.com:REDACTED/repo.git ab-remove-stuff: Fast-forward

Specifically HEAD@{88} here doesn't have the bad commits, and HEAD@{87} does. Therefore it's reasonable to assume I screwed up at the merge jeremy_ab_deletions: Fast-forward commit...... but I cannot figure out which 'merge commit' that would be. I tried this:

$ git revert -m 1 4c431c3
fatal: Mainline was specified but commit 4c431c345dfe0a856967c090932c32f153824085 is not a merge.

I...can't find an actual merge commit it seems? Does anyone have any idea what I did wrong :/ I'm all kinds of lost right now.

Was it helpful?

Solution

If nobody else has pulled this master (or pulled but for certain hasn't used it), this is what I would do:

  1. If no work was done on master since the 'accident', I would just reset it to the last good commit, and then update the remote master branch (by pushing with -f).
  2. If some work has been done, you can reset it to the last good commit, then use git rebase -i and delete the problematic commits, leaving the good ones in the list. Then again you'll need to push (with -f).

Alternatively, you can do all this in a new branch:

  1. Checkout the last good commit in master, create a branch there,
  2. Then use git rebase -i master to filter out the bad commits.
  3. Then you can go back to master and "merge" manually, bringing in all the changes from the new branch, and overwriting everything in master (you can use --no-commit and git checkout --theirs)
  4. push (without -f) the fixed master.

Hope this helps! I hate mergencies.

OTHER TIPS

UPDATE: While this may help someone else, this actually made things more frustrating for me. I'll keep this here in case someone else stumbles upon it.

sinelaw pointed me in the right direction...but I found a more appropriate answer here: Revert to a commit by a SHA hash in Git?

The answer's message reads:

If you want to commit on top of the current HEAD with the exact state at a different commit, undoing all the intermediate commits, then you can use reset to create the correct state of the index to make the commit.

This is exactly what I wanted. I want to revert to HEAD@{88} but make that revert it's own commit since some people have already pulled the master branch and I don't want to have to get them to go through reset steps like I had to... So these are the commands I used:

# reset the index to the desired tree
git reset HEAD@{88}

# move the branch pointer back to the previous HEAD
git reset --soft HEAD@{1}

git commit -m "Revert the bad ab merge"

# Update working copy to reflect the new commit
git reset --hard

# Clean untracked files
git clean -f -d

Looking at the history I can see that I just created a commit with an exact reversal of all of the changes that should have been exclusive to the ab branch.

(update): Nevermind, this isn't quite what I wanted. Our repo has several branches off of it, as well as the 'master' branch. The master is intended to hold changes that are universal among the other 3 branches, and it is frequently merged into those branches. Doing this revert-with-a-commit series of commands made the merging of master into the 'ab' branch (or any of the branches for that matter) a serious nightmare of merge conflicts and unintended deleted files (Since they should live in ab, just not in master). I went with sinelaw's solution above and worked with the one non-techy designer that had pulled master to revert to the good version as well.

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