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