~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/ngit/NGit/NGit.Merge/ResolveMerger.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
95
95
                private IDictionary<string, DirCacheEntry> toBeCheckedOut = new Dictionary<string
96
96
                        , DirCacheEntry>();
97
97
 
 
98
                private IList<string> toBeDeleted = new AList<string>();
 
99
 
98
100
                private IDictionary<string, MergeResult<Sequence>> mergeResults = new Dictionary<
99
101
                        string, MergeResult<Sequence>>();
100
102
 
101
103
                private IDictionary<string, ResolveMerger.MergeFailureReason> failingPaths = new 
102
104
                        Dictionary<string, ResolveMerger.MergeFailureReason>();
103
105
 
104
 
                private ObjectInserter oi;
105
 
 
106
106
                private bool enterSubtree;
107
107
 
108
108
                private bool inCore;
122
122
                                .HISTOGRAM);
123
123
                        mergeAlgorithm = new MergeAlgorithm(DiffAlgorithm.GetAlgorithm(diffAlg));
124
124
                        commitNames = new string[] { "BASE", "OURS", "THEIRS" };
125
 
                        oi = GetObjectInserter();
126
125
                        this.inCore = inCore;
127
126
                        if (inCore)
128
127
                        {
174
173
                                }
175
174
                                if (!inCore)
176
175
                                {
 
176
                                        // No problem found. The only thing left to be done is to
 
177
                                        // checkout all files from "theirs" which have been selected to
 
178
                                        // go into the new index.
 
179
                                        Checkout();
177
180
                                        // All content-merges are successfully done. If we can now write the
178
181
                                        // new index we are on quite safe ground. Even if the checkout of
179
182
                                        // files coming from "theirs" fails the user can work around such
184
187
                                                throw new IndexWriteException();
185
188
                                        }
186
189
                                        builder = null;
187
 
                                        // No problem found. The only thing left to be done is to checkout
188
 
                                        // all files from "theirs" which have been selected to go into the
189
 
                                        // new index.
190
 
                                        Checkout();
191
190
                                }
192
191
                                else
193
192
                                {
194
193
                                        builder.Finish();
195
194
                                        builder = null;
196
195
                                }
197
 
                                if (GetUnmergedPaths().IsEmpty())
 
196
                                if (GetUnmergedPaths().IsEmpty() && !Failed())
198
197
                                {
199
 
                                        resultTree = dircache.WriteTree(oi);
 
198
                                        resultTree = dircache.WriteTree(GetObjectInserter());
200
199
                                        return true;
201
200
                                }
202
201
                                else
224
223
                                foreach (KeyValuePair<string, DirCacheEntry> entry in toBeCheckedOut.EntrySet())
225
224
                                {
226
225
                                        FilePath f = new FilePath(db.WorkTree, entry.Key);
227
 
                                        if (entry.Value != null)
228
 
                                        {
229
 
                                                CreateDir(f.GetParentFile());
230
 
                                                DirCacheCheckout.CheckoutEntry(db, f, entry.Value, r);
231
 
                                        }
232
 
                                        else
233
 
                                        {
234
 
                                                if (!f.Delete())
235
 
                                                {
236
 
                                                        failingPaths.Put(entry.Key, ResolveMerger.MergeFailureReason.COULD_NOT_DELETE);
237
 
                                                }
238
 
                                        }
 
226
                                        CreateDir(f.GetParentFile());
 
227
                                        DirCacheCheckout.CheckoutEntry(db, f, entry.Value, r);
239
228
                                        modifiedFiles.AddItem(entry.Key);
240
229
                                }
 
230
                                // Iterate in reverse so that "folder/file" is deleted before
 
231
                                // "folder". Otherwise this could result in a failing path because
 
232
                                // of a non-empty directory, for which delete() would fail.
 
233
                                for (int i = toBeDeleted.Count - 1; i >= 0; i--)
 
