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
45
46 package org.eclipse.jgit.merge;
47
48 import static org.eclipse.jgit.diff.DiffAlgorithm.SupportedAlgorithm.HISTOGRAM;
49 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFF_SECTION;
50 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_ALGORITHM;
51 import static org.eclipse.jgit.lib.Constants.CHARACTER_ENCODING;
52 import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
53
54 import java.io.BufferedOutputStream;
55 import java.io.File;
56 import java.io.FileInputStream;
57 import java.io.FileNotFoundException;
58 import java.io.FileOutputStream;
59 import java.io.IOException;
60 import java.io.InputStream;
61 import java.io.OutputStream;
62 import java.util.ArrayList;
63 import java.util.Arrays;
64 import java.util.Collections;
65 import java.util.HashMap;
66 import java.util.Iterator;
67 import java.util.LinkedList;
68 import java.util.List;
69 import java.util.Map;
70
71 import org.eclipse.jgit.attributes.Attributes;
72 import org.eclipse.jgit.diff.DiffAlgorithm;
73 import org.eclipse.jgit.diff.DiffAlgorithm.SupportedAlgorithm;
74 import org.eclipse.jgit.diff.RawText;
75 import org.eclipse.jgit.diff.RawTextComparator;
76 import org.eclipse.jgit.diff.Sequence;
77 import org.eclipse.jgit.dircache.DirCache;
78 import org.eclipse.jgit.dircache.DirCacheBuildIterator;
79 import org.eclipse.jgit.dircache.DirCacheBuilder;
80 import org.eclipse.jgit.dircache.DirCacheCheckout;
81 import org.eclipse.jgit.dircache.DirCacheEntry;
82 import org.eclipse.jgit.errors.CorruptObjectException;
83 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
84 import org.eclipse.jgit.errors.IndexWriteException;
85 import org.eclipse.jgit.errors.MissingObjectException;
86 import org.eclipse.jgit.errors.NoWorkTreeException;
87 import org.eclipse.jgit.lib.Config;
88 import org.eclipse.jgit.lib.ConfigConstants;
89 import org.eclipse.jgit.lib.FileMode;
90 import org.eclipse.jgit.lib.ObjectId;
91 import org.eclipse.jgit.lib.ObjectInserter;
92 import org.eclipse.jgit.lib.ObjectReader;
93 import org.eclipse.jgit.lib.Repository;
94 import org.eclipse.jgit.revwalk.RevTree;
95 import org.eclipse.jgit.treewalk.AbstractTreeIterator;
96 import org.eclipse.jgit.treewalk.CanonicalTreeParser;
97 import org.eclipse.jgit.treewalk.NameConflictTreeWalk;
98 import org.eclipse.jgit.treewalk.TreeWalk;
99 import org.eclipse.jgit.treewalk.WorkingTreeIterator;
100 import org.eclipse.jgit.treewalk.filter.TreeFilter;
101 import org.eclipse.jgit.util.FS;
102 import org.eclipse.jgit.util.TemporaryBuffer;
103
104
105
106
107 public class ResolveMerger extends ThreeWayMerger {
108
109
110
111
112 public enum MergeFailureReason {
113
114 DIRTY_INDEX,
115
116 DIRTY_WORKTREE,
117
118 COULD_NOT_DELETE
119 }
120
121
122
123
124
125
126 protected NameConflictTreeWalk tw;
127
128
129
130
131
132
133 protected String commitNames[];
134
135
136
137
138
139
140 protected static final int T_BASE = 0;
141
142
143
144
145
146
147 protected static final int T_OURS = 1;
148
149
150
151
152
153
154 protected static final int T_THEIRS = 2;
155
156
157
158
159
160
161 protected static final int T_INDEX = 3;
162
163
164
165
166
167
168 protected static final int T_FILE = 4;
169
170
171
172
173
174
175 protected DirCacheBuilder builder;
176
177
178
179
180
181
182 protected ObjectId resultTree;
183
184
185
186
187
188
189
190 protected List<String> unmergedPaths = new ArrayList<>();
191
192
193
194
195
196
197 protected List<String> modifiedFiles = new LinkedList<>();
198
199
200
201
202
203
204
205 protected Map<String, DirCacheEntry> toBeCheckedOut = new HashMap<>();
206
207
208
209
210
211
212
213 protected List<String> toBeDeleted = new ArrayList<>();
214
215
216
217
218
219
220
221 protected Map<String, MergeResult<? extends Sequence>> mergeResults = new HashMap<>();
222
223
224
225
226
227
228 protected Map<String, MergeFailureReason> failingPaths = new HashMap<>();
229
230
231
232
233
234
235
236 protected boolean enterSubtree;
237
238
239
240
241
242
243
244
245
246 protected boolean inCore;
247
248
249
250
251
252
253
254
255 protected boolean implicitDirCache;
256
257
258
259
260
261 protected DirCache dircache;
262
263
264
265
266
267
268 protected WorkingTreeIterator workingTreeIterator;
269
270
271
272
273
274 protected MergeAlgorithm mergeAlgorithm;
275
276
277
278
279
280 private int inCoreLimit;
281
282 private static MergeAlgorithm getMergeAlgorithm(Config config) {
283 SupportedAlgorithm diffAlg = config.getEnum(
284 CONFIG_DIFF_SECTION, null, CONFIG_KEY_ALGORITHM,
285 HISTOGRAM);
286 return new MergeAlgorithm(DiffAlgorithm.getAlgorithm(diffAlg));
287 }
288
289 private static int getInCoreLimit(Config config) {
290 return config.getInt(
291 ConfigConstants.CONFIG_MERGE_SECTION, ConfigConstants.CONFIG_KEY_IN_CORE_LIMIT, 10 << 20);
292 }
293
294 private static String[] defaultCommitNames() {
295 return new String[] { "BASE", "OURS", "THEIRS" };
296 }
297
298
299
300
301
302 protected ResolveMerger(Repository local, boolean inCore) {
303 super(local);
304 Config config = local.getConfig();
305 mergeAlgorithm = getMergeAlgorithm(config);
306 inCoreLimit = getInCoreLimit(config);
307 commitNames = defaultCommitNames();
308 this.inCore = inCore;
309
310 if (inCore) {
311 implicitDirCache = false;
312 dircache = DirCache.newInCore();
313 } else {
314 implicitDirCache = true;
315 }
316 }
317
318
319
320
321 protected ResolveMerger(Repository local) {
322 this(local, false);
323 }
324
325
326
327
328
329
330 protected ResolveMerger(ObjectInserter inserter, Config config) {
331 super(inserter);
332 mergeAlgorithm = getMergeAlgorithm(config);
333 commitNames = defaultCommitNames();
334 inCore = true;
335 implicitDirCache = false;
336 dircache = DirCache.newInCore();
337 }
338
339 @Override
340 protected boolean mergeImpl() throws IOException {
341 if (implicitDirCache)
342 dircache = nonNullRepo().lockDirCache();
343
344 try {
345 return mergeTrees(mergeBase(), sourceTrees[0], sourceTrees[1],
346 false);
347 } finally {
348 if (implicitDirCache)
349 dircache.unlock();
350 }
351 }
352
353 private void checkout() throws NoWorkTreeException, IOException {
354
355
356
357 for (int i = toBeDeleted.size() - 1; i >= 0; i--) {
358 String fileName = toBeDeleted.get(i);
359 File f = new File(nonNullRepo().getWorkTree(), fileName);
360 if (!f.delete())
361 if (!f.isDirectory())
362 failingPaths.put(fileName,
363 MergeFailureReason.COULD_NOT_DELETE);
364 modifiedFiles.add(fileName);
365 }
366 for (Map.Entry<String, DirCacheEntry> entry : toBeCheckedOut
367 .entrySet()) {
368 DirCacheCheckout.checkoutEntry(db, entry.getValue(), reader);
369 modifiedFiles.add(entry.getKey());
370 }
371 }
372
373
374
375
376
377
378
379
380
381
382
383
384 protected void cleanUp() throws NoWorkTreeException,
385 CorruptObjectException,
386 IOException {
387 if (inCore) {
388 modifiedFiles.clear();
389 return;
390 }
391
392 DirCache dc = nonNullRepo().readDirCache();
393 Iterator<String> mpathsIt=modifiedFiles.iterator();
394 while(mpathsIt.hasNext()) {
395 String mpath=mpathsIt.next();
396 DirCacheEntry entry = dc.getEntry(mpath);
397 if (entry != null)
398 DirCacheCheckout.checkoutEntry(db, entry, reader);
399 mpathsIt.remove();
400 }
401 }
402
403
404
405
406
407
408
409
410
411
412
413 private DirCacheEntry add(byte[] path, CanonicalTreeParser p, int stage,
414 long lastMod, long len) {
415 if (p != null && !p.getEntryFileMode().equals(FileMode.TREE)) {
416 DirCacheEntry e = new DirCacheEntry(path, stage);
417 e.setFileMode(p.getEntryFileMode());
418 e.setObjectId(p.getEntryObjectId());
419 e.setLastModified(lastMod);
420 e.setLength(len);
421 builder.add(e);
422 return e;
423 }
424 return null;
425 }
426
427
428
429
430
431
432
433
434
435
436 private DirCacheEntry keep(DirCacheEntry e) {
437 DirCacheEntry newEntry = new DirCacheEntry(e.getPathString(),
438 e.getStage());
439 newEntry.setFileMode(e.getFileMode());
440 newEntry.setObjectId(e.getObjectId());
441 newEntry.setLastModified(e.getLastModified());
442 newEntry.setLength(e.getLength());
443 builder.add(newEntry);
444 return newEntry;
445 }
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494 protected boolean processEntry(CanonicalTreeParser base,
495 CanonicalTreeParser ours, CanonicalTreeParser theirs,
496 DirCacheBuildIterator index, WorkingTreeIterator work,
497 boolean ignoreConflicts, Attributes attributes)
498 throws MissingObjectException, IncorrectObjectTypeException,
499 CorruptObjectException, IOException {
500 enterSubtree = true;
501 final int modeO = tw.getRawMode(T_OURS);
502 final int modeT = tw.getRawMode(T_THEIRS);
503 final int modeB = tw.getRawMode(T_BASE);
504
505 if (modeO == 0 && modeT == 0 && modeB == 0)
506
507 return true;
508
509 if (isIndexDirty())
510 return false;
511
512 DirCacheEntry ourDce = null;
513
514 if (index == null || index.getDirCacheEntry() == null) {
515
516
517 if (nonTree(modeO)) {
518 ourDce = new DirCacheEntry(tw.getRawPath());
519 ourDce.setObjectId(tw.getObjectId(T_OURS));
520 ourDce.setFileMode(tw.getFileMode(T_OURS));
521 }
522 } else {
523 ourDce = index.getDirCacheEntry();
524 }
525
526 if (nonTree(modeO) && nonTree(modeT) && tw.idEqual(T_OURS, T_THEIRS)) {
527
528 if (modeO == modeT) {
529
530
531
532 keep(ourDce);
533
534 return true;
535 } else {
536
537
538
539 int newMode = mergeFileModes(modeB, modeO, modeT);
540 if (newMode != FileMode.MISSING.getBits()) {
541 if (newMode == modeO)
542
543 keep(ourDce);
544 else {
545
546
547 if (isWorktreeDirty(work, ourDce))
548 return false;
549
550
551 DirCacheEntry e = add(tw.getRawPath(), theirs,
552 DirCacheEntry.STAGE_0, 0, 0);
553 toBeCheckedOut.put(tw.getPathString(), e);
554 }
555 return true;
556 } else {
557
558
559 add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
560 add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
561 add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
562 unmergedPaths.add(tw.getPathString());
563 mergeResults.put(
564 tw.getPathString(),
565 new MergeResult<>(Collections
566 .<RawText> emptyList()));
567 }
568 return true;
569 }
570 }
571
572 if (modeB == modeT && tw.idEqual(T_BASE, T_THEIRS)) {
573
574
575 if (ourDce != null)
576 keep(ourDce);
577
578 return true;
579 }
580
581 if (modeB == modeO && tw.idEqual(T_BASE, T_OURS)) {
582
583
584
585
586 if (isWorktreeDirty(work, ourDce))
587 return false;
588 if (nonTree(modeT)) {
589
590
591
592 DirCacheEntry e = add(tw.getRawPath(), theirs,
593 DirCacheEntry.STAGE_0, 0, 0);
594 if (e != null)
595 toBeCheckedOut.put(tw.getPathString(), e);
596 return true;
597 } else {
598
599
600
601
602
603 if (tw.getTreeCount() > T_FILE && tw.getRawMode(T_FILE) == 0)
604 return true;
605 toBeDeleted.add(tw.getPathString());
606 return true;
607 }
608 }
609
610 if (tw.isSubtree()) {
611
612
613
614
615 if (nonTree(modeO) && !nonTree(modeT)) {
616 if (nonTree(modeB))
617 add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
618 add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
619 unmergedPaths.add(tw.getPathString());
620 enterSubtree = false;
621 return true;
622 }
623 if (nonTree(modeT) && !nonTree(modeO)) {
624 if (nonTree(modeB))
625 add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
626 add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
627 unmergedPaths.add(tw.getPathString());
628 enterSubtree = false;
629 return true;
630 }
631
632
633
634
635
636 if (!nonTree(modeO))
637 return true;
638
639
640
641 }
642
643 if (nonTree(modeO) && nonTree(modeT)) {
644
645 if (isWorktreeDirty(work, ourDce))
646 return false;
647
648
649 if (isGitLink(modeO) || isGitLink(modeT)
650 || !attributes.canBeContentMerged()) {
651 add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
652 add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
653 add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
654 unmergedPaths.add(tw.getPathString());
655 return true;
656 }
657
658 MergeResult<RawText> result = contentMerge(base, ours, theirs);
659 if (ignoreConflicts) {
660 result.setContainsConflicts(false);
661 }
662 updateIndex(base, ours, theirs, result);
663 if (result.containsConflicts() && !ignoreConflicts)
664 unmergedPaths.add(tw.getPathString());
665 modifiedFiles.add(tw.getPathString());
666 } else if (modeO != modeT) {
667
668 if (((modeO != 0 && !tw.idEqual(T_BASE, T_OURS)) || (modeT != 0 && !tw
669 .idEqual(T_BASE, T_THEIRS)))) {
670
671 add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
672 add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
673 DirCacheEntry e = add(tw.getRawPath(), theirs,
674 DirCacheEntry.STAGE_3, 0, 0);
675
676
677 if (modeO == 0) {
678
679 if (isWorktreeDirty(work, ourDce))
680 return false;
681 if (nonTree(modeT)) {
682 if (e != null)
683 toBeCheckedOut.put(tw.getPathString(), e);
684 }
685 }
686
687 unmergedPaths.add(tw.getPathString());
688
689
690 mergeResults.put(tw.getPathString(),
691 contentMerge(base, ours, theirs));
692 }
693 }
694 return true;
695 }
696
697
698
699
700
701
702
703
704
705
706
707
708
709 private MergeResult<RawText> contentMerge(CanonicalTreeParser base,
710 CanonicalTreeParser ours, CanonicalTreeParser theirs)
711 throws IOException {
712 RawText baseText = base == null ? RawText.EMPTY_TEXT : getRawText(
713 base.getEntryObjectId(), reader);
714 RawText ourText = ours == null ? RawText.EMPTY_TEXT : getRawText(
715 ours.getEntryObjectId(), reader);
716 RawText theirsText = theirs == null ? RawText.EMPTY_TEXT : getRawText(
717 theirs.getEntryObjectId(), reader);
718 return (mergeAlgorithm.merge(RawTextComparator.DEFAULT, baseText,
719 ourText, theirsText));
720 }
721
722 private boolean isIndexDirty() {
723 if (inCore)
724 return false;
725
726 final int modeI = tw.getRawMode(T_INDEX);
727 final int modeO = tw.getRawMode(T_OURS);
728
729
730 final boolean isDirty = nonTree(modeI)
731 && !(modeO == modeI && tw.idEqual(T_INDEX, T_OURS));
732 if (isDirty)
733 failingPaths
734 .put(tw.getPathString(), MergeFailureReason.DIRTY_INDEX);
735 return isDirty;
736 }
737
738 private boolean isWorktreeDirty(WorkingTreeIterator work,
739 DirCacheEntry ourDce) throws IOException {
740 if (work == null)
741 return false;
742
743 final int modeF = tw.getRawMode(T_FILE);
744 final int modeO = tw.getRawMode(T_OURS);
745
746
747 boolean isDirty;
748 if (ourDce != null)
749 isDirty = work.isModified(ourDce, true, reader);
750 else {
751 isDirty = work.isModeDifferent(modeO);
752 if (!isDirty && nonTree(modeF))
753 isDirty = !tw.idEqual(T_FILE, T_OURS);
754 }
755
756
757 if (isDirty && modeF == FileMode.TYPE_TREE
758 && modeO == FileMode.TYPE_MISSING)
759 isDirty = false;
760 if (isDirty)
761 failingPaths.put(tw.getPathString(),
762 MergeFailureReason.DIRTY_WORKTREE);
763 return isDirty;
764 }
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779 private void updateIndex(CanonicalTreeParser base,
780 CanonicalTreeParser ours, CanonicalTreeParser theirs,
781 MergeResult<RawText> result) throws FileNotFoundException,
782 IOException {
783 File mergedFile = !inCore ? writeMergedFile(result) : null;
784
785 if (result.containsConflicts()) {
786
787
788
789 add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
790 add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
791 add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
792 mergeResults.put(tw.getPathString(), result);
793 return;
794 }
795
796
797
798 DirCacheEntry dce = new DirCacheEntry(tw.getPathString());
799
800
801
802 int newMode = mergeFileModes(
803 tw.getRawMode(0),
804 tw.getRawMode(1),
805 tw.getRawMode(2));
806 dce.setFileMode(newMode == FileMode.MISSING.getBits()
807 ? FileMode.REGULAR_FILE
808 : FileMode.fromBits(newMode));
809 if (mergedFile != null) {
810 long len = mergedFile.length();
811 dce.setLastModified(FS.DETECTED.lastModified(mergedFile));
812 dce.setLength((int) len);
813 InputStream is = new FileInputStream(mergedFile);
814 try {
815 dce.setObjectId(getObjectInserter().insert(OBJ_BLOB, len, is));
816 } finally {
817 is.close();
818 }
819 } else
820 dce.setObjectId(insertMergeResult(result));
821 builder.add(dce);
822 }
823
824
825
826
827
828
829
830
831
832
833 private File writeMergedFile(MergeResult<RawText> result)
834 throws FileNotFoundException, IOException {
835 File workTree = nonNullRepo().getWorkTree();
836 FS fs = nonNullRepo().getFS();
837 File of = new File(workTree, tw.getPathString());
838 File parentFolder = of.getParentFile();
839 if (!fs.exists(parentFolder))
840 parentFolder.mkdirs();
841 try (OutputStream os = new BufferedOutputStream(
842 new FileOutputStream(of))) {
843 new MergeFormatter().formatMerge(os, result,
844 Arrays.asList(commitNames), CHARACTER_ENCODING);
845 }
846 return of;
847 }
848
849 private ObjectId insertMergeResult(MergeResult<RawText> result)
850 throws IOException {
851 TemporaryBuffer.LocalFile buf = new TemporaryBuffer.LocalFile(
852 db != null ? nonNullRepo().getDirectory() : null, inCoreLimit);
853 try {
854 new MergeFormatter().formatMerge(buf, result,
855 Arrays.asList(commitNames), CHARACTER_ENCODING);
856 buf.close();
857 try (InputStream in = buf.openInputStream()) {
858 return getObjectInserter().insert(OBJ_BLOB, buf.length(), in);
859 }
860 } finally {
861 buf.destroy();
862 }
863 }
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881 private int mergeFileModes(int modeB, int modeO, int modeT) {
882 if (modeO == modeT)
883 return modeO;
884 if (modeB == modeO)
885
886 return (modeT == FileMode.MISSING.getBits()) ? modeO : modeT;
887 if (modeB == modeT)
888
889 return (modeO == FileMode.MISSING.getBits()) ? modeT : modeO;
890 return FileMode.MISSING.getBits();
891 }
892
893 private static RawText getRawText(ObjectId id, ObjectReader reader)
894 throws IOException {
895 if (id.equals(ObjectId.zeroId()))
896 return new RawText(new byte[] {});
897 return new RawText(reader.open(id, OBJ_BLOB).getCachedBytes());
898 }
899
900 private static boolean nonTree(final int mode) {
901 return mode != 0 && !FileMode.TREE.equals(mode);
902 }
903
904 private static boolean isGitLink(final int mode) {
905 return FileMode.GITLINK.equals(mode);
906 }
907
908 @Override
909 public ObjectId getResultTreeId() {
910 return (resultTree == null) ? null : resultTree.toObjectId();
911 }
912
913
914
915
916
917
918 public void setCommitNames(String[] commitNames) {
919 this.commitNames = commitNames;
920 }
921
922
923
924
925
926 public String[] getCommitNames() {
927 return commitNames;
928 }
929
930
931
932
933
934 public List<String> getUnmergedPaths() {
935 return unmergedPaths;
936 }
937
938
939
940
941
942
943
944 public List<String> getModifiedFiles() {
945 return modifiedFiles;
946 }
947
948
949
950
951
952
953
954 public Map<String, DirCacheEntry> getToBeCheckedOut() {
955 return toBeCheckedOut;
956 }
957
958
959
960
961 public Map<String, MergeResult<? extends Sequence>> getMergeResults() {
962 return mergeResults;
963 }
964
965
966
967
968
969
970 public Map<String, MergeFailureReason> getFailingPaths() {
971 return (failingPaths.size() == 0) ? null : failingPaths;
972 }
973
974
975
976
977
978
979
980
981 public boolean failed() {
982 return failingPaths.size() > 0;
983 }
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998 public void setDirCache(DirCache dc) {
999 this.dircache = dc;
1000 implicitDirCache = false;
1001 }
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014 public void setWorkingTreeIterator(WorkingTreeIterator workingTreeIterator) {
1015 this.workingTreeIterator = workingTreeIterator;
1016 }
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048 protected boolean mergeTrees(AbstractTreeIterator baseTree,
1049 RevTree headTree, RevTree mergeTree, boolean ignoreConflicts)
1050 throws IOException {
1051
1052 builder = dircache.builder();
1053 DirCacheBuildIterator buildIt = new DirCacheBuildIterator(builder);
1054
1055 tw = new NameConflictTreeWalk(db, reader);
1056 tw.addTree(baseTree);
1057 tw.addTree(headTree);
1058 tw.addTree(mergeTree);
1059 int dciPos = tw.addTree(buildIt);
1060 if (workingTreeIterator != null) {
1061 tw.addTree(workingTreeIterator);
1062 workingTreeIterator.setDirCacheIterator(tw, dciPos);
1063 } else {
1064 tw.setFilter(TreeFilter.ANY_DIFF);
1065 }
1066
1067 if (!mergeTreeWalk(tw, ignoreConflicts)) {
1068 return false;
1069 }
1070
1071 if (!inCore) {
1072
1073
1074
1075 checkout();
1076
1077
1078
1079
1080
1081 if (!builder.commit()) {
1082 cleanUp();
1083 throw new IndexWriteException();
1084 }
1085 builder = null;
1086
1087 } else {
1088 builder.finish();
1089 builder = null;
1090 }
1091
1092 if (getUnmergedPaths().isEmpty() && !failed()) {
1093 resultTree = dircache.writeTree(getObjectInserter());
1094 return true;
1095 } else {
1096 resultTree = null;
1097 return false;
1098 }
1099 }
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113 protected boolean mergeTreeWalk(TreeWalk treeWalk, boolean ignoreConflicts)
1114 throws IOException {
1115 boolean hasWorkingTreeIterator = tw.getTreeCount() > T_FILE;
1116 boolean hasAttributeNodeProvider = treeWalk
1117 .getAttributesNodeProvider() != null;
1118 while (treeWalk.next()) {
1119 if (!processEntry(
1120 treeWalk.getTree(T_BASE, CanonicalTreeParser.class),
1121 treeWalk.getTree(T_OURS, CanonicalTreeParser.class),
1122 treeWalk.getTree(T_THEIRS, CanonicalTreeParser.class),
1123 treeWalk.getTree(T_INDEX, DirCacheBuildIterator.class),
1124 hasWorkingTreeIterator ? treeWalk.getTree(T_FILE,
1125 WorkingTreeIterator.class) : null,
1126 ignoreConflicts, hasAttributeNodeProvider
1127 ? treeWalk.getAttributes() : new Attributes())) {
1128 cleanUp();
1129 return false;
1130 }
1131 if (treeWalk.isSubtree() && enterSubtree)
1132 treeWalk.enterSubtree();
1133 }
1134 return true;
1135 }
1136 }