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