234
                                {
 
235
                                        string fileName = toBeDeleted[i];
 
236
                                        FilePath f = new FilePath(db.WorkTree, fileName);
 
237
                                        if (!f.Delete())
 
238
                                        {
 
239
                                                failingPaths.Put(fileName, ResolveMerger.MergeFailureReason.COULD_NOT_DELETE);
 
240
                                        }
 
241
                                        modifiedFiles.AddItem(fileName);
 
242
                                }
241
243
                        }
242
244
                        finally
243
245
                        {
310
312
                /// <param name="path"></param>
311
313
                /// <param name="p"></param>
312
314
                /// <param name="stage"></param>
 
315
                /// <param name="lastMod"></param>
 
316
                /// <param name="len"></param>
313
317
                /// <returns>the entry which was added to the index</returns>
314
 
                private DirCacheEntry Add(byte[] path, CanonicalTreeParser p, int stage)
 
318
                private DirCacheEntry Add(byte[] path, CanonicalTreeParser p, int stage, long lastMod
 
319
                        , long len)
315
320
                {
316
321
                        if (p != null && !p.EntryFileMode.Equals(FileMode.TREE))
317
322
                        {
318
323
                                DirCacheEntry e = new DirCacheEntry(path, stage);
319
324
                                e.FileMode = p.EntryFileMode;
320
325
                                e.SetObjectId(p.EntryObjectId);
 
326
                                e.LastModified = lastMod;
 
327
                                e.SetLength(len);
321
328
                                builder.Add(e);
322
329
                                return e;
323
330
                        }
324
331
                        return null;
325
332
                }
326
333
 
 
334
                /// <summary>
 
335
                /// adds a entry to the index builder which is a copy of the specified
 
336
                /// DirCacheEntry
 
337
                /// </summary>
 
338
                /// <param name="e">the entry which should be copied</param>
 
339
                /// <returns>the entry which was added to the index</returns>
 
340
                private DirCacheEntry Keep(DirCacheEntry e)
 
341
                {
 
342
                        DirCacheEntry newEntry = new DirCacheEntry(e.PathString, e.Stage);
 
343
                        newEntry.FileMode = e.FileMode;
 
344
                        newEntry.SetObjectId(e.GetObjectId());
 
345
                        newEntry.LastModified = e.LastModified;
 
346
                        newEntry.SetLength(e.Length);
 
347
                        builder.Add(newEntry);
 
348
                        return newEntry;
 
349
                }
 
350
 
327
351
                /// <summary>Processes one path and tries to merge.</summary>
328
352
                /// <remarks>
329
353
                /// Processes one path and tries to merge. This method will do all do all
383
407
                        {
384
408
                                return false;
385
409
                        }
 
410
                        DirCacheEntry ourDce = null;
 
411
                        if (index == null || index.GetDirCacheEntry() == null)
 
412
                        {
 
413
                                // create a fake DCE, but only if ours is valid. ours is kept only
 
414
                                // in case it is valid, so a null ourDce is ok in all other cases.
 
415
                                if (NonTree(modeO))
 
416
                                {
 
417
                                        ourDce = new DirCacheEntry(tw.RawPath);
 
418
                                        ourDce.SetObjectId(tw.GetObjectId(T_OURS));
 
419
                                        ourDce.FileMode = tw.GetFileMode(T_OURS);
 
420
                                }
 
421
                        }
 
422
                        else
 
423
                        {
 
424
                                ourDce = index.GetDirCacheEntry();
 
425
                        }
386
426
                        if (NonTree(modeO) && NonTree(modeT) && tw.IdEqual(T_OURS, T_THEIRS))
387
427
                        {
388
428
                                // OURS and THEIRS have equal content. Check the file mode
389
429
                                if (modeO == modeT)
390
430
                                {
391
431
                                        // content and mode of OURS and THEIRS are equal: it doesn't
392
 
                                        // matter which one we choose. OURS is chosen.
393
 
                                        Add(tw.RawPath, ours, DirCacheEntry.STAGE_0);
 
432
                                        // matter which one we choose. OURS is chosen. Since the index
 
433
                                        // is clean (the index matches already OURS) we can keep the existing one
 
434
                                        Keep(ourDce);
394
435
                                        // no checkout needed!
395
436
                                        return true;
396
437
                                }
405
446
                                                if (newMode == modeO)
406
447
                                                {
407
448
                                                        // ours version is preferred
408
 
                                                        Add(tw.RawPath, ours, DirCacheEntry.STAGE_0);
 
449
                                                        Keep(ourDce);
409
450
                                                }
410
451
                                                else
411
452
                                                {
412
453
                                                        // the preferred version THEIRS has a different mode
413
454
                                                        // than ours. Check it out!
414
 
                                                        if (IsWorktreeDirty())
 
455
                                                        if (IsWorktreeDirty(work))
415
456
                                                        {
416
457
                                                                return false;
417
458
                                                        }
418
 
                                                        DirCacheEntry e = Add(tw.RawPath, theirs, DirCacheEntry.STAGE_0);
 
459
                                                        // we know about length and lastMod only after we have written the new content.
 
460
                                                        // This will happen later. Set these values to 0 for know.
 
461
                                                        DirCacheEntry e = Add(tw.RawPath, theirs, DirCacheEntry.STAGE_0, 0, 0);
419
462
                                                        toBeCheckedOut.Put(tw.PathString, e);
420
463
                                                }
421
464
                                                return true;
422
465
                                        }
423
466
                                        else
424
467
                                        {
425
 
                                                // FileModes are not mergeable. We found a conflict on modes
426
 
                                                Add(tw.RawPath, @base, DirCacheEntry.STAGE_1);
427
 
                                                Add(tw.RawPath, ours, DirCacheEntry.STAGE_2);
428
 
                                                Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3);
 
468
                                                // FileModes are not mergeable. We found a conflict on modes.
 
469
                                                // For conflicting entries we don't know lastModified and length.
 
470
                                                Add(tw.RawPath, @base, DirCacheEntry.STAGE_1, 0, 0);
 
471
                                                Add(tw.RawPath, ours, DirCacheEntry.STAGE_2, 0, 0);
 
472
                                                Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3, 0, 0);
