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 @Deprecated
494 protected boolean processEntry(CanonicalTreeParser base,
495 CanonicalTreeParser ours, CanonicalTreeParser theirs,
496 DirCacheBuildIterator index, WorkingTreeIterator work,
497 boolean ignoreConflicts) throws MissingObjectException,
498 IncorrectObjectTypeException, CorruptObjectException, IOException {
499 return processEntry(base, ours, theirs, index, work, ignoreConflicts,
500 null);
501 }
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550 protected boolean processEntry(CanonicalTreeParser base,
551 CanonicalTreeParser ours, CanonicalTreeParser theirs,
552 DirCacheBuildIterator index, WorkingTreeIterator work,
553 boolean ignoreConflicts, Attributes attributes)
554 throws MissingObjectException, IncorrectObjectTypeException,
555 CorruptObjectException, IOException {
556 enterSubtree = true;
557 final int modeO = tw.getRawMode(T_OURS);
558 final int modeT = tw.getRawMode(T_THEIRS);
559 final int modeB = tw.getRawMode(T_BASE);
560
561 if (modeO == 0 && modeT == 0 && modeB == 0)
562
563 return true;
564
565 if (isIndexDirty())
566 return false;
567
568 DirCacheEntry ourDce = null;
569
570 if (index == null || index.getDirCacheEntry() == null) {
571
572
573 if (nonTree(modeO)) {
574 ourDce = new DirCacheEntry(tw.getRawPath());
575 ourDce.setObjectId(tw.getObjectId(T_OURS));
576 ourDce.setFileMode(tw.getFileMode(T_OURS));
577 }
578 } else {
579 ourDce = index.getDirCacheEntry();
580 }
581
582 if (nonTree(modeO) && nonTree(modeT) && tw.idEqual(T_OURS, T_THEIRS)) {
583
584 if (modeO == modeT) {
585
586
587
588 keep(ourDce);
589
590 return true;
591 } else {
592
593
594
595 int newMode = mergeFileModes(modeB, modeO, modeT);
596 if (newMode != FileMode.MISSING.getBits()) {
597 if (newMode == modeO)
598
599 keep(ourDce);
600 else {
601
602
603 if (isWorktreeDirty(work, ourDce))
604 return false;
605
606
607 DirCacheEntry e = add(tw.getRawPath(), theirs,
608 DirCacheEntry.STAGE_0, 0, 0);
609 toBeCheckedOut.put(tw.getPathString(), e);
610 }
611 return true;
612 } else {
613
614
615 add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
616 add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
617 add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
618 unmergedPaths.add(tw.getPathString());
619 mergeResults.put(
620 tw.getPathString(),
621 new MergeResult<>(Collections
622 .<RawText> emptyList()));
623 }
624 return true;
625 }
626 }
627
628 if (modeB == modeT && tw.idEqual(T_BASE, T_THEIRS)) {
629
630
631 if (ourDce != null)
632 keep(ourDce);
633
634 return true;
635 }
636
637 if (modeB == modeO && tw.idEqual(T_BASE, T_OURS)) {
638
639
640
641
642 if (isWorktreeDirty(work, ourDce))
643 return false;
644 if (nonTree(modeT)) {
645
646
647
648 DirCacheEntry e = add(tw.getRawPath(), theirs,
649 DirCacheEntry.STAGE_0, 0, 0);
650 if (e != null)
651 toBeCheckedOut.put(tw.getPathString(), e);
652 return true;
653 } else {
654
655
656
657
658
659 if (tw.getTreeCount() > T_FILE && tw.getRawMode(T_FILE) == 0)
660 return true;
661 toBeDeleted.add(tw.getPathString());
662 return true;
663 }
664 }
665
666 if (tw.isSubtree()) {
667
668
669
670
671 if (nonTree(modeO) && !nonTree(modeT)) {
672 if (nonTree(modeB))
673 add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
674 add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
675 unmergedPaths.add(tw.getPathString());
676 enterSubtree = false;
677 return true;
678 }
679 if (nonTree(modeT) && !nonTree(modeO)) {
680 if (nonTree(modeB))
681 add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
682 add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
683 unmergedPaths.add(tw.getPathString());
684 enterSubtree = false;
685 return true;
686 }
687
688
689
690
691
692 if (!nonTree(modeO))
693 return true;
694
695
696
697 }
698
699 if (nonTree(modeO) && nonTree(modeT)) {
700
701 if (isWorktreeDirty(work, ourDce))
702 return false;
703
704
705 if (isGitLink(modeO) || isGitLink(modeT)
706 || !attributes.canBeContentMerged()) {
707 add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
708 add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
709 add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
710 unmergedPaths.add(tw.getPathString());
711 return true;
712 }
713
714 MergeResult<RawText> result = contentMerge(base, ours, theirs);
715 if (ignoreConflicts) {
716 result.setContainsConflicts(false);
717 }
718 updateIndex(base, ours, theirs, result);
719 if (result.containsConflicts() && !ignoreConflicts)
720 unmergedPaths.add(tw.getPathString());
721 modifiedFiles.add(tw.getPathString());
722 } else if (modeO != modeT) {
723
724 if (((modeO != 0 && !tw.idEqual(T_BASE, T_OURS)) || (modeT != 0 && !tw
725 .idEqual(T_BASE, T_THEIRS)))) {
726
727 add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
728 add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
729 DirCacheEntry e = add(tw.getRawPath(), theirs,
730 DirCacheEntry.STAGE_3, 0, 0);
731
732
733 if (modeO == 0) {
734
735 if (isWorktreeDirty(work, ourDce))
736 return false;
737 if (nonTree(modeT)) {
738 if (e != null)
739 toBeCheckedOut.put(tw.getPathString(), e);
740 }
741 }
742
743 unmergedPaths.add(tw.getPathString());
744
745
746 mergeResults.put(tw.getPathString(),
747 contentMerge(base, ours, theirs));
748 }
749 }
750 return true;
751 }
752
753
754
755
756
757
758
759
760
761
762
763
764
765 private MergeResult<RawText> contentMerge(CanonicalTreeParser base,
766 CanonicalTreeParser ours, CanonicalTreeParser theirs)
767 throws IOException {
768 RawText baseText = base == null ? RawText.EMPTY_TEXT : getRawText(
769 base.getEntryObjectId(), reader);
770 RawText ourText = ours == null ? RawText.EMPTY_TEXT : getRawText(
771 ours.getEntryObjectId(), reader);
772 RawText theirsText = theirs == null ? RawText.EMPTY_TEXT : getRawText(
773 theirs.getEntryObjectId(), reader);
774 return (mergeAlgorithm.merge(RawTextComparator.DEFAULT, baseText,
775 ourText, theirsText));
776 }
777
778 private boolean isIndexDirty() {
779 if (inCore)
780 return false;
781
782 final int modeI = tw.getRawMode(T_INDEX);
783 final int modeO = tw.getRawMode(T_OURS);
784
785
786 final boolean isDirty = nonTree(modeI)
787 && !(modeO == modeI && tw.idEqual(T_INDEX, T_OURS));
788 if (isDirty)
789 failingPaths
790 .put(tw.getPathString(), MergeFailureReason.DIRTY_INDEX);
791 return isDirty;
792 }
793
794 private boolean isWorktreeDirty(WorkingTreeIterator work,
795 DirCacheEntry ourDce) throws IOException {
796 if (work == null)
797 return false;
798
799 final int modeF = tw.getRawMode(T_FILE);
800 final int modeO = tw.getRawMode(T_OURS);
801
802
803 boolean isDirty;
804 if (ourDce != null)
805 isDirty = work.isModified(ourDce, true, reader);
806 else {
807 isDirty = work.isModeDifferent(modeO);
808 if (!isDirty && nonTree(modeF))
809 isDirty = !tw.idEqual(T_FILE, T_OURS);
810 }
811
812
813 if (isDirty && modeF == FileMode.TYPE_TREE
814 && modeO == FileMode.TYPE_MISSING)
815 isDirty = false;
816 if (isDirty)
817 failingPaths.put(tw.getPathString(),
818 MergeFailureReason.DIRTY_WORKTREE);
819 return isDirty;
820 }
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835 private void updateIndex(CanonicalTreeParser base,
836 CanonicalTreeParser ours, CanonicalTreeParser theirs,
837 MergeResult<RawText> result) throws FileNotFoundException,
838 IOException {
839 File mergedFile = !inCore ? writeMergedFile(result) : null;
840
841 if (result.containsConflicts()) {
842
843
844
845 add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
846 add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
847 add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
848 mergeResults.put(tw.getPathString(), result);
849 return;
850 }
851
852
853
854 DirCacheEntry dce = new DirCacheEntry(tw.getPathString());
855
856
857
858 int newMode = mergeFileModes(
859 tw.getRawMode(0),
860 tw.getRawMode(1),
861 tw.getRawMode(2));
862 dce.setFileMode(newMode == FileMode.MISSING.getBits()
863 ? FileMode.REGULAR_FILE
864 : FileMode.fromBits(newMode));
865 if (mergedFile != null) {
866 long len = mergedFile.length();
867 dce.setLastModified(FS.DETECTED.lastModified(mergedFile));
868 dce.setLength((int) len);
869 InputStream is = new FileInputStream(mergedFile);
870 try {
871 dce.setObjectId(getObjectInserter().insert(OBJ_BLOB, len, is));
872 } finally {
873 is.close();
874 }
875 } else
876 dce.setObjectId(insertMergeResult(result));
877 builder.add(dce);
878 }
879
880
881
882
883
884
885
886
887
888
889 private File writeMergedFile(MergeResult<RawText> result)
890 throws FileNotFoundException, IOException {
891 File workTree = nonNullRepo().getWorkTree();
892 FS fs = nonNullRepo().getFS();
893 File of = new File(workTree, tw.getPathString());
894 File parentFolder = of.getParentFile();
895 if (!fs.exists(parentFolder))
896 parentFolder.mkdirs();
897 try (OutputStream os = new BufferedOutputStream(
898 new FileOutputStream(of))) {
899 new MergeFormatter().formatMerge(os, result,
900 Arrays.asList(commitNames), CHARACTER_ENCODING);
901 }
902 return of;
903 }
904
905 private ObjectId insertMergeResult(MergeResult<RawText> result)
906 throws IOException {
907 TemporaryBuffer.LocalFile buf = new TemporaryBuffer.LocalFile(
908 db != null ? nonNullRepo().getDirectory() : null, inCoreLimit);
909 try {
910 new MergeFormatter().formatMerge(buf, result,
911 Arrays.asList(commitNames), CHARACTER_ENCODING);
912 buf.close();
913 try (InputStream in = buf.openInputStream()) {
914 return getObjectInserter().insert(OBJ_BLOB, buf.length(), in);
915 }
916 } finally {
917 buf.destroy();
918 }
919 }
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937 private int mergeFileModes(int modeB, int modeO, int modeT) {
938 if (modeO == modeT)
939 return modeO;
940 if (modeB == modeO)
941
942 return (modeT == FileMode.MISSING.getBits()) ? modeO : modeT;
943 if (modeB == modeT)
944
945 return (modeO == FileMode.MISSING.getBits()) ? modeT : modeO;
946 return FileMode.MISSING.getBits();
947 }
948
949 private static RawText getRawText(ObjectId id, ObjectReader reader)
950 throws IOException {
951 if (id.equals(ObjectId.zeroId()))
952 return new RawText(new byte[] {});
953 return new RawText(reader.open(id, OBJ_BLOB).getCachedBytes());
954 }
955
956 private static boolean nonTree(final int mode) {
957 return mode != 0 && !FileMode.TREE.equals(mode);
958 }
959
960 private static boolean isGitLink(final int mode) {
961 return FileMode.GITLINK.equals(mode);
962 }
963
964 @Override
965 public ObjectId getResultTreeId() {
966 return (resultTree == null) ? null : resultTree.toObjectId();
967 }
968
969
970
971
972
973
974 public void setCommitNames(String[] commitNames) {
975 this.commitNames = commitNames;
976 }
977
978
979
980
981
982 public String[] getCommitNames() {
983 return commitNames;
984 }
985
986
987
988
989
990 public List<String> getUnmergedPaths() {
991 return unmergedPaths;
992 }
993
994
995
996
997
998
999
1000 public List<String> getModifiedFiles() {
1001 return modifiedFiles;
1002 }
1003
1004
1005
1006
1007
1008
1009
1010 public Map<String, DirCacheEntry> getToBeCheckedOut() {
1011 return toBeCheckedOut;
1012 }
1013
1014
1015
1016
1017 public Map<String, MergeResult<? extends Sequence>> getMergeResults() {
1018 return mergeResults;
1019 }
1020
1021
1022
1023
1024
1025
1026 public Map<String, MergeFailureReason> getFailingPaths() {
1027 return (failingPaths.size() == 0) ? null : failingPaths;
1028 }
1029
1030
1031
1032
1033
1034
1035
1036
1037 public boolean failed() {
1038 return failingPaths.size() > 0;
1039 }
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054 public void setDirCache(DirCache dc) {
1055 this.dircache = dc;
1056 implicitDirCache = false;
1057 }
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070 public void setWorkingTreeIterator(WorkingTreeIterator workingTreeIterator) {
1071 this.workingTreeIterator = workingTreeIterator;
1072 }
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104 protected boolean mergeTrees(AbstractTreeIterator baseTree,
1105 RevTree headTree, RevTree mergeTree, boolean ignoreConflicts)
1106 throws IOException {
1107
1108 builder = dircache.builder();
1109 DirCacheBuildIterator buildIt = new DirCacheBuildIterator(builder);
1110
1111 tw = new NameConflictTreeWalk(db, reader);
1112 tw.addTree(baseTree);
1113 tw.addTree(headTree);
1114 tw.addTree(mergeTree);
1115 int dciPos = tw.addTree(buildIt);
1116 if (workingTreeIterator != null) {
1117 tw.addTree(workingTreeIterator);
1118 workingTreeIterator.setDirCacheIterator(tw, dciPos);
1119 } else {
1120 tw.setFilter(TreeFilter.ANY_DIFF);
1121 }
1122
1123 if (!mergeTreeWalk(tw, ignoreConflicts)) {
1124 return false;
1125 }
1126
1127 if (!inCore) {
1128
1129
1130
1131 checkout();
1132
1133
1134
1135
1136
1137 if (!builder.commit()) {
1138 cleanUp();
1139 throw new IndexWriteException();
1140 }
1141 builder = null;
1142
1143 } else {
1144 builder.finish();
1145 builder = null;
1146 }
1147
1148 if (getUnmergedPaths().isEmpty() && !failed()) {
1149 resultTree = dircache.writeTree(getObjectInserter());
1150 return true;
1151 } else {
1152 resultTree = null;
1153 return false;
1154 }
1155 }
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169 protected boolean mergeTreeWalk(TreeWalk treeWalk, boolean ignoreConflicts)
1170 throws IOException {
1171 boolean hasWorkingTreeIterator = tw.getTreeCount() > T_FILE;
1172 boolean hasAttributeNodeProvider = treeWalk
1173 .getAttributesNodeProvider() != null;
1174 while (treeWalk.next()) {
1175 if (!processEntry(
1176 treeWalk.getTree(T_BASE, CanonicalTreeParser.class),
1177 treeWalk.getTree(T_OURS, CanonicalTreeParser.class),
1178 treeWalk.getTree(T_THEIRS, CanonicalTreeParser.class),
1179 treeWalk.getTree(T_INDEX, DirCacheBuildIterator.class),
1180 hasWorkingTreeIterator ? treeWalk.getTree(T_FILE,
1181 WorkingTreeIterator.class) : null,
1182 ignoreConflicts, hasAttributeNodeProvider
1183 ? treeWalk.getAttributes() : new Attributes())) {
1184 cleanUp();
1185 return false;
1186 }
1187 if (treeWalk.isSubtree() && enterSubtree)
1188 treeWalk.enterSubtree();
1189 }
1190 return true;
1191 }
1192 }