How to revert merge git
How to revert merge git
How to revert a faulty merge
and asked for help recovering from this situation.
The history immediately after the «revert of the merge» would look like this:
Such a «revert» of a merge can be made with:
After the developers of the side branch fix their mistakes, the history may look like this:
where C and D are to fix what was broken in A and B, and you may already have some other changes on the mainline after W.
If you merge the updated side branch (with D at its tip), none of the changes made in A or B will be in the result, because they were reverted by W. That is what Alan saw.
Linus explains the situation:
In such a situation, you would want to first revert the previous revert, which would make the history look like this:
where Y is the revert of W. Such a «revert of the revert» can be done with:
This history would (ignoring possible conflicts between what W and W..Y changed) be equivalent to not having W or Y at all in the history:
and merging the side branch again will not have conflict arising from an earlier revert and revert of the revert.
Of course the changes made in C and D still can conflict with what was done by any of the x, but that is just a normal merge conflict.
On the other hand, if the developers of the side branch discarded their faulty A and B, and redone the changes on top of the updated mainline after the revert, the history would have looked like this:
If you reverted the revert in such a case as in the previous example:
In the history with rebased side branch, W (and M) are behind the merge base of the updated branch and the tip of the mainline, and they should merge without the past faulty merge and its revert getting in the way.
To recap, these are two very different scenarios, and they want two very different resolution strategies:
If the faulty side branch was fixed by adding corrections on top, then doing a revert of the previous revert would be the right thing to do.
If the faulty side branch whose effects were discarded by an earlier revert of a merge was rebuilt from scratch (i.e. rebasing and fixing, as you seem to have interpreted), then re-merging the result without doing anything else fancy would be the right thing to do. (See the ADDENDUM below for how to rebuild a branch from scratch without changing its original branching-off point.)
However, there are things to keep in mind when reverting a merge (and reverting such a revert).
When you have a problem you are chasing down, and you hit a «revert this merge», what you’re hitting is essentially a single commit that contains all the changes (but obviously in reverse) of all the commits that got merged. So it’s debugging hell, because now you don’t have lots of small changes that you can try to pinpoint which part of it changes.
But does it all work? Sure it does. You can revert a merge, and from a purely technical angle, Git did it very naturally and had no real troubles. It just considered it a change from «state before merge» to «state after merge», and that was it. Nothing complicated, nothing odd, nothing really dangerous. Git will do it without even thinking about it.
So from a technical angle, there’s nothing wrong with reverting a merge, but from a workflow angle it’s something that you generally should try to avoid.
If at all possible, for example, if you find a problem that got merged into the main tree, rather than revert the merge, try really hard to bisect the problem down into the branch you merged, and just fix it, or try to revert the individual commit that caused it.
Yes, it’s more complex, and no, it’s not always going to work (sometimes the answer is: «oops, I really shouldn’t have merged it, because it wasn’t ready yet, and I really need to undo all of the merge»). So then you really should revert the merge, but when you want to re-do the merge, you now need to do it by reverting the revert.
Sometimes you have to rewrite one of a topic branch’s commits and you can’t change the topic’s branching-off point. Consider the following situation:
where commit W reverted commit M because it turned out that commit B was wrong and needs to be rewritten, but you need the rewritten topic to still branch from commit P (perhaps P is a branching-off point for yet another branch, and you want be able to merge the topic into both branches).
To merge A-B’-C’ into the mainline branch you would still have to first revert commit W in order to pick up the changes in A, but then it’s likely that the changes in B’ will conflict with the original B changes re-introduced by the reversion of W.
However, you can avoid these problems if you recreate the entire branch, including commit A:
You can merge A’-B’-C’ into the mainline branch without worrying about first reverting W. Mainline’s history would look like this:
Git undo merge [a Git commands tutorial]
Why undo merge
Occasionally, you can get into a situation where you make a merge, commit it, and maybe even push it to your remote server before realizing there’s an issue with it. When this happens, you’ll need a way to get your main branch back to its previous state.
However, if you’ve already finished your merge, there’s no such option. Instead, here’s what you’ll need to do: first, make sure you check out the main branch that you merged your changes into. You’ll want the next steps to affect this branch.
Next, find the commit hash of the merge with git log:
That will generate a list of commits that looks something like this:
The commit hash is the seven character string in the beginning of each line. In this case, `52bc98d` is our merge’s hash. Once you have that, you can pass it to the git revert command to undo the merge:
And Bob’s your uncle! The git revert command will have generated a commit that restores your branch’s state to where it was before the faulty merge. If your merge was remote (i.e. happened on GitHub) you can push this commit like any other and you’ll be set to go.
How does reverting a merge work?
As it does with regular commits, Git creates merge commits with a commit hash representing the point in history where the other branch was merged in. We can use this information to run the git revert command to restore your branch to the state that it was in previously.
git revert generates a series of changes that, when applied, produce the exact inverse of whatever commit you give to it, then creates a new commit with those changes. This means that both the original commit and the new inverse commit will both be stored in history, preserving all of the data about what happened but leaving your branch in the state it was before you made the first commit.
Due to the way merges work, you have to do a little extra work, though. Normally, you can feed git revert the hash of the commit you want to undo, and Git will then look at that commit’s pointer to its parent commit to determine which changes to revert.
Reapplying a reverted merge
A common workflow need after you revert a faulty merge is to continue working on the branch and re-merge it later.
Unfortunately, you can’t directly do that. If you try, you’ll find that the commits from the first merge of the branch that you already reverted won’t be reapplied after the second merge. The commits in the branch that was merged are permanently reverted, so if you attempt to re-merge a reverted branch without rebuilding those commits, those changes won’t be applied the second time.
Linus Torvalds, the creator of Git, explains why this happens (emphasis mine):
«A `revert` undoes the data changes, but it’s very much _not_ an `undo` in the sense that it doesn’t undo the effects of a commit on the repository history. So if you think of `revert` as `undo`, then you’re going to always miss this part of reverts. Yes, it undoes the data, but no, it doesn’t undo history.»
You can read the full documentation on handling faulty merges here. It gets much more in-depth than this article does, but here’s the tl;dr on what you actually need to do from lower down the page:
«If the faulty side branch was fixed by adding corrections on top, then doing a revert of the previous revert would be the right thing to do.»
«If the faulty side branch whose effects were discarded by an earlier revert of a merge was rebuilt from scratch (i.e. rebasing and fixing, as you seem to have interpreted), then re-merging the result without doing anything else fancy would be the right thing to do.»
Taking preventative measures to avoid merge reversions
Reverting merges is a messy business. It’s time-consuming, confusing, and results in a less clear Git history. As your codebase grows, you may want to take preventative measures to avoid having to revert merges unnecessarily.
For example, you may want to improve or set up your code review process. You can also define code owners to make sure the appropriate eyes are on your pull requests before they get merged.
Finally, a tool like Datree can also be extremely useful to establish guidelines across multiple repositories as your organization grows.
Learn from Nana, AWS Hero & CNCF Ambassador, how to enforce K8s best practices with Datree
рџЌї Techworld with Nana: How to enforce Kubernetes best practices and prevent misconfigurations from reaching production. Watch now.
Headingajsdajk jkahskjafhkasj khfsakjhf
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.
Git FAQ
Frequently asked questions around Git and Version Control.
How to Undo a Merge in Git
Merging is the process of integrating another branch into your current HEAD branch. (Feel free to check out our git merge Command Overview if you want to learn more about merge in general.)
In this short article, we’ll discuss how to undo a merge in Git!
The Git Cheat Sheet
Using git reset to Undo a Merge
One of the best aspects about Git is that you can undo virtually anything. And, luckily, a merge is no exception! You can use the git reset command to return to the revision before the merge, thereby effectively undoing it:
If you don’t have the hash of the commit before the merge at hand, you can also use the following variation of the command:
This way, using «HEAD
1″, you’re telling Git to go back to the commit before the current HEAD revision — which should be the commit before the merge!
Please note that, in both cases, we need to use the «—hard» option. This means that any local changes in your Working Copy will be discarded; if you have valuable uncommitted changes, be sure to use git stash before.
Undoing a Merge in Tower
In case you are using the Tower Git client, undoing a merge is really simple: just press CMD+Z afterwards and Tower will undo the merge for you!
How to Undo a Pushed Merge
The example from above is useful when you have NOT already pushed the merge to a remote repository. In such a case, when you’ve already shared the merge commit with your colleagues on a remote, you should consider a different solution.
Let’s take a closer look at what this command will do:
Learn More
Get our popular Git Cheat Sheet for free!
You’ll find the most important commands on the front and helpful best practice tips on the back. Over 100,000 developers have downloaded it to make Git a little bit easier.
About Us
As the makers of Tower, the best Git client for Mac and Windows, we help over 100,000 users in companies like Apple, Google, Amazon, Twitter, and Ebay get the most out of Git.
Just like with Tower, our mission with this platform is to help people become better professionals.
That’s why we provide our guides, videos, and cheat sheets (about version control with Git and lots of other topics) for free.
Reverting a merge commit
Move back to an older commit in Git using revert
REVERTING A COMMIT
The revert command in git takes in a commit id and compares the changes with the parent. The delta or the diff is calculated and the negation of it applied as a new commit. In case the commit-sha is not specified, it is defaulted to the commit-sha of the HEAD commit.
This command creates a commit fbb1df5 on top of the HEAD negating the changes made by 9735432. The new HEAD will then point to the fbb1df5. The resultant tree will behave as if the commit 9735432 does not exist.
THE MERGE COMMIT
Unlike other commits, the merge commit is a commit which has multiple (generally two) parents.
For instance, when a branch named feature is merged with master, a new commit is created on the branch master which has two parents, the previous head of master and the head of feature.
On merging the feature to master.
These commands create a new merge commit 1c32600.
The merge commit 1c32600 has two parent commits
On running git show, the new commits display both the parents
REVERTING THE MERGE COMMIT
The parent number is assigned from left. To revert the changes brought in by the feature branch, revert the commit with respect to the second parent ( 1484b1a).
This will revert all the changes made by the second branch ( feature) on master. The resulting tree will behave as the branch feature was never merged to master.
Similarly, to revert the changes from the commits in the first parent of the merge commit run
This will revert all the commits that were made on the master after the feature branch was created leaving only the commits in the feature branch in the master.
In the above example, 9745432 and b15b045 would be removed from the master branch leaving only the commits 1484b1a and 79fe70a and the older commits which are in feature.
Also, the master branch may be merged to feature branch.
$ git checkout feature
$ git merge master
The changes in the commit in the 9745432 and b15b045 in the master branch will get included in the feature branch. This time for the merge commit the first parent is the original branch which is the commit 1484b1a itself whereas the commit in the master branch 9745432 is the second parent.
CAUTION
If the merge of master to the feature branch was unintentional. The correct way to undo it is to reset the branch. This can be done by running the following in the feature branch.
On the other hand, reverting a merge commit negates all the changes made by the branch of the specified parent.
Now the master branch pointing to the commit a75ebc will not have the changes done in the commits 9745432 and b15b045.
Thanks for reading. Hope this was helpful. Please leave your comments if you have any questions or you feel something more needs to be added.
Git Revert Merge git revert, merge commits, confusion
I ran into a gap in my understanding of git and merge commits yesterday. Most of the time, the projects I contribute to work with a «mergeless» commit history, so we usually rebase+squash our changes into a single commit and apply those to master leaving us with a commit history that looks like:
Exit fullscreen mode
Generally, if I need to revert commit 3, all I need to do is git revert 3 and that commit gets reverted and committed as commit 6:
Exit fullscreen mode
Yesterday, I needed to revert a change in a project that works with multiple remote branches that are merged to master via a merge commit:
Exit fullscreen mode
So, I tried git revert 5a and got a message I’d never seen before:
Usually you cannot revert a merge because you do not know which side of the merge should be considered the mainline. This option specifies the parent number (starting from 1) of the mainline and allows revert to reverse the change relative to the specified parent.
Reverting a merge commit declares that you will never want the tree changes brought in by the merge. As a result, later merges will only bring in tree changes introduced by commits that are not ancestors of the previously reverted merge. This may or may not be what you want.
Also, what is that bit about «you will never want the tree changes brought in by the merge»? Does that mean these changes that I’m reverting will never be applied if I try to re-merge them later from the same branch? So, if I add a new commit to my feature branch, and then try to merge that branch back into master, will I only get the new changes and not the changes I reverted? If so, how do I get the changes I reverted back?
I haven’t had a chance to sort all this out fully or test my assumptions as after about an hour of futzing around with this I figured it would be easier to just find the problem and fix it instead of trying to revert the change that caused it.
This definitely makes me feel like a «mergeless» git history is easier to work with since it’s simpler and each commit is a discreet unit which can be easily backed out, but I know some people prefer the merge commit workflow so I’ll have to spend some more time playing with that to figure it out.