429
473
                                                unmergedPaths.AddItem(tw.PathString);
430
474
                                                mergeResults.Put(tw.PathString, new MergeResult<RawText>(Sharpen.Collections.EmptyList
431
475
                                                        <RawText>()).Upcast ());
436
480
                        if (NonTree(modeO) && modeB == modeT && tw.IdEqual(T_BASE, T_THEIRS))
437
481
                        {
438
482
                                // THEIRS was not changed compared to BASE. All changes must be in
439
 
                                // OURS. OURS is chosen.
440
 
                                Add(tw.RawPath, ours, DirCacheEntry.STAGE_0);
 
483
                                // OURS. OURS is chosen. We can keep the existing entry.
 
484
                                Keep(ourDce);
441
485
                                // no checkout needed!
442
486
                                return true;
443
487
                        }
446
490
                                // OURS was not changed compared to BASE. All changes must be in
447
491
                                // THEIRS. THEIRS is chosen.
448
492
                                // Check worktree before checking out THEIRS
449
 
                                if (IsWorktreeDirty())
 
493
                                if (IsWorktreeDirty(work))
450
494
                                {
451
495
                                        return false;
452
496
                                }
453
497
                                if (NonTree(modeT))
454
498
                                {
455
 
                                        DirCacheEntry e = Add(tw.RawPath, theirs, DirCacheEntry.STAGE_0);
 
499
                                        // we know about length and lastMod only after we have written
 
500
                                        // the new content.
 
501
                                        // This will happen later. Set these values to 0 for know.
 
502
                                        DirCacheEntry e = Add(tw.RawPath, theirs, DirCacheEntry.STAGE_0, 0, 0);
456
503
                                        if (e != null)
457
504
                                        {
458
505
                                                toBeCheckedOut.Put(tw.PathString, e);
465
512
                                        {
466
513
                                                // we want THEIRS ... but THEIRS contains the deletion of the
467
514
                                                // file
468
 
                                                toBeCheckedOut.Put(tw.PathString, null);
 
515
                                                toBeDeleted.AddItem(tw.PathString);
469
516
                                                return true;
470
517
                                        }
471
518
                                }
480
527
                                {
481
528
                                        if (NonTree(modeB))
482
529
                                        {
483
 
                                                Add(tw.RawPath, @base, DirCacheEntry.STAGE_1);
 
530
                                                Add(tw.RawPath, @base, DirCacheEntry.STAGE_1, 0, 0);
484
531
                                        }
485
 
                                        Add(tw.RawPath, ours, DirCacheEntry.STAGE_2);
 
532
                                        Add(tw.RawPath, ours, DirCacheEntry.STAGE_2, 0, 0);
486
533
                                        unmergedPaths.AddItem(tw.PathString);
487
534
                                        enterSubtree = false;
488
535
                                        return true;
491
538
                                {
492
539
                                        if (NonTree(modeB))
493
540
                                        {
494
 
                                                Add(tw.RawPath, @base, DirCacheEntry.STAGE_1);
 
541
                                                Add(tw.RawPath, @base, DirCacheEntry.STAGE_1, 0, 0);
495
542
                                        }
496
 
                                        Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3);
 
543
                                        Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3, 0, 0);
497
544
                                        unmergedPaths.AddItem(tw.PathString);
498
545
                                        enterSubtree = false;
499
546
                                        return true;
512
559
                        if (NonTree(modeO) && NonTree(modeT))
513
560
                        {
514
561
                                // Check worktree before modifying files
515
 
                                if (IsWorktreeDirty())
 
562
                                if (IsWorktreeDirty(work))
516
563
                                {
517
564
                                        return false;
518
565
                                }
 
566
                                // Don't attempt to resolve submodule link conflicts
 
567
                                if (IsGitLink(modeO) || IsGitLink(modeT))
 
568
                                {
 
569
                                        Add(tw.RawPath, @base, DirCacheEntry.STAGE_1, 0, 0);
 
570
                                        Add(tw.RawPath, ours, DirCacheEntry.STAGE_2, 0, 0);
 
571
                                        Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3, 0, 0);
 
572
                                        unmergedPaths.AddItem(tw.PathString);
 
573
                                        return true;
 
574
                                }
519
575
                                MergeResult<RawText> result = ContentMerge(@base, ours, theirs);
520
576
                                FilePath of = WriteMergedFile(result);
521
577
                                UpdateIndex(@base, ours, theirs, result, of);
533
589
                                        if (((modeO != 0 && !tw.IdEqual(T_BASE, T_OURS)) || (modeT != 0 && !tw.IdEqual(T_BASE
534
590
                                                , T_THEIRS))))
535
591
                                        {
536
 
                                                Add(tw.RawPath, @base, DirCacheEntry.STAGE_1);
537
 
                                                Add(tw.RawPath, ours, DirCacheEntry.STAGE_2);
538
 
                                                DirCacheEntry e = Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3);
 
592
                                                Add(tw.RawPath, @base, DirCacheEntry.STAGE_1, 0, 0);
 
593
                                                Add(tw.RawPath, ours, DirCacheEntry.STAGE_2, 0, 0);
 
594
                                                DirCacheEntry e = Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3, 0, 0);
