1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.merge;
12
13 import java.util.ArrayList;
14 import java.util.Iterator;
15 import java.util.List;
16
17 import org.eclipse.jgit.diff.DiffAlgorithm;
18 import org.eclipse.jgit.diff.Edit;
19 import org.eclipse.jgit.diff.EditList;
20 import org.eclipse.jgit.diff.HistogramDiff;
21 import org.eclipse.jgit.diff.Sequence;
22 import org.eclipse.jgit.diff.SequenceComparator;
23 import org.eclipse.jgit.merge.MergeChunk.ConflictState;
24
25
26
27
28
29
30 public final class MergeAlgorithm {
31 private final DiffAlgorithm diffAlg;
32
33
34
35
36
37 public MergeAlgorithm() {
38 this(new HistogramDiff());
39 }
40
41
42
43
44
45
46
47 public MergeAlgorithm(DiffAlgorithm diff) {
48 this.diffAlg = diff;
49 }
50
51
52
53 private static final Edittml#Edit">Edit END_EDIT = new Edit(Integer.MAX_VALUE,
54 Integer.MAX_VALUE);
55
56 @SuppressWarnings("ReferenceEquality")
57 private static boolean isEndEdit(Edit edit) {
58 return edit == END_EDIT;
59 }
60
61
62
63
64
65
66
67
68
69
70 public <S extends Sequence> MergeResult<S> merge(
71 SequenceComparator<S> cmp, S base, S ours, S theirs) {
72 List<S> sequences = new ArrayList<>(3);
73 sequences.add(base);
74 sequences.add(ours);
75 sequences.add(theirs);
76 MergeResult<S> result = new MergeResult<>(sequences);
77
78 if (ours.size() == 0) {
79 if (theirs.size() != 0) {
80 EditList theirsEdits = diffAlg.diff(cmp, base, theirs);
81 if (!theirsEdits.isEmpty()) {
82
83
84 result.add(1, 0, 0, ConflictState.FIRST_CONFLICTING_RANGE);
85 result.add(2, 0, theirs.size(),
86 ConflictState.NEXT_CONFLICTING_RANGE);
87 } else
88
89 result.add(1, 0, 0, ConflictState.NO_CONFLICT);
90 } else
91
92 result.add(1, 0, 0, ConflictState.NO_CONFLICT);
93 return result;
94 } else if (theirs.size() == 0) {
95 EditList oursEdits = diffAlg.diff(cmp, base, ours);
96 if (!oursEdits.isEmpty()) {
97
98
99 result.add(1, 0, ours.size(),
100 ConflictState.FIRST_CONFLICTING_RANGE);
101 result.add(2, 0, 0, ConflictState.NEXT_CONFLICTING_RANGE);
102 } else
103
104 result.add(2, 0, 0, ConflictState.NO_CONFLICT);
105 return result;
106 }
107
108 EditList oursEdits = diffAlg.diff(cmp, base, ours);
109 Iterator<Edit> baseToOurs = oursEdits.iterator();
110 EditList theirsEdits = diffAlg.diff(cmp, base, theirs);
111 Iterator<Edit> baseToTheirs = theirsEdits.iterator();
112 int current = 0;
113
114 Edit oursEdit = nextEdit(baseToOurs);
115 Edit theirsEdit = nextEdit(baseToTheirs);
116
117
118
119
120 while (!isEndEdit(theirsEdit) || !isEndEdit(oursEdit)) {
121 if (oursEdit.getEndA() < theirsEdit.getBeginA()) {
122
123
124
125 if (current != oursEdit.getBeginA()) {
126 result.add(0, current, oursEdit.getBeginA(),
127 ConflictState.NO_CONFLICT);
128 }
129 result.add(1, oursEdit.getBeginB(), oursEdit.getEndB(),
130 ConflictState.NO_CONFLICT);
131 current = oursEdit.getEndA();
132 oursEdit = nextEdit(baseToOurs);
133 } else if (theirsEdit.getEndA() < oursEdit.getBeginA()) {
134
135
136
137 if (current != theirsEdit.getBeginA()) {
138 result.add(0, current, theirsEdit.getBeginA(),
139 ConflictState.NO_CONFLICT);
140 }
141 result.add(2, theirsEdit.getBeginB(), theirsEdit.getEndB(),
142 ConflictState.NO_CONFLICT);
143 current = theirsEdit.getEndA();
144 theirsEdit = nextEdit(baseToTheirs);
145 } else {
146
147
148
149 if (oursEdit.getBeginA() != current
150 && theirsEdit.getBeginA() != current) {
151 result.add(0, current, Math.min(oursEdit.getBeginA(),
152 theirsEdit.getBeginA()), ConflictState.NO_CONFLICT);
153 }
154
155
156
157 int oursBeginB = oursEdit.getBeginB();
158 int theirsBeginB = theirsEdit.getBeginB();
159
160 if (oursEdit.getBeginA() < theirsEdit.getBeginA()) {
161 theirsBeginB -= theirsEdit.getBeginA()
162 - oursEdit.getBeginA();
163 } else {
164 oursBeginB -= oursEdit.getBeginA() - theirsEdit.getBeginA();
165 }
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194 Edit nextOursEdit = nextEdit(baseToOurs);
195 Edit nextTheirsEdit = nextEdit(baseToTheirs);
196 for (;;) {
197 if (oursEdit.getEndA() >= nextTheirsEdit.getBeginA()) {
198 theirsEdit = nextTheirsEdit;
199 nextTheirsEdit = nextEdit(baseToTheirs);
200 } else if (theirsEdit.getEndA() >= nextOursEdit.getBeginA()) {
201 oursEdit = nextOursEdit;
202 nextOursEdit = nextEdit(baseToOurs);
203 } else {
204 break;
205 }
206 }
207
208
209 int oursEndB = oursEdit.getEndB();
210 int theirsEndB = theirsEdit.getEndB();
211 if (oursEdit.getEndA() < theirsEdit.getEndA()) {
212 oursEndB += theirsEdit.getEndA() - oursEdit.getEndA();
213 } else {
214 theirsEndB += oursEdit.getEndA() - theirsEdit.getEndA();
215 }
216
217
218
219
220
221
222
223
224
225
226
227 int minBSize = oursEndB - oursBeginB;
228 int BSizeDelta = minBSize - (theirsEndB - theirsBeginB);
229 if (BSizeDelta > 0)
230 minBSize -= BSizeDelta;
231
232 int commonPrefix = 0;
233 while (commonPrefix < minBSize
234 && cmp.equals(ours, oursBeginB + commonPrefix, theirs,
235 theirsBeginB + commonPrefix))
236 commonPrefix++;
237 minBSize -= commonPrefix;
238 int commonSuffix = 0;
239 while (commonSuffix < minBSize
240 && cmp.equals(ours, oursEndB - commonSuffix - 1, theirs,
241 theirsEndB - commonSuffix - 1))
242 commonSuffix++;
243 minBSize -= commonSuffix;
244
245
246 if (commonPrefix > 0)
247 result.add(1, oursBeginB, oursBeginB + commonPrefix,
248 ConflictState.NO_CONFLICT);
249
250
251 if (minBSize > 0 || BSizeDelta != 0) {
252 result.add(1, oursBeginB + commonPrefix, oursEndB
253 - commonSuffix,
254 ConflictState.FIRST_CONFLICTING_RANGE);
255 result.add(2, theirsBeginB + commonPrefix, theirsEndB
256 - commonSuffix,
257 ConflictState.NEXT_CONFLICTING_RANGE);
258 }
259
260
261 if (commonSuffix > 0)
262 result.add(1, oursEndB - commonSuffix, oursEndB,
263 ConflictState.NO_CONFLICT);
264
265 current = Math.max(oursEdit.getEndA(), theirsEdit.getEndA());
266 oursEdit = nextOursEdit;
267 theirsEdit = nextTheirsEdit;
268 }
269 }
270
271
272 if (current < base.size()) {
273 result.add(0, current, base.size(), ConflictState.NO_CONFLICT);
274 }
275 return result;
276 }
277
278
279
280
281
282
283
284
285
286
287
288 private static Edit nextEdit(Iterator<Edit> it) {
289 return (it.hasNext() ? it.next() : END_EDIT);
290 }
291 }