Trying to Understand Revert And Merges in Git
Disclaimer: I'm not an expert in Git. This post is me trying to understand how it works, by trying to explain it to someone else. If I've said something wrong in this post, please don't hesitate to correct me by leaving a comment below or getting in touch with me.
So, in the past, I got confused by how a
git revert command affected the merges. Part of it is due to my TFS background. But anyway, as it turns out, it works exactly how it is supposed to work, once you have a better understanding of how Git works.
git revert rolls back a specific commit made in the repo. In addition to that, it adds a new commit to indicate that the previous commit was rolled back.
To better explain how this affects merges, I'll try to go over a scenario where I merge branches, then revert a commit in one branch, then try to merge the branches again. So here goes.
Imagine that I have two branches,
develop branch was created based off the
master branch, so they should have the same code in them.
Let's say that in the
develop branch, there were new commits added. Let's call them Commit 1A, Commit 1B and Commit 1C.
Then I decided to merge
After the merge, both branches are in sync again. If you look at the history of commits into both branches, at the top of the list would be Commit 1C, then Commit 1B then Commit 1A.
Depending on how you do your merges, the
master branch would normally have an extra commit showing the merge from the
develop branch. Let's call that Commit 2A. But after that commit though, you would still see Commit 1C, then Commit 1B then Commit 1A, just like in the
Anyway the point is, at this moment in time, both branches have the same set of changes/commits. Everything that is in the
develop branch, is also in the
Table below shows the history of commits for both branches.
But then I decided to revert a change in the
master branch because it broke something. Let's say I reverted Commit 1B in the
master branch. Since a
git revert command creates a new commit, it will show up in the history for the
master branch too. Let's call this Commit 2B.
Around the same time, I also pushed new code to the
develop branch. Let's say that was Commit 1D.
The updated table below shows the commits for both branches at this point in time.
And so what happens now when I merge the
develop branch into the
Previously, I expected that if I merged
master at this point in time:
- I would get Commit 1D added to the
- I would get Commit 1B added back to the
But that is not how Git works. At least not for the 2nd expectation. That may be the case with a merge in TFS, but not in Git. And that's because of the effect of the
git revert command and how Git compares differences between branches during a merge.
git revert command creates a new commit to track the rolling back of a previous commit. In this case, it created Commit 2B. When you merge
develop into the
master branch at this point, Git will look at the commit history in the
develop branch and will say, “Hey, the master branch has all of the same commits except Commit 1D, so I'll only add Commit 1D into the master branch.”
So what about Commit 1B that was reverted in the
master branch, but is still in the
develop branch? Why was that not merged?
Since merges are directional (source branch to target branch), Git sees that Commit 1B in the
develop branch (source branch) is already in the history of commits for the
master branch (target branch). So as far as a merge goes, Commit 1B is already in the
master branch and so there is no need to add it during a merge.
Now if you were to reverse the direction of the merge, if you were to merge the
master branch into the
develop branch, Git will now see that Commit 1B was reverted in the
master branch (source branch) via Commit 2B. And so Git will then revert Commit 1B in the
develop branch (target branch) by copying the changes from Commit 2B as part of the merge.
So, there you go. I hope this post can help someone else who had trouble understanding how reverts and merges work in Git.
Discuss... or leave a comment below.