539
595
                                                // OURS was deleted checkout THEIRS
540
596
                                                if (modeO == 0)
541
597
                                                {
542
598
                                                        // Check worktree before checking out THEIRS
543
 
                                                        if (IsWorktreeDirty())
 
599
                                                        if (IsWorktreeDirty(work))
544
600
                                                        {
545
601
                                                                return false;
546
602
                                                        }
592
648
                        int modeI = tw.GetRawMode(T_INDEX);
593
649
                        int modeO = tw.GetRawMode(T_OURS);
594
650
                        // Index entry has to match ours to be considered clean
595
 
                        bool isDirty = NonTree(modeI) && !(tw.IdEqual(T_INDEX, T_OURS) && modeO == modeI);
 
651
                        bool isDirty = NonTree(modeI) && !(modeO == modeI && tw.IdEqual(T_INDEX, T_OURS));
596
652
                        if (isDirty)
597
653
                        {
598
654
                                failingPaths.Put(tw.PathString, ResolveMerger.MergeFailureReason.DIRTY_INDEX);
600
656
                        return isDirty;
601
657
                }
602
658
 
603
 
                private bool IsWorktreeDirty()
 
659
                private bool IsWorktreeDirty(WorkingTreeIterator work)
604
660
                {
605
 
                        if (inCore)
 
661
                        if (inCore || work == null)
606
662
                        {
607
663
                                return false;
608
664
                        }
609
665
                        int modeF = tw.GetRawMode(T_FILE);
610
666
                        int modeO = tw.GetRawMode(T_OURS);
611
667
                        // Worktree entry has to match ours to be considered clean
612
 
                        bool isDirty = NonTree(modeF) && !(tw.IdEqual(T_FILE, T_OURS) && modeO == modeF);
 
668
                        bool isDirty = work.IsModeDifferent(modeO);
 
669
                        if (!isDirty && NonTree(modeF))
 
670
                        {
 
671
                                isDirty = !tw.IdEqual(T_FILE, T_OURS);
 
672
                        }
613
673
                        if (isDirty)
614
674
                        {
615
675
                                failingPaths.Put(tw.PathString, ResolveMerger.MergeFailureReason.DIRTY_WORKTREE);
640
700
                                // a conflict occurred, the file will contain conflict markers
641
701
                                // the index will be populated with the three stages and only the
642
702
                                // workdir (if used) contains the halfways merged content
643
 
                                Add(tw.RawPath, @base, DirCacheEntry.STAGE_1);
644
 
                                Add(tw.RawPath, ours, DirCacheEntry.STAGE_2);
645
 
                                Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3);
 
703
                                Add(tw.RawPath, @base, DirCacheEntry.STAGE_1, 0, 0);
 
704
                                Add(tw.RawPath, ours, DirCacheEntry.STAGE_2, 0, 0);
 
705
                                Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3, 0, 0);
646
706
                                mergeResults.Put(tw.PathString, result.Upcast ());
647
707
                        }
