Ben Packard
Ben Packard

Reputation: 26476

Git revert in master reverting commits when merged into feature branch

I have been developing a major, long-term feature on a separate branch, big-feature. During its development, I have also been making smaller unrelated updates on master (well, technically I have been making the smaller updates on their own branches from master and then merging them into master.)

Each time I complete some changes to master, I have been in the habit of also merging master into big-feature so that the feature branch doesn't stray too far from master and the merge will be hopefully easier when the big feature is complete.

However, after some recent work, I accidentally merged big-feature into master. I attempted to rectify this with revert, and indeed the previous code state seems to have been restored. However, I still see the full history of commits from big-feature listed in the commit history of master, plus a merge and revert at the top.

The problem is, when I now make a small change on master and attempt to merge master into big-feature, all of big-feature's code reverts to that of master. I can only guess that the revert from master is being merged into big-feature and removing all the commits in big-feature.

Hopefully this is semi-coherent.

Questions:

  1. Is my diagnosis correct?
  2. Is my strategy of periodically merging master into big-feature a bad idea?
  3. The main question: how do I fix this?

P.S. I also tried a hard reset of master to the commit before the erroneous merge, but this didn't remove all of the commits from big-feature, which surprised me?

Upvotes: 1

Views: 2546

Answers (3)

nvinogr
nvinogr

Reputation: 47

NOTE: This answer is only applicable if you are able to overwrite history. You should only do it if you haven't pushed you changes to remote or if you know for a FACT that this won't affect other developers (e.g. there are none or you can communicate to everyone working on the project what you are about to do)


how do I fix this?

I'm assuming that what happened when you merged big-feature to master was a fast-forward merge.

In that case, using git reset to reset to some specific commit may not work as our commits from master and big-feature may have become mixed. Instead we can use git reflog to find the state master was in before we've made the merge and then reset master to that state.

git reflog master # Show the history of updates to the tip of master.
                  # Find the line that says "master{n}: merge big-feature: Fast-forward"
                  # and note the reference number n

git switch master # checkout master if necessary
git reset --keep master@{n+1} # Now reset master to the reference just before merge

Is my strategy of periodically merging master into big-feature a bad idea?

If, again, you can overwrite history I would recommend periodically rebasing your feature branch on master instead. This gives you an advantage of having a clean history on your feature branch, which makes interacting with the branch easier, including in cases like this.

Upvotes: 1

matt
matt

Reputation: 535118

I accidentally merged big-feature into master. I attempted to rectify this with revert

That's not how to undo a merge.

A revert is a whole new commit, which is artificially created in such a way as to add to the future history the negation of some commit that came before it.

The way to undo the merge is to be on the branch you were on when you did the merge and simply reset --hard back one commit, namely to the commit just before the merge commit. It has no name so you have to use HEAD~1 notation or use the SHA of that commit. The merge commit is thrown away, and presto, we are right back where we were before the merge.

(You say you tried that, but you don't give the actual command that you gave, so there is no reason to think you gave the command correctly.)

In this example, I have created commits A, B, and C on master and commit Z on feature, and I have merged feature into master — you can tell that because (1) I am on master, and (2) the merge commit is part of master, not part of feature:

*   a65559d (HEAD -> master) merge commit
|\  
| * c6c9d90 (feature) Z
* | caa732e C
* | 11bbc44 B
|/  
* 92e934a A

Note the SHA numbers. Let's say we regret this move. So our goal is to delete a65559d in such a way as to put master back at caa732e, where it was before we merged feature. We are currently on master, so all we have to do is say:

git reset --hard caa732e

Result:

* c6c9d90 (feature) Z
| * caa732e (HEAD -> master) C
| * 11bbc44 B
|/  
* 92e934a A

Exactly what we wanted.

Upvotes: 4

Tim Biegeleisen
Tim Biegeleisen

Reputation: 521178

I suspect that the problem here is that when you now merge master into big-feature, Git is pulling along that merge revert commit, which is then functionally undoing a bunch of your work which happened in big-feature. While there might be a more graceful way to handle this, an easy solution would be to just cherry pick the commits from master which you want to also include in big-feature:

# from big-feature
git cherry-pick ABCD

The above assumes that ABCD is the SHA-1 hash of the commit in master which has the minor fix which you want to bring into big-feature.

Using this approach is more work, because you need to figure out exactly which commit(s) need to come in, but it avoids the merge brute force approach which is no longer working for you.

Upvotes: 0

Related Questions