about summary refs log tree commit diff
path: root/third_party/git/Documentation/howto/revert-a-faulty-merge.txt
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/git/Documentation/howto/revert-a-faulty-merge.txt')
-rw-r--r--third_party/git/Documentation/howto/revert-a-faulty-merge.txt273
1 files changed, 0 insertions, 273 deletions
diff --git a/third_party/git/Documentation/howto/revert-a-faulty-merge.txt b/third_party/git/Documentation/howto/revert-a-faulty-merge.txt
deleted file mode 100644
index 19f59cc88808..000000000000
--- a/third_party/git/Documentation/howto/revert-a-faulty-merge.txt
+++ /dev/null
@@ -1,273 +0,0 @@
-Date: Fri, 19 Dec 2008 00:45:19 -0800
-From: Linus Torvalds <torvalds@linux-foundation.org>, Junio C Hamano <gitster@pobox.com>
-Subject: Re: Odd merge behaviour involving reverts
-Abstract: Sometimes a branch that was already merged to the mainline
- is later found to be faulty.  Linus and Junio give guidance on
- recovering from such a premature merge and continuing development
- after the offending branch is fixed.
-Message-ID: <7vocz8a6zk.fsf@gitster.siamese.dyndns.org>
-References: <alpine.LFD.2.00.0812181949450.14014@localhost.localdomain>
-Content-type: text/asciidoc
-
-How to revert a faulty merge
-============================
-
-Alan <alan@clueserver.org> said:
-
-    I have a master branch.  We have a branch off of that that some
-    developers are doing work on.  They claim it is ready. We merge it
-    into the master branch.  It breaks something so we revert the merge.
-    They make changes to the code.  they get it to a point where they say
-    it is ok and we merge again.
-
-    When examined, we find that code changes made before the revert are
-    not in the master branch, but code changes after are in the master
-    branch.
-
-and asked for help recovering from this situation.
-
-The history immediately after the "revert of the merge" would look like
-this:
-
- ---o---o---o---M---x---x---W
-               /
-       ---A---B
-
-where A and B are on the side development that was not so good, M is the
-merge that brings these premature changes into the mainline, x are changes
-unrelated to what the side branch did and already made on the mainline,
-and W is the "revert of the merge M" (doesn't W look M upside down?).
-IOW, `"diff W^..W"` is similar to `"diff -R M^..M"`.
-
-Such a "revert" of a merge can be made with:
-
-    $ git revert -m 1 M
-
-After the developers of the side branch fix their mistakes, the history
-may look like this:
-
- ---o---o---o---M---x---x---W---x
-               /
-       ---A---B-------------------C---D
-
-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:
-
-    Reverting a regular commit just effectively undoes what that commit
-    did, and is fairly straightforward. But reverting a merge commit also
-    undoes the _data_ that the commit changed, but it does absolutely
-    nothing to the effects on _history_ that the merge had.
-
-    So the merge will still exist, and it will still be seen as joining
-    the two branches together, and future merges will see that merge as
-    the last shared state - and the revert that reverted the merge brought
-    in will not affect that at all.
-
-    So 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.
-
-In such a situation, you would want to first revert the previous revert,
-which would make the history look like this:
-
- ---o---o---o---M---x---x---W---x---Y
-               /
-       ---A---B-------------------C---D
-
-where Y is the revert of W.  Such a "revert of the revert" can be done
-with:
-
-    $ git revert W
-
-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:
-
- ---o---o---o---M---x---x-------x----
-               /
-       ---A---B-------------------C---D
-
-and merging the side branch again will not have conflict arising from an
-earlier revert and revert of the revert.
-
- ---o---o---o---M---x---x-------x-------*
-               /                       /
-       ---A---B-------------------C---D
-
-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:
-
- ---o---o---o---M---x---x---W---x---x
-               /                 \
-       ---A---B                   A'--B'--C'
-
-If you reverted the revert in such a case as in the previous example:
-
- ---o---o---o---M---x---x---W---x---x---Y---*
-               /                 \         /
-       ---A---B                   A'--B'--C'
-
-where Y is the revert of W, A' and B' are rerolled A and B, and there may
-also be a further fix-up C' on the side branch.  `"diff Y^..Y"` is similar
-to `"diff -R W^..W"` (which in turn means it is similar to `"diff M^..M"`),
-and `"diff A'^..C'"` by definition would be similar but different from that,
-because it is a rerolled series of the earlier change.  There will be a
-lot of overlapping changes that result in conflicts.  So do not do "revert
-of revert" blindly without thinking..
-
- ---o---o---o---M---x---x---W---x---x
-               /                 \
-       ---A---B                   A'--B'--C'
-
-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).
-
-For example, think about what reverting a merge (and then reverting the
-revert) does to bisectability. Ignore the fact that the revert of a revert
-is undoing it - just think of it as a "single commit that does a lot".
-Because that is what it does.
-
-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.
-
-ADDENDUM
-
-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:
-
- P---o---o---M---x---x---W---x
-  \         /
-   A---B---C
-
-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).
-
-The natural thing to do in this case is to checkout the A-B-C branch and use
-"rebase -i P" to change commit B.  However this does not rewrite commit A,
-because "rebase -i" by default fast-forwards over any initial commits selected
-with the "pick" command.  So you end up with this:
-
- P---o---o---M---x---x---W---x
-  \         /
-   A---B---C   <-- old branch
-    \
-     B'---C'   <-- naively rewritten branch
-
-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:
-
-   A'---B'---C'  <-- completely rewritten branch
-  /
- P---o---o---M---x---x---W---x
-  \         /
-   A---B---C
-
-You can merge A'-B'-C' into the mainline branch without worrying about first
-reverting W.  Mainline's history would look like this:
-
-   A'---B'---C'------------------
-  /                              \
- P---o---o---M---x---x---W---x---M2
-  \         /
-   A---B---C
-
-But if you don't actually need to change commit A, then you need some way to
-recreate it as a new commit with the same changes in it.  The rebase command's
---no-ff option provides a way to do this:
-
-    $ git rebase [-i] --no-ff P
-
-The --no-ff option creates a new branch A'-B'-C' with all-new commits (all the
-SHA IDs will be different) even if in the interactive case you only actually
-modify commit B.  You can then merge this new branch directly into the mainline
-branch and be sure you'll get all of the branch's changes.
-
-You can also use --no-ff in cases where you just add extra commits to the topic
-to fix it up.  Let's revisit the situation discussed at the start of this howto:
-
- P---o---o---M---x---x---W---x
-  \         /
-   A---B---C----------------D---E   <-- fixed-up topic branch
-
-At this point, you can use --no-ff to recreate the topic branch:
-
-    $ git checkout E
-    $ git rebase --no-ff P
-
-yielding
-
-   A'---B'---C'------------D'---E'  <-- recreated topic branch
-  /
- P---o---o---M---x---x---W---x
-  \         /
-   A---B---C----------------D---E
-
-You can merge the recreated branch into the mainline without reverting commit W,
-and mainline's history will look like this:
-
-   A'---B'---C'------------D'---E'
-  /                              \
- P---o---o---M---x---x---W---x---M2
-  \         /
-   A---B---C