648
708
                        else
661
721
                                InputStream @is = new FileInputStream(of);
662
722
                                try
663
723
                                {
664
 
                                        dce.SetObjectId(oi.Insert(Constants.OBJ_BLOB, of.Length(), @is));
 
724
                                        dce.SetObjectId(GetObjectInserter().Insert(Constants.OBJ_BLOB, of.Length(), @is));
665
725
                                }
666
726
                                finally
667
727
                                {
702
762
                                        throw new NGit.Errors.NotSupportedException();
703
763
                                }
704
764
                                of = new FilePath(workTree, tw.PathString);
 
765
                                FilePath parentFolder = of.GetParentFile();
 
766
                                if (!parentFolder.Exists())
 
767
                                {
 
768
                                        parentFolder.Mkdirs();
 
769
                                }
705
770
                                fos = new FileOutputStream(of);
706
771
                                try
707
772
                                {
787
852
                        return mode != 0 && !FileMode.TREE.Equals(mode);
788
853
                }
789
854
 
 
855
                private static bool IsGitLink(int mode)
 
856
                {
 
857
                        return FileMode.GITLINK.Equals(mode);
 
858
                }
 
859
 
790
860
                public override ObjectId GetResultTreeId()
791
861
                {
792
862
                        return (resultTree == null) ? null : resultTree.ToObjectId();