Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><strong>Reverting Merges vs. Resetting Merges</strong></p> <p>My guess is that you actually <em>are</em> <code>Already-up-to-date</code>. </p> <p>The problem is that <a href="https://www.kernel.org/pub/software/scm/git/docs/git-revert.html" rel="noreferrer">git revert</a> doesn't undo the merge, it only undoes the changes that the merge brought with it. When you create a merge commit, your combining the commit histories of those two branches.</p> <p><strong>Merging</strong></p> <pre><code> develop | A---B---C \ \ E---F---M | newfeature </code></pre> <p>In the case above, <code>develop</code> is merged into <code>newfeature</code>, creating the <code>M</code> commit. If you were to run <code>git log newfeature</code> you would see all the commits from both branches, however from the perspective of the <code>newfeature</code> branch, all those changes were performed by the <code>M</code> commit.</p> <p><strong>Reverting</strong></p> <p>The <code>git revert</code> command does not remove any commits, instead it creates a new commit that undoes the changes that the commit contained. For example if you had a commit containing this diff...</p> <pre><code>-This is the old sentence. +This is ne new sentence. </code></pre> <p>Then reverted this, the revert command would create a new commit that just preformed the opposite diff, it simply flips the signs.</p> <pre><code>-This is ne new sentence. +This is the old sentence. </code></pre> <p>This is really useful for undoing damage caused by commits that other developers already have. It moves history forward rather than changing history. </p> <p><strong>Reverting Merges</strong></p> <p>However, in the context of a non-fastforward merge it may have an undesired effect.</p> <pre><code> develop | A---B---C \ \ E---F---M---W | newfeature </code></pre> <p>Assuming W is a reversion commit, you can see how running <code>git log newfeature</code> will still include all the commits from the develop branch. As a result, additional merges from <code>develop</code> will no work, because it doesn't see anything missing from your branch.</p> <p><strong>Using <a href="https://www.kernel.org/pub/software/scm/git/docs/git-reset.html" rel="noreferrer">git reset</a> instead of revert.</strong></p> <p>In the future, you might want to consider using <code>git reset --hard &lt;ref&gt;</code> (where <code>&lt;ref&gt;</code> is the commit hash of the merge) to undo a merge if that merge has not been shared with other developers. In the example above, after having created merge commit <code>M</code>, running the command <code>git reset --hard F</code> would result in the following.</p> <pre><code> develop | A---B---C \ \ E---F---M | newfeature </code></pre> <p>As you can see this technique doesn't obliterate the commit as some people tend to think, it simply moves your branch back to the commit you selected. Now if you ran <code>git log newfeature</code> you would only get commit <code>F</code>, <code>E</code>, and <code>A</code>. Now the merge is actually gone from your branches history, so a later attempts to re-merge in <code>develop</code> will cause no problems.</p> <p>This method is not without its complications. Realize that you are now modifying history, so if the <code>newfeature</code> branch was pushed to a remote branch after the <code>M</code> merge was made, then git is going to think you are simply out of date and tell you that you need to run <code>git pull</code>. If its just you working on that remote branch, then feel free to <code>force-push</code> - <code>git push -f &lt;remote&gt; &lt;branch&gt;</code>. This will have the same effect of the reset but on the remote branch.</p> <p>If this branch is being used by multiple developers, who would have by now already pulled from it - then this is a bad idea. This is the very reason <code>git revert</code> is useful, because it undoes changes without changing the actual history.</p> <p>Using reset on history is really only on option for commits that have not been shared. </p> <p><strong>The solution - reverting the reversion.</strong></p> <p>If the merge commit has already been shared, then the best approach is probably to use <code>git revert</code> on that merge. However as we said before, you can not then simply merge the branch back in and expect all the changes from that branch to re-appear. The answer is to revert the revert commit. </p> <p>Lets say you did some work on the <code>develop</code> branch after having revered the merge in <code>newfeature</code>. Your history would look something like this.</p> <pre><code> develop | A---B---C---D \ \ E---F---M---W | newfeature </code></pre> <p>If you merge <code>develop</code> into <code>newfeature</code> now, you would only get <code>D</code> because its the only commit that is not already part of the history of the <code>newfeature</code> branch. What you also need to do is revert that <code>W</code> commit - <code>git revert W</code> should do the trick followed by <code>git merge develop</code>. </p> <pre><code> develop | A---B---C-----------D \ \ \ E---F---M---W---M---G | newfeature </code></pre> <p>This restores all the changes made by the original merge commit - which were actually made by <code>C</code> and <code>B</code> but were reverted in <code>W</code>, it then brings in <code>D</code> via a new merge commit <code>G</code> I would recommend reverting the revert <em>before</em> merging in the recent changes to <code>develop</code>, I suspect doing it in that order will have a lower chance of triggering conflicts.</p> <p><strong>TL;DR</strong></p> <p>Reverting creates a 'revert commit'. When undoing a revert, you need to run the revert command on the revert commit that was created when you reverted the first time. It should be easy enough to find, git tends to auto-comment on reverts so that they start with the word "Reverted".</p> <p><code>git revert &lt;commit&gt;</code></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload