Add a documentat on how to revert a faulty merge
Linus and Junio explained issues that are involved in reverting a merge and how to continue working with a branch that was updated since such a revert on the mailing list. This is to help new people who did not see these messages. Signed-off-by: Nanako Shiraishi <nanako3@lavabit.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Nanako Shiraishi committed
Dec 20, 2008 at 20:27 UTC
a128a2cdc35cdf0eff7eeb1c21b912209f133633
1 file changed
+179
Documentation/howto/revert-a-faulty-merge.txt
new
+179
@@ -0,0 +1,179 @@
1
+Date: Fri, 19 Dec 2008 00:45:19 -0800
2
+From: Linus Torvalds <torvalds@linux-foundation.org>, Junio C Hamano <gitster@pobox.com>
3
+Subject: Re: Odd merge behaviour involving reverts
4
+Abstract: Sometimes a branch that was already merged to the mainline
5
+ is later found to be faulty. Linus and Junio give guidance on
6
+ recovering from such a premature merge and continuing development
7
+ after the offending branch is fixed.
8
+Message-ID: <7vocz8a6zk.fsf@gitster.siamese.dyndns.org>
9
+References: <alpine.LFD.2.00.0812181949450.14014@localhost.localdomain>
10
+
11
+Alan <alan@clueserver.org> said:
12
+
13
+ I have a master branch. We have a branch off of that that some
14
+ developers are doing work on. They claim it is ready. We merge it
15
+ into the master branch. It breaks something so we revert the merge.
16
+ They make changes to the code. they get it to a point where they say
17
+ it is ok and we merge again.
18
+
19
+ When examined, we find that code changes made before the revert are
20
+ not in the master branch, but code changes after are in the master
21
+ branch.
22
+
23
+and asked for help recovering from this situation.
24
+
25
+The history immediately after the "revert of the merge" would look like
26
+this:
27
+
28
+ ---o---o---o---M---x---x---W
29
+ /
30
+ ---A---B
31
+
32
+where A and B are on the side development that was not so good, M is the
33
+merge that brings these premature changes into the mainline, x are changes
34
+unrelated to what the side branch did and already made on the mainline,
35
+and W is the "revert of the merge M" (doesn't W look M upside down?).
36
+IOW, "diff W^..W" is similar to "diff -R M^..M".
37
+
38
+Such a "revert" of a merge can be made with:
39
+
40
+ $ git revert -m 1 M
41
+
42
+After the develpers of the side branch fixes their mistakes, the history
43
+may look like this:
44
+
45
+ ---o---o---o---M---x---x---W---x
46
+ /
47
+ ---A---B-------------------C---D
48
+
49
+where C and D are to fix what was broken in A and B, and you may already
50
+have some other changes on the mainline after W.
51
+
52
+If you merge the updated side branch (with D at its tip), none of the
53
+changes made in A nor B will be in the result, because they were reverted
54
+by W. That is what Alan saw.
55
+
56
+Linus explains the situation:
57
+
58
+ Reverting a regular commit just effectively undoes what that commit
59
+ did, and is fairly straightforward. But reverting a merge commit also
60
+ undoes the _data_ that the commit changed, but it does absolutely
61
+ nothing to the effects on _history_ that the merge had.
62
+
63
+ So the merge will still exist, and it will still be seen as joining
64
+ the two branches together, and future merges will see that merge as
65
+ the last shared state - and the revert that reverted the merge brought
66
+ in will not affect that at all.
67
+
68
+ So a "revert" undoes the data changes, but it's very much _not_ an
69
+ "undo" in the sense that it doesn't undo the effects of a commit on
70
+ the repository history.
71
+
72
+ So if you think of "revert" as "undo", then you're going to always
73
+ miss this part of reverts. Yes, it undoes the data, but no, it doesn't
74
+ undo history.
75
+
76
+In such a situation, you would want to first revert the previous revert,
77
+which would make the history look like this:
78
+
79
+ ---o---o---o---M---x---x---W---x---Y
80
+ /
81
+ ---A---B-------------------C---D
82
+
83
+where Y is the revert of W. Such a "revert of the revert" can be done
84
+with:
85
+
86
+ $ git revert W
87
+
88
+This history would (ignoring possible conflicts between what W and W..Y
89
+changed) be equivalent to not having W nor Y at all in the history:
90
+
91
+ ---o---o---o---M---x---x-------x----
92
+ /
93
+ ---A---B-------------------C---D
94
+
95
+and merging the side branch again will not have conflict arising from an
96
+earlier revert and revert of the revert.
97
+
98
+ ---o---o---o---M---x---x-------x-------*
99
+ / /
100
+ ---A---B-------------------C---D
101
+
102
+Of course the changes made in C and D still can conflict with what was
103
+done by any of the x, but that is just a normal merge conflict.
104
+
105
+On the other hand, if the developers of the side branch discarded their
106
+faulty A and B, and redone the changes on top of the updated mainline
107
+after the revert, the history would have looked like this:
108
+
109
+ ---o---o---o---M---x---x---W---x---x
110
+ / \
111
+ ---A---B A'--B'--C'
112
+
113
+If you reverted the revert in such a case as in the previous example:
114
+
115
+ ---o---o---o---M---x---x---W---x---x---Y---*
116
+ / \ /
117
+ ---A---B A'--B'--C'
118
+
119
+where Y is the revert of W, A' and B'are rerolled A and B, and there may
120
+also be a further fix-up C' on the side branch. "diff Y^..Y" is similar
121
+to "diff -R W^..W" (which in turn means it is similar to "diff M^..M"),
122
+and "diff A'^..C'" by definition would be similar but different from that,
123
+because it is a rerolled series of the earlier change. There will be a
124
+lot of overlapping changes that result in conflicts. So do not do "revert
125
+of revert" blindly without thinking..
126
+
127
+ ---o---o---o---M---x---x---W---x---x
128
+ / \
129
+ ---A---B A'--B'--C'
130
+
131
+In the history with rebased side branch, W (and M) are behind the merge
132
+base of the updated branch and the tip of the mainline, and they should
133
+merge without the past faulty merge and its revert getting in the way.
134
+
135
+To recap, these are two very different scenarios, and they want two very
136
+different resolution strategies:
137
+
138
+ - If the faulty side branch was fixed by adding corrections on top, then
139
+ doing a revert of the previous revert would be the right thing to do.
140
+
141
+ - If the faulty side branch whose effects were discarded by an earlier
142
+ revert of a merge was rebuilt from scratch (i.e. rebasing and fixing,
143
+ as you seem to have interpreted), then re-merging the result without
144
+ doing anything else fancy would be the right thing to do.
145
+
146
+However, there are things to keep in mind when reverting a merge (and
147
+reverting such a revert).
148
+
149
+For example, think about what reverting a merge (and then reverting the
150
+revert) does to bisectability. Ignore the fact that the revert of a revert
151
+is undoing it - just think of it as a "single commit that does a lot".
152
+Because that is what it does.
153
+
154
+When you have a problem you are chasing down, and you hit a "revert this
155
+merge", what you're hitting is essentially a single commit that contains
156
+all the changes (but obviously in reverse) of all the commits that got
157
+merged. So it's debugging hell, because now you don't have lots of small
158
+changes that you can try to pinpoint which _part_ of it changes.
159
+
160
+But does it all work? Sure it does. You can revert a merge, and from a
161
+purely technical angle, git did it very naturally and had no real
162
+troubles. It just considered it a change from "state before merge" to
163
+"state after merge", and that was it. Nothing complicated, nothing odd,
164
+nothing really dangerous. Git will do it without even thinking about it.
165
+
166
+So from a technical angle, there's nothing wrong with reverting a merge,
167
+but from a workflow angle it's something that you generally should try to
168
+avoid.
169
+
170
+If at all possible, for example, if you find a problem that got merged
171
+into the main tree, rather than revert the merge, try _really_ hard to
172
+bisect the problem down into the branch you merged, and just fix it, or
173
+try to revert the individual commit that caused it.
174
+
175
+Yes, it's more complex, and no, it's not always going to work (sometimes
176
+the answer is: "oops, I really shouldn't have merged it, because it wasn't
177
+ready yet, and I really need to undo _all_ of the merge"). So then you
178
+really should revert the merge, but when you want to re-do the merge, you
179
+now need to do it by reverting the revert.