1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.treewalk;
12
13 import java.io.IOException;
14
15 import org.eclipse.jgit.annotations.Nullable;
16 import org.eclipse.jgit.errors.CorruptObjectException;
17 import org.eclipse.jgit.lib.FileMode;
18 import org.eclipse.jgit.lib.ObjectReader;
19 import org.eclipse.jgit.lib.Repository;
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
45
46
47
48
49
50
51
52
53
54
55
56 public class NameConflictTreeWalk extends TreeWalk {
57 private static final int TREE_MODE = FileMode.TREE.getBits();
58
59 private boolean fastMinHasMatch;
60
61 private AbstractTreeIterator dfConflict;
62
63
64
65
66
67
68
69 public NameConflictTreeWalk(Repository repo) {
70 super(repo);
71 }
72
73
74
75
76
77
78
79
80
81
82 public NameConflictTreeWalk(@Nullable Repository repo, ObjectReader or) {
83 super(repo, or);
84 }
85
86
87
88
89
90
91
92 public NameConflictTreeWalk(ObjectReader or) {
93 super(or);
94 }
95
96 @Override
97 AbstractTreeIterator min() throws CorruptObjectException {
98 for (;;) {
99 final AbstractTreeIterator minRef = fastMin();
100 if (fastMinHasMatch)
101 return minRef;
102
103 if (isTree(minRef)) {
104 if (skipEntry(minRef)) {
105 for (AbstractTreeIterator t : trees) {
106 if (t.matches == minRef) {
107 t.next(1);
108 t.matches = null;
109 }
110 }
111 continue;
112 }
113 return minRef;
114 }
115
116 return combineDF(minRef);
117 }
118 }
119
120 private AbstractTreeIterator fastMin() {
121 fastMinHasMatch = true;
122
123 int i = 0;
124 AbstractTreeIterator minRef = trees[i];
125 while (minRef.eof() && ++i < trees.length)
126 minRef = trees[i];
127 if (minRef.eof())
128 return minRef;
129
130 boolean hasConflict = false;
131 minRef.matches = minRef;
132 while (++i < trees.length) {
133 final AbstractTreeIterator t = trees[i];
134 if (t.eof())
135 continue;
136
137 final int cmp = t.pathCompare(minRef);
138 if (cmp < 0) {
139 if (fastMinHasMatch && isTree(minRef) && !isTree(t)
140 && nameEqual(minRef, t)) {
141
142
143
144
145 t.matches = minRef;
146 hasConflict = true;
147 } else {
148 fastMinHasMatch = false;
149 t.matches = t;
150 minRef = t;
151 }
152 } else if (cmp == 0) {
153
154
155 t.matches = minRef;
156 } else if (fastMinHasMatch && isTree(t) && !isTree(minRef)
157 && !isGitlink(minRef) && nameEqual(t, minRef)) {
158
159
160
161
162
163
164
165
166 for (int k = 0; k < i; k++) {
167 final AbstractTreeIterator p = trees[k];
168 if (p.matches == minRef)
169 p.matches = t;
170 }
171 t.matches = t;
172 minRef = t;
173 hasConflict = true;
174 } else
175 fastMinHasMatch = false;
176 }
177
178 if (hasConflict && fastMinHasMatch && dfConflict == null)
179 dfConflict = minRef;
180 return minRef;
181 }
182
183 private static boolean nameEqual(final AbstractTreeIterator a,
184 final AbstractTreeIterator b) {
185 return a.pathCompare(b, TREE_MODE) == 0;
186 }
187
188 private boolean isGitlink(AbstractTreeIterator p) {
189 return FileMode.GITLINK.equals(p.mode);
190 }
191
192 private static boolean isTree(AbstractTreeIterator p) {
193 return FileMode.TREE.equals(p.mode);
194 }
195
196 private boolean skipEntry(AbstractTreeIterator minRef)
197 throws CorruptObjectException {
198
199
200
201 for (AbstractTreeIterator t : trees) {
202 if (t.matches == minRef || t.first())
203 continue;
204
205 int stepsBack = 0;
206 for (;;) {
207 stepsBack++;
208 t.back(1);
209
210 final int cmp = t.pathCompare(minRef, 0);
211 if (cmp == 0) {
212
213
214 t.next(stepsBack);
215 return true;
216 } else if (cmp < 0 || t.first()) {
217
218
219 t.next(stepsBack);
220 break;
221 }
222 }
223 }
224
225
226
227 return false;
228 }
229
230 private AbstractTreeIteratorg/eclipse/jgit/treewalk/AbstractTreeIterator.html#AbstractTreeIterator">AbstractTreeIterator combineDF(AbstractTreeIterator minRef)
231 throws CorruptObjectException {
232
233
234
235
236 AbstractTreeIterator treeMatch = null;
237 for (AbstractTreeIterator t : trees) {
238 if (t.matches == minRef || t.eof())
239 continue;
240
241 for (;;) {
242 final int cmp = t.pathCompare(minRef, TREE_MODE);
243 if (cmp < 0) {
244
245
246 t.matchShift++;
247 t.next(1);
248 if (t.eof()) {
249 t.back(t.matchShift);
250 t.matchShift = 0;
251 break;
252 }
253 } else if (cmp == 0) {
254
255
256 t.matches = minRef;
257 treeMatch = t;
258 break;
259 } else {
260
261
262 if (t.matchShift != 0) {
263 t.back(t.matchShift);
264 t.matchShift = 0;
265 }
266 break;
267 }
268 }
269 }
270
271 if (treeMatch != null) {
272
273
274
275
276 for (AbstractTreeIterator t : trees)
277 if (t.matches == minRef)
278 t.matches = treeMatch;
279
280 if (dfConflict == null && !isGitlink(minRef)) {
281 dfConflict = treeMatch;
282 }
283
284 return treeMatch;
285 }
286
287 return minRef;
288 }
289
290 @Override
291 void popEntriesEqual() throws CorruptObjectException {
292 final AbstractTreeIterator ch = currentHead;
293 for (AbstractTreeIterator t : trees) {
294 if (t.matches == ch) {
295 if (t.matchShift == 0)
296 t.next(1);
297 else {
298 t.back(t.matchShift);
299 t.matchShift = 0;
300 }
301 t.matches = null;
302 }
303 }
304
305 if (ch == dfConflict)
306 dfConflict = null;
307 }
308
309 @Override
310 void skipEntriesEqual() throws CorruptObjectException {
311 final AbstractTreeIterator ch = currentHead;
312 for (AbstractTreeIterator t : trees) {
313 if (t.matches == ch) {
314 if (t.matchShift == 0)
315 t.skip();
316 else {
317 t.back(t.matchShift);
318 t.matchShift = 0;
319 }
320 t.matches = null;
321 }
322 }
323
324 if (ch == dfConflict)
325 dfConflict = null;
326 }
327
328 @Override
329 void stopWalk() throws IOException {
330 if (!needsStopWalk()) {
331 return;
332 }
333
334
335
336
337
338
339
340 for (;;) {
341 AbstractTreeIterator t = min();
342 if (t.eof()) {
343 if (depth > 0) {
344 exitSubtree();
345 popEntriesEqual();
346 continue;
347 }
348 return;
349 }
350 currentHead = t;
351 skipEntriesEqual();
352 }
353 }
354
355 private boolean needsStopWalk() {
356 for (AbstractTreeIterator t : trees) {
357 if (t.needsStopWalk()) {
358 return true;
359 }
360 }
361 return false;
362 }
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378 public boolean isDirectoryFileConflict() {
379 return dfConflict != null;
380 }
381 }