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.annotations.NonNull;
18 import org.eclipse.jgit.diff.DiffAlgorithm;
19 import org.eclipse.jgit.diff.Edit;
20 import org.eclipse.jgit.diff.EditList;
21 import org.eclipse.jgit.diff.HistogramDiff;
22 import org.eclipse.jgit.diff.Sequence;
23 import org.eclipse.jgit.diff.SequenceComparator;
24 import org.eclipse.jgit.merge.MergeChunk.ConflictState;
25
26
27
28
29
30
31 public final class MergeAlgorithm {
32
33 private final DiffAlgorithm diffAlg;
34
35 @NonNull
36 private ContentMergeStrategy strategy = ContentMergeStrategy.CONFLICT;
37
38
39
40
41
42 public MergeAlgorithm() {
43 this(new HistogramDiff());
44 }
45
46
47
48
49
50
51
52 public MergeAlgorithm(DiffAlgorithm diff) {
53 this.diffAlg = diff;
54 }
55
56
57
58
59
60
61
62 @NonNull
63 public ContentMergeStrategy getContentMergeStrategy() {
64 return strategy;
65 }
66
67
68
69
70
71
72
73
74
75 public void setContentMergeStrategy(ContentMergeStrategy strategy) {
76 this.strategy = strategy == null ? ContentMergeStrategy.CONFLICT
77 : strategy;
78 }
79
80
81
82 private static final Edittml#Edit">Edit END_EDIT = new Edit(Integer.MAX_VALUE,
83 Integer.MAX_VALUE);
84
85 @SuppressWarnings("ReferenceEquality")
86 private static boolean isEndEdit(Edit edit) {
87 return edit == END_EDIT;
88 }
89
90
91
92
93
94
95
96
97
98
99 public <S extends Sequence> MergeResult<S> merge(
100 SequenceComparator<S> cmp, S base, S ours, S theirs) {
101 List<S> sequences = new ArrayList<>(3);
102 sequences.add(base);
103 sequences.add(ours);
104 sequences.add(theirs);
105 MergeResult<S> result = new MergeResult<>(sequences);
106
107 if (ours.size() == 0) {
108 if (theirs.size() != 0) {
109 EditList theirsEdits = diffAlg.diff(cmp, base, theirs);
110 if (!theirsEdits.isEmpty()) {
111
112 switch (strategy) {
113 case OURS:
114 result.add(1, 0, 0, ConflictState.NO_CONFLICT);
115 break;
116 case THEIRS:
117 result.add(2, 0, theirs.size(),
118 ConflictState.NO_CONFLICT);
119 break;
120 default:
121
122 result.add(1, 0, 0,
123 ConflictState.FIRST_CONFLICTING_RANGE);
124 result.add(2, 0, theirs.size(),
125 ConflictState.NEXT_CONFLICTING_RANGE);
126 break;
127 }
128 } else {
129
130 result.add(1, 0, 0, ConflictState.NO_CONFLICT);
131 }
132 } else {
133
134 result.add(1, 0, 0, ConflictState.NO_CONFLICT);
135 }
136 return result;
137 } else if (theirs.size() == 0) {
138 EditList oursEdits = diffAlg.diff(cmp, base, ours);
139 if (!oursEdits.isEmpty()) {
140
141 switch (strategy) {
142 case OURS:
143 result.add(1, 0, ours.size(), ConflictState.NO_CONFLICT);
144 break;
145 case THEIRS:
146 result.add(2, 0, 0, ConflictState.NO_CONFLICT);
147 break;
148 default:
149
150 result.add(1, 0, ours.size(),
151 ConflictState.FIRST_CONFLICTING_RANGE);
152 result.add(2, 0, 0, ConflictState.NEXT_CONFLICTING_RANGE);
153 break;
154 }
155 } else {
156
157 result.add(2, 0, 0, ConflictState.NO_CONFLICT);
158 }
159 return result;
160 }
161
162 EditList oursEdits = diffAlg.diff(cmp, base, ours);
163 Iterator<Edit> baseToOurs = oursEdits.iterator();
164 EditList theirsEdits = diffAlg.diff(cmp, base, theirs);
165 Iterator<Edit> baseToTheirs = theirsEdits.iterator();
166 int current = 0;
167
168 Edit oursEdit = nextEdit(baseToOurs);
169 Edit theirsEdit = nextEdit(baseToTheirs);
170
171
172
173
174 while (!isEndEdit(theirsEdit) || !isEndEdit(oursEdit)) {
175 if (oursEdit.getEndA() < theirsEdit.getBeginA()) {
176
177
178
179 if (current != oursEdit.getBeginA()) {
180 result.add(0, current, oursEdit.getBeginA(),
181 ConflictState.NO_CONFLICT);
182 }
183 result.add(1, oursEdit.getBeginB(), oursEdit.getEndB(),
184 ConflictState.NO_CONFLICT);
185 current = oursEdit.getEndA();
186 oursEdit = nextEdit(baseToOurs);
187 } else if (theirsEdit.getEndA() < oursEdit.getBeginA()) {
188
189
190
191 if (current != theirsEdit.getBeginA()) {
192 result.add(0, current, theirsEdit.getBeginA(),
193 ConflictState.NO_CONFLICT);
194 }
195 result.add(2, theirsEdit.getBeginB(), theirsEdit.getEndB(),
196 ConflictState.NO_CONFLICT);
197 current = theirsEdit.getEndA();
198 theirsEdit = nextEdit(baseToTheirs);
199 } else {
200
201
202
203 if (oursEdit.getBeginA() != current
204 && theirsEdit.getBeginA() != current) {
205 result.add(0, current, Math.min(oursEdit.getBeginA(),
206 theirsEdit.getBeginA()), ConflictState.NO_CONFLICT);
207 }
208
209
210
211 int oursBeginB = oursEdit.getBeginB();
212 int theirsBeginB = theirsEdit.getBeginB();
213
214 if (oursEdit.getBeginA() < theirsEdit.getBeginA()) {
215 theirsBeginB -= theirsEdit.getBeginA()
216 - oursEdit.getBeginA();
217 } else {
218 oursBeginB -= oursEdit.getBeginA() - theirsEdit.getBeginA();
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248 Edit nextOursEdit = nextEdit(baseToOurs);
249 Edit nextTheirsEdit = nextEdit(baseToTheirs);
250 for (;;) {
251 if (oursEdit.getEndA() >= nextTheirsEdit.getBeginA()) {
252 theirsEdit = nextTheirsEdit;
253 nextTheirsEdit = nextEdit(baseToTheirs);
254 } else if (theirsEdit.getEndA() >= nextOursEdit.getBeginA()) {
255 oursEdit = nextOursEdit;
256 nextOursEdit = nextEdit(baseToOurs);
257 } else {
258 break;
259 }
260 }
261
262
263 int oursEndB = oursEdit.getEndB();
264 int theirsEndB = theirsEdit.getEndB();
265 if (oursEdit.getEndA() < theirsEdit.getEndA()) {
266 oursEndB += theirsEdit.getEndA() - oursEdit.getEndA();
267 } else {
268 theirsEndB += oursEdit.getEndA() - theirsEdit.getEndA();
269 }
270
271
272
273
274
275
276
277
278
279
280
281 int minBSize = oursEndB - oursBeginB;
282 int BSizeDelta = minBSize - (theirsEndB - theirsBeginB);
283 if (BSizeDelta > 0)
284 minBSize -= BSizeDelta;
285
286 int commonPrefix = 0;
287 while (commonPrefix < minBSize
288 && cmp.equals(ours, oursBeginB + commonPrefix, theirs,
289 theirsBeginB + commonPrefix))
290 commonPrefix++;
291 minBSize -= commonPrefix;
292 int commonSuffix = 0;
293 while (commonSuffix < minBSize
294 && cmp.equals(ours, oursEndB - commonSuffix - 1, theirs,
295 theirsEndB - commonSuffix - 1))
296 commonSuffix++;
297 minBSize -= commonSuffix;
298
299
300 if (commonPrefix > 0)
301 result.add(1, oursBeginB, oursBeginB + commonPrefix,
302 ConflictState.NO_CONFLICT);
303
304
305 if (minBSize > 0 || BSizeDelta != 0) {
306 switch (strategy) {
307 case OURS:
308 result.add(1, oursBeginB + commonPrefix,
309 oursEndB - commonSuffix,
310 ConflictState.NO_CONFLICT);
311 break;
312 case THEIRS:
313 result.add(2, theirsBeginB + commonPrefix,
314 theirsEndB - commonSuffix,
315 ConflictState.NO_CONFLICT);
316 break;
317 default:
318 result.add(1, oursBeginB + commonPrefix,
319 oursEndB - commonSuffix,
320 ConflictState.FIRST_CONFLICTING_RANGE);
321 result.add(2, theirsBeginB + commonPrefix,
322 theirsEndB - commonSuffix,
323 ConflictState.NEXT_CONFLICTING_RANGE);
324 break;
325 }
326 }
327
328
329 if (commonSuffix > 0)
330 result.add(1, oursEndB - commonSuffix, oursEndB,
331 ConflictState.NO_CONFLICT);
332
333 current = Math.max(oursEdit.getEndA(), theirsEdit.getEndA());
334 oursEdit = nextOursEdit;
335 theirsEdit = nextTheirsEdit;
336 }
337 }
338
339
340 if (current < base.size()) {
341 result.add(0, current, base.size(), ConflictState.NO_CONFLICT);
342 }
343 return result;
344 }
345
346
347
348
349
350
351
352
353
354
355
356 private static Edit nextEdit(Iterator<Edit> it) {
357 return (it.hasNext() ? it.next() : END_EDIT);
358 }
359 }