Beispiel #1
0
        internal MergeResult <Sequence> Upcast()
        {
            var r = new MergeResult <Sequence> (sequences.UpcastTo <S, Sequence> ());

            r.chunks            = chunks;
            r.containsConflicts = containsConflicts;
            return(r);
        }
Beispiel #2
0
        /// <summary>
        /// Formats the results of a merge of exactly two
        /// <see cref="NGit.Diff.RawText">NGit.Diff.RawText</see>
        /// objects in
        /// a Git conformant way. This convenience method accepts the names for the
        /// three sequences (base and the two merged sequences) as explicit
        /// parameters and doesn't require the caller to specify a List
        /// </summary>
        /// <param name="out">
        /// the
        /// <see cref="Sharpen.OutputStream">Sharpen.OutputStream</see>
        /// where to write the textual
        /// presentation
        /// </param>
        /// <param name="res">the merge result which should be presented</param>
        /// <param name="baseName">the name ranges from the base should get</param>
        /// <param name="oursName">the name ranges from ours should get</param>
        /// <param name="theirsName">the name ranges from theirs should get</param>
        /// <param name="charsetName">
        /// the name of the characterSet used when writing conflict
        /// metadata
        /// </param>
        /// <exception cref="System.IO.IOException">System.IO.IOException</exception>
        public virtual void FormatMerge(OutputStream @out, MergeResult <RawText> res, string baseName
                                        , string oursName, string theirsName, string charsetName)
        {
            IList <string> names = new AList <string>(3);

            names.AddItem(baseName);
            names.AddItem(oursName);
            names.AddItem(theirsName);
            FormatMerge(@out, res, names, charsetName);
        }
Beispiel #3
0
        /// <summary>Writes merged file content to the working tree.</summary>
        /// <remarks>
        /// Writes merged file content to the working tree. In case
        /// <see cref="inCore">inCore</see>
        /// is set and we don't have a working tree the content is written to a
        /// temporary file
        /// </remarks>
        /// <param name="result">the result of the content merge</param>
        /// <returns>the file to which the merged content was written</returns>
        /// <exception cref="System.IO.FileNotFoundException">System.IO.FileNotFoundException
        ///     </exception>
        /// <exception cref="System.IO.IOException">System.IO.IOException</exception>
        private FilePath WriteMergedFile(MergeResult <RawText> result)
        {
            MergeFormatter   fmt = new MergeFormatter();
            FilePath         of  = null;
            FileOutputStream fos;

            if (!inCore)
            {
                FilePath workTree = db.WorkTree;
                if (workTree == null)
                {
                    // TODO: This should be handled by WorkingTreeIterators which
                    // support write operations
                    throw new NGit.Errors.NotSupportedException();
                }
                of = new FilePath(workTree, tw.PathString);
                FilePath parentFolder = of.GetParentFile();
                if (!parentFolder.Exists())
                {
                    parentFolder.Mkdirs();
                }
                fos = new FileOutputStream(of);
                try
                {
                    fmt.FormatMerge(fos, result, Arrays.AsList(commitNames), Constants.CHARACTER_ENCODING
                                    );
                }
                finally
                {
                    fos.Close();
                }
            }
            else
            {
                if (!result.ContainsConflicts())
                {
                    // When working inCore, only trivial merges can be handled,
                    // so we generate objects only in conflict free cases
                    of  = FilePath.CreateTempFile("merge_", "_temp", null);
                    fos = new FileOutputStream(of);
                    try
                    {
                        fmt.FormatMerge(fos, result, Arrays.AsList(commitNames), Constants.CHARACTER_ENCODING
                                        );
                    }
                    finally
                    {
                        fos.Close();
                    }
                }
            }
            return(of);
        }
Beispiel #4
0
        /// <summary>
        /// Formats the results of a merge of
        /// <see cref="NGit.Diff.RawText">NGit.Diff.RawText</see>
        /// objects in a Git
        /// conformant way. This method also assumes that the
        /// <see cref="NGit.Diff.RawText">NGit.Diff.RawText</see>
        /// objects
        /// being merged are line oriented files which use LF as delimiter. This
        /// method will also use LF to separate chunks and conflict metadata,
        /// therefore it fits only to texts that are LF-separated lines.
        /// </summary>
        /// <param name="out">the outputstream where to write the textual presentation</param>
        /// <param name="res">the merge result which should be presented</param>
        /// <param name="seqName">
        /// When a conflict is reported each conflicting range will get a
        /// name. This name is following the "<&lt;&lt;&lt;&lt;&lt;&lt; " or ">&gt;&gt;&gt;&gt;&gt;&gt; "
        /// conflict markers. The names for the sequences are given in
        /// this list
        /// </param>
        /// <param name="charsetName">
        /// the name of the characterSet used when writing conflict
        /// metadata
        /// </param>
        /// <exception cref="System.IO.IOException">System.IO.IOException</exception>
        public virtual void FormatMerge(OutputStream @out, MergeResult <RawText> res, IList
                                        <string> seqName, string charsetName)
        {
            string lastConflictingName = null;
            // is set to non-null whenever we are
            // in a conflict
            bool threeWayMerge = (res.GetSequences().Count == 3);

            foreach (MergeChunk chunk in res)
            {
                RawText seq = res.GetSequences()[chunk.GetSequenceIndex()];
                if (lastConflictingName != null && chunk.GetConflictState() != MergeChunk.ConflictState
                    .NEXT_CONFLICTING_RANGE)
                {
                    // found the end of an conflict
                    @out.Write(Sharpen.Runtime.GetBytesForString((">>>>>>> " + lastConflictingName +
                                                                  "\n"), charsetName));
                    lastConflictingName = null;
                }
                if (chunk.GetConflictState() == MergeChunk.ConflictState.FIRST_CONFLICTING_RANGE)
                {
                    // found the start of an conflict
                    @out.Write(Sharpen.Runtime.GetBytesForString(("<<<<<<< " + seqName[chunk.GetSequenceIndex
                                                                                           ()] + "\n"), charsetName));
                    lastConflictingName = seqName[chunk.GetSequenceIndex()];
                }
                else
                {
                    if (chunk.GetConflictState() == MergeChunk.ConflictState.NEXT_CONFLICTING_RANGE)
                    {
                        // found another conflicting chunk
                        lastConflictingName = seqName[chunk.GetSequenceIndex()];
                        @out.Write(Sharpen.Runtime.GetBytesForString((threeWayMerge ? "=======\n" : "======= "
                                                                      + lastConflictingName + "\n"), charsetName));
                    }
                }
                // the lines with conflict-metadata are written. Now write the chunk
                for (int i = chunk.GetBegin(); i < chunk.GetEnd(); i++)
                {
                    seq.WriteLine(@out, i);
                    @out.Write('\n');
                }
            }
            // one possible leftover: if the merge result ended with a conflict we
            // have to close the last conflict here
            if (lastConflictingName != null)
            {
                @out.Write(Sharpen.Runtime.GetBytesForString((">>>>>>> " + lastConflictingName +
                                                              "\n"), charsetName));
            }
        }
Beispiel #5
0
 /// <summary>Updates the index after a content merge has happened.</summary>
 /// <remarks>
 /// Updates the index after a content merge has happened. If no conflict has
 /// occurred this includes persisting the merged content to the object
 /// database. In case of conflicts this method takes care to write the
 /// correct stages to the index.
 /// </remarks>
 /// <param name="base"></param>
 /// <param name="ours"></param>
 /// <param name="theirs"></param>
 /// <param name="result"></param>
 /// <param name="of"></param>
 /// <exception cref="System.IO.FileNotFoundException">System.IO.FileNotFoundException
 ///     </exception>
 /// <exception cref="System.IO.IOException">System.IO.IOException</exception>
 private void UpdateIndex(CanonicalTreeParser @base, CanonicalTreeParser ours, CanonicalTreeParser
                          theirs, MergeResult <RawText> result, FilePath of)
 {
     if (result.ContainsConflicts())
     {
         // a conflict occurred, the file will contain conflict markers
         // the index will be populated with the three stages and only the
         // workdir (if used) contains the halfways merged content
         Add(tw.RawPath, @base, DirCacheEntry.STAGE_1, 0, 0);
         Add(tw.RawPath, ours, DirCacheEntry.STAGE_2, 0, 0);
         Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3, 0, 0);
         mergeResults.Put(tw.PathString, result.Upcast());
     }
     else
     {
         // no conflict occurred, the file will contain fully merged content.
         // the index will be populated with the new merged version
         DirCacheEntry dce     = new DirCacheEntry(tw.PathString);
         int           newMode = MergeFileModes(tw.GetRawMode(0), tw.GetRawMode(1), tw.GetRawMode(2)
                                                );
         // set the mode for the new content. Fall back to REGULAR_FILE if
         // you can't merge modes of OURS and THEIRS
         dce.FileMode = (newMode == FileMode.MISSING.GetBits()) ? FileMode.REGULAR_FILE :
                        FileMode.FromBits(newMode);
         dce.LastModified = of.LastModified();
         dce.SetLength((int)of.Length());
         InputStream @is = new FileInputStream(of);
         try
         {
             dce.SetObjectId(GetObjectInserter().Insert(Constants.OBJ_BLOB, of.Length(), @is));
         }
         finally
         {
             @is.Close();
             if (inCore)
             {
                 FileUtils.Delete(of);
             }
         }
         builder.Add(dce);
     }
 }
        // An special edit which acts as a sentinel value by marking the end the
        // list of edits
        /// <summary>Does the three way merge between a common base and two sequences.</summary>
        /// <remarks>Does the three way merge between a common base and two sequences.</remarks>
        /// <?></?>
        /// <param name="cmp">comparison method for this execution.</param>
        /// <param name="base">the common base sequence</param>
        /// <param name="ours">the first sequence to be merged</param>
        /// <param name="theirs">the second sequence to be merged</param>
        /// <returns>the resulting content</returns>
        public MergeResult <S> Merge <S>(SequenceComparator <S> cmp, S @base, S ours, S theirs
                                         ) where S : Sequence
        {
            IList <S> sequences = new AList <S>(3);

            sequences.AddItem(@base);
            sequences.AddItem(ours);
            sequences.AddItem(theirs);
            MergeResult <S> result = new MergeResult <S>(sequences);

            if (ours.Size() == 0)
            {
                if (theirs.Size() != 0)
                {
                    EditList theirsEdits = diffAlg.Diff(cmp, @base, theirs);
                    if (!theirsEdits.IsEmpty())
                    {
                        // we deleted, they modified -> Let their complete content
                        // conflict with empty text
                        result.Add(1, 0, 0, MergeChunk.ConflictState.FIRST_CONFLICTING_RANGE);
                        result.Add(2, 0, theirs.Size(), MergeChunk.ConflictState.NEXT_CONFLICTING_RANGE);
                    }
                    else
                    {
                        // we deleted, they didn't modify -> Let our deletion win
                        result.Add(1, 0, 0, MergeChunk.ConflictState.NO_CONFLICT);
                    }
                }
                else
                {
                    // we and they deleted -> return a single chunk of nothing
                    result.Add(1, 0, 0, MergeChunk.ConflictState.NO_CONFLICT);
                }
                return(result);
            }
            else
            {
                if (theirs.Size() == 0)
                {
                    EditList oursEdits = diffAlg.Diff(cmp, @base, ours);
                    if (!oursEdits.IsEmpty())
                    {
                        // we modified, they deleted -> Let our complete content
                        // conflict with empty text
                        result.Add(1, 0, ours.Size(), MergeChunk.ConflictState.FIRST_CONFLICTING_RANGE);
                        result.Add(2, 0, 0, MergeChunk.ConflictState.NEXT_CONFLICTING_RANGE);
                    }
                    else
                    {
                        // they deleted, we didn't modify -> Let their deletion win
                        result.Add(2, 0, 0, MergeChunk.ConflictState.NO_CONFLICT);
                    }
                    return(result);
                }
            }
            EditList        oursEdits_1   = diffAlg.Diff(cmp, @base, ours);
            Iterator <Edit> baseToOurs    = oursEdits_1.Iterator();
            EditList        theirsEdits_1 = diffAlg.Diff(cmp, @base, theirs);
            Iterator <Edit> baseToTheirs  = theirsEdits_1.Iterator();
            int             current       = 0;
            // points to the next line (first line is 0) of base
            // which was not handled yet
            Edit oursEdit   = NextEdit(baseToOurs);
            Edit theirsEdit = NextEdit(baseToTheirs);

            // iterate over all edits from base to ours and from base to theirs
            // leave the loop when there are no edits more for ours or for theirs
            // (or both)
            while (theirsEdit != END_EDIT || oursEdit != END_EDIT)
            {
                if (oursEdit.GetEndA() < theirsEdit.GetBeginA())
                {
                    // something was changed in ours not overlapping with any change
                    // from theirs. First add the common part in front of the edit
                    // then the edit.
                    if (current != oursEdit.GetBeginA())
                    {
                        result.Add(0, current, oursEdit.GetBeginA(), MergeChunk.ConflictState.NO_CONFLICT
                                   );
                    }
                    result.Add(1, oursEdit.GetBeginB(), oursEdit.GetEndB(), MergeChunk.ConflictState.
                               NO_CONFLICT);
                    current  = oursEdit.GetEndA();
                    oursEdit = NextEdit(baseToOurs);
                }
                else
                {
                    if (theirsEdit.GetEndA() < oursEdit.GetBeginA())
                    {
                        // something was changed in theirs not overlapping with any
                        // from ours. First add the common part in front of the edit
                        // then the edit.
                        if (current != theirsEdit.GetBeginA())
                        {
                            result.Add(0, current, theirsEdit.GetBeginA(), MergeChunk.ConflictState.NO_CONFLICT
                                       );
                        }
                        result.Add(2, theirsEdit.GetBeginB(), theirsEdit.GetEndB(), MergeChunk.ConflictState
                                   .NO_CONFLICT);
                        current    = theirsEdit.GetEndA();
                        theirsEdit = NextEdit(baseToTheirs);
                    }
                    else
                    {
                        // here we found a real overlapping modification
                        // if there is a common part in front of the conflict add it
                        if (oursEdit.GetBeginA() != current && theirsEdit.GetBeginA() != current)
                        {
                            result.Add(0, current, Math.Min(oursEdit.GetBeginA(), theirsEdit.GetBeginA()), MergeChunk.ConflictState
                                       .NO_CONFLICT);
                        }
                        // set some initial values for the ranges in A and B which we
                        // want to handle
                        int oursBeginB   = oursEdit.GetBeginB();
                        int theirsBeginB = theirsEdit.GetBeginB();
                        // harmonize the start of the ranges in A and B
                        if (oursEdit.GetBeginA() < theirsEdit.GetBeginA())
                        {
                            theirsBeginB -= theirsEdit.GetBeginA() - oursEdit.GetBeginA();
                        }
                        else
                        {
                            oursBeginB -= oursEdit.GetBeginA() - theirsEdit.GetBeginA();
                        }
                        // combine edits:
                        // Maybe an Edit on one side corresponds to multiple Edits on
                        // the other side. Then we have to combine the Edits of the
                        // other side - so in the end we can merge together two single
                        // edits.
                        //
                        // It is important to notice that this combining will extend the
                        // ranges of our conflict always downwards (towards the end of
                        // the content). The starts of the conflicting ranges in ours
                        // and theirs are not touched here.
                        //
                        // This combining is an iterative process: after we have
                        // combined some edits we have to do the check again. The
                        // combined edits could now correspond to multiple edits on the
                        // other side.
                        //
                        // Example: when this combining algorithm works on the following
                        // edits
                        // oursEdits=((0-5,0-5),(6-8,6-8),(10-11,10-11)) and
                        // theirsEdits=((0-1,0-1),(2-3,2-3),(5-7,5-7))
                        // it will merge them into
                        // oursEdits=((0-8,0-8),(10-11,10-11)) and
                        // theirsEdits=((0-7,0-7))
                        //
                        // Since the only interesting thing to us is how in ours and
                        // theirs the end of the conflicting range is changing we let
                        // oursEdit and theirsEdit point to the last conflicting edit
                        Edit nextOursEdit   = NextEdit(baseToOurs);
                        Edit nextTheirsEdit = NextEdit(baseToTheirs);
                        for (; ;)
                        {
                            if (oursEdit.GetEndA() >= nextTheirsEdit.GetBeginA())
                            {
                                theirsEdit     = nextTheirsEdit;
                                nextTheirsEdit = NextEdit(baseToTheirs);
                            }
                            else
                            {
                                if (theirsEdit.GetEndA() >= nextOursEdit.GetBeginA())
                                {
                                    oursEdit     = nextOursEdit;
                                    nextOursEdit = NextEdit(baseToOurs);
                                }
                                else
                                {
                                    break;
                                }
                            }
                        }
                        // harmonize the end of the ranges in A and B
                        int oursEndB   = oursEdit.GetEndB();
                        int theirsEndB = theirsEdit.GetEndB();
                        if (oursEdit.GetEndA() < theirsEdit.GetEndA())
                        {
                            oursEndB += theirsEdit.GetEndA() - oursEdit.GetEndA();
                        }
                        else
                        {
                            theirsEndB += oursEdit.GetEndA() - theirsEdit.GetEndA();
                        }
                        // A conflicting region is found. Strip off common lines in
                        // in the beginning and the end of the conflicting region
                        // Determine the minimum length of the conflicting areas in OURS
                        // and THEIRS. Also determine how much bigger the conflicting
                        // area in THEIRS is compared to OURS. All that is needed to
                        // limit the search for common areas at the beginning or end
                        // (the common areas cannot be bigger then the smaller
                        // conflicting area. The delta is needed to know whether the
                        // complete conflicting area is common in OURS and THEIRS.
                        int minBSize   = oursEndB - oursBeginB;
                        int BSizeDelta = minBSize - (theirsEndB - theirsBeginB);
                        if (BSizeDelta > 0)
                        {
                            minBSize -= BSizeDelta;
                        }
                        int commonPrefix = 0;
                        while (commonPrefix < minBSize && cmp.Equals(ours, oursBeginB + commonPrefix, theirs
                                                                     , theirsBeginB + commonPrefix))
                        {
                            commonPrefix++;
                        }
                        minBSize -= commonPrefix;
                        int commonSuffix = 0;
                        while (commonSuffix < minBSize && cmp.Equals(ours, oursEndB - commonSuffix - 1, theirs
                                                                     , theirsEndB - commonSuffix - 1))
                        {
                            commonSuffix++;
                        }
                        minBSize -= commonSuffix;
                        // Add the common lines at start of conflict
                        if (commonPrefix > 0)
                        {
                            result.Add(1, oursBeginB, oursBeginB + commonPrefix, MergeChunk.ConflictState.NO_CONFLICT
                                       );
                        }
                        // Add the conflict (Only if there is a conflict left to report)
                        if (minBSize > 0 || BSizeDelta != 0)
                        {
                            result.Add(1, oursBeginB + commonPrefix, oursEndB - commonSuffix, MergeChunk.ConflictState
                                       .FIRST_CONFLICTING_RANGE);
                            result.Add(2, theirsBeginB + commonPrefix, theirsEndB - commonSuffix, MergeChunk.ConflictState
                                       .NEXT_CONFLICTING_RANGE);
                        }
                        // Add the common lines at end of conflict
                        if (commonSuffix > 0)
                        {
                            result.Add(1, oursEndB - commonSuffix, oursEndB, MergeChunk.ConflictState.NO_CONFLICT
                                       );
                        }
                        current    = Math.Max(oursEdit.GetEndA(), theirsEdit.GetEndA());
                        oursEdit   = nextOursEdit;
                        theirsEdit = nextTheirsEdit;
                    }
                }
            }
            // maybe we have a common part behind the last edit: copy it to the
            // result
            if (current < @base.Size())
            {
                result.Add(0, current, @base.Size(), MergeChunk.ConflictState.NO_CONFLICT);
            }
            return(result);
        }
Beispiel #7
0
        /// <exception cref="System.IO.FileNotFoundException"></exception>
        /// <exception cref="System.InvalidOperationException"></exception>
        /// <exception cref="System.IO.IOException"></exception>
        private bool ContentMerge(CanonicalTreeParser @base, CanonicalTreeParser ours, CanonicalTreeParser
                                  theirs)
        {
            MergeFormatter fmt      = new MergeFormatter();
            RawText        baseText = @base == null ? RawText.EMPTY_TEXT : GetRawText(@base.EntryObjectId
                                                                                      , db);
            // do the merge
            MergeResult <RawText> result = mergeAlgorithm.Merge(RawTextComparator.DEFAULT, baseText
                                                                , GetRawText(ours.EntryObjectId, db), GetRawText(theirs.EntryObjectId, db));
            FilePath         of = null;
            FileOutputStream fos;

            if (!inCore)
            {
                FilePath workTree = db.WorkTree;
                if (workTree == null)
                {
                    // TODO: This should be handled by WorkingTreeIterators which
                    // support write operations
                    throw new NotSupportedException();
                }
                of  = new FilePath(workTree, tw.PathString);
                fos = new FileOutputStream(of);
                try
                {
                    fmt.FormatMerge(fos, result, Arrays.AsList(commitNames), Constants.CHARACTER_ENCODING
                                    );
                }
                finally
                {
                    fos.Close();
                }
            }
            else
            {
                if (!result.ContainsConflicts())
                {
                    // When working inCore, only trivial merges can be handled,
                    // so we generate objects only in conflict free cases
                    of  = FilePath.CreateTempFile("merge_", "_temp", null);
                    fos = new FileOutputStream(of);
                    try
                    {
                        fmt.FormatMerge(fos, result, Arrays.AsList(commitNames), Constants.CHARACTER_ENCODING
                                        );
                    }
                    finally
                    {
                        fos.Close();
                    }
                }
            }
            if (result.ContainsConflicts())
            {
                // a conflict occurred, the file will contain conflict markers
                // the index will be populated with the three stages and only the
                // workdir (if used) contains the halfways merged content
                Add(tw.RawPath, @base, DirCacheEntry.STAGE_1);
                Add(tw.RawPath, ours, DirCacheEntry.STAGE_2);
                Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3);
                mergeResults.Put(tw.PathString, result.Upcast());
                return(false);
            }
            else
            {
                // no conflict occurred, the file will contain fully merged content.
                // the index will be populated with the new merged version
                DirCacheEntry dce = new DirCacheEntry(tw.PathString);
                dce.FileMode     = tw.GetFileMode(0);
                dce.LastModified = of.LastModified();
                dce.SetLength((int)of.Length());
                InputStream @is = new FileInputStream(of);
                try
                {
                    dce.SetObjectId(oi.Insert(Constants.OBJ_BLOB, of.Length(), @is));
                }
                finally
                {
                    @is.Close();
                    if (inCore)
                    {
                        FileUtils.Delete(of);
                    }
                }
                builder.Add(dce);
                return(true);
            }
        }
Beispiel #8
0
        /// <summary>Processes one path and tries to merge.</summary>
        /// <remarks>
        /// Processes one path and tries to merge. This method will do all do all
        /// trivial (not content) merges and will also detect if a merge will fail.
        /// The merge will fail when one of the following is true
        /// <ul>
        /// <li>the index entry does not match the entry in ours. When merging one
        /// branch into the current HEAD, ours will point to HEAD and theirs will
        /// point to the other branch. It is assumed that the index matches the HEAD
        /// because it will only not match HEAD if it was populated before the merge
        /// operation. But the merge commit should not accidentally contain
        /// modifications done before the merge. Check the &lt;a href=
        /// "http://www.kernel.org/pub/software/scm/git/docs/git-read-tree.html#_3_way_merge"
        /// &gt;git read-tree</a> documentation for further explanations.</li>
        /// <li>A conflict was detected and the working-tree file is dirty. When a
        /// conflict is detected the content-merge algorithm will try to write a
        /// merged version into the working-tree. If the file is dirty we would
        /// override unsaved data.</li>
        /// </remarks>
        /// <param name="base">the common base for ours and theirs</param>
        /// <param name="ours">
        /// the ours side of the merge. When merging a branch into the
        /// HEAD ours will point to HEAD
        /// </param>
        /// <param name="theirs">
        /// the theirs side of the merge. When merging a branch into the
        /// current HEAD theirs will point to the branch which is merged
        /// into HEAD.
        /// </param>
        /// <param name="index">the index entry</param>
        /// <param name="work">the file in the working tree</param>
        /// <returns>
        /// <code>false</code> if the merge will fail because the index entry
        /// didn't match ours or the working-dir file was dirty and a
        /// conflict occurred
        /// </returns>
        /// <exception cref="NGit.Errors.MissingObjectException">NGit.Errors.MissingObjectException
        ///     </exception>
        /// <exception cref="NGit.Errors.IncorrectObjectTypeException">NGit.Errors.IncorrectObjectTypeException
        ///     </exception>
        /// <exception cref="NGit.Errors.CorruptObjectException">NGit.Errors.CorruptObjectException
        ///     </exception>
        /// <exception cref="System.IO.IOException">System.IO.IOException</exception>
        private bool ProcessEntry(CanonicalTreeParser @base, CanonicalTreeParser ours, CanonicalTreeParser
                                  theirs, DirCacheBuildIterator index, WorkingTreeIterator work)
        {
            enterSubtree = true;
            int modeO = tw.GetRawMode(T_OURS);
            int modeT = tw.GetRawMode(T_THEIRS);
            int modeB = tw.GetRawMode(T_BASE);

            if (modeO == 0 && modeT == 0 && modeB == 0)
            {
                // File is either untracked or new, staged but uncommitted
                return(true);
            }
            if (IsIndexDirty())
            {
                return(false);
            }
            DirCacheEntry ourDce = null;

            if (index == null || index.GetDirCacheEntry() == null)
            {
                // create a fake DCE, but only if ours is valid. ours is kept only
                // in case it is valid, so a null ourDce is ok in all other cases.
                if (NonTree(modeO))
                {
                    ourDce = new DirCacheEntry(tw.RawPath);
                    ourDce.SetObjectId(tw.GetObjectId(T_OURS));
                    ourDce.FileMode = tw.GetFileMode(T_OURS);
                }
            }
            else
            {
                ourDce = index.GetDirCacheEntry();
            }
            if (NonTree(modeO) && NonTree(modeT) && tw.IdEqual(T_OURS, T_THEIRS))
            {
                // OURS and THEIRS have equal content. Check the file mode
                if (modeO == modeT)
                {
                    // content and mode of OURS and THEIRS are equal: it doesn't
                    // matter which one we choose. OURS is chosen. Since the index
                    // is clean (the index matches already OURS) we can keep the existing one
                    Keep(ourDce);
                    // no checkout needed!
                    return(true);
                }
                else
                {
                    // same content but different mode on OURS and THEIRS.
                    // Try to merge the mode and report an error if this is
                    // not possible.
                    int newMode = MergeFileModes(modeB, modeO, modeT);
                    if (newMode != FileMode.MISSING.GetBits())
                    {
                        if (newMode == modeO)
                        {
                            // ours version is preferred
                            Keep(ourDce);
                        }
                        else
                        {
                            // the preferred version THEIRS has a different mode
                            // than ours. Check it out!
                            if (IsWorktreeDirty(work))
                            {
                                return(false);
                            }
                            // we know about length and lastMod only after we have written the new content.
                            // This will happen later. Set these values to 0 for know.
                            DirCacheEntry e = Add(tw.RawPath, theirs, DirCacheEntry.STAGE_0, 0, 0);
                            toBeCheckedOut.Put(tw.PathString, e);
                        }
                        return(true);
                    }
                    else
                    {
                        // FileModes are not mergeable. We found a conflict on modes.
                        // For conflicting entries we don't know lastModified and length.
                        Add(tw.RawPath, @base, DirCacheEntry.STAGE_1, 0, 0);
                        Add(tw.RawPath, ours, DirCacheEntry.STAGE_2, 0, 0);
                        Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3, 0, 0);
                        unmergedPaths.AddItem(tw.PathString);
                        mergeResults.Put(tw.PathString, new MergeResult <RawText>(Sharpen.Collections.EmptyList
                                                                                  <RawText>()).Upcast());
                    }
                    return(true);
                }
            }
            if (NonTree(modeO) && modeB == modeT && tw.IdEqual(T_BASE, T_THEIRS))
            {
                // THEIRS was not changed compared to BASE. All changes must be in
                // OURS. OURS is chosen. We can keep the existing entry.
                Keep(ourDce);
                // no checkout needed!
                return(true);
            }
            if (modeB == modeO && tw.IdEqual(T_BASE, T_OURS))
            {
                // OURS was not changed compared to BASE. All changes must be in
                // THEIRS. THEIRS is chosen.
                // Check worktree before checking out THEIRS
                if (IsWorktreeDirty(work))
                {
                    return(false);
                }
                if (NonTree(modeT))
                {
                    // we know about length and lastMod only after we have written
                    // the new content.
                    // This will happen later. Set these values to 0 for know.
                    DirCacheEntry e = Add(tw.RawPath, theirs, DirCacheEntry.STAGE_0, 0, 0);
                    if (e != null)
                    {
                        toBeCheckedOut.Put(tw.PathString, e);
                    }
                    return(true);
                }
                else
                {
                    if (modeT == 0 && modeB != 0)
                    {
                        // we want THEIRS ... but THEIRS contains the deletion of the
                        // file
                        toBeDeleted.AddItem(tw.PathString);
                        return(true);
                    }
                }
            }
            if (tw.IsSubtree)
            {
                // file/folder conflicts: here I want to detect only file/folder
                // conflict between ours and theirs. file/folder conflicts between
                // base/index/workingTree and something else are not relevant or
                // detected later
                if (NonTree(modeO) && !NonTree(modeT))
                {
                    if (NonTree(modeB))
                    {
                        Add(tw.RawPath, @base, DirCacheEntry.STAGE_1, 0, 0);
                    }
                    Add(tw.RawPath, ours, DirCacheEntry.STAGE_2, 0, 0);
                    unmergedPaths.AddItem(tw.PathString);
                    enterSubtree = false;
                    return(true);
                }
                if (NonTree(modeT) && !NonTree(modeO))
                {
                    if (NonTree(modeB))
                    {
                        Add(tw.RawPath, @base, DirCacheEntry.STAGE_1, 0, 0);
                    }
                    Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3, 0, 0);
                    unmergedPaths.AddItem(tw.PathString);
                    enterSubtree = false;
                    return(true);
                }
                // ours and theirs are both folders or both files (and treewalk
                // tells us we are in a subtree because of index or working-dir).
                // If they are both folders no content-merge is required - we can
                // return here.
                if (!NonTree(modeO))
                {
                    return(true);
                }
            }
            // ours and theirs are both files, just fall out of the if block
            // and do the content merge
            if (NonTree(modeO) && NonTree(modeT))
            {
                // Check worktree before modifying files
                if (IsWorktreeDirty(work))
                {
                    return(false);
                }
                // Don't attempt to resolve submodule link conflicts
                if (IsGitLink(modeO) || IsGitLink(modeT))
                {
                    Add(tw.RawPath, @base, DirCacheEntry.STAGE_1, 0, 0);
                    Add(tw.RawPath, ours, DirCacheEntry.STAGE_2, 0, 0);
                    Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3, 0, 0);
                    unmergedPaths.AddItem(tw.PathString);
                    return(true);
                }
                MergeResult <RawText> result = ContentMerge(@base, ours, theirs);
                FilePath of = WriteMergedFile(result);
                UpdateIndex(@base, ours, theirs, result, of);
                if (result.ContainsConflicts())
                {
                    unmergedPaths.AddItem(tw.PathString);
                }
                modifiedFiles.AddItem(tw.PathString);
            }
            else
            {
                if (modeO != modeT)
                {
                    // OURS or THEIRS has been deleted
                    if (((modeO != 0 && !tw.IdEqual(T_BASE, T_OURS)) || (modeT != 0 && !tw.IdEqual(T_BASE
                                                                                                   , T_THEIRS))))
                    {
                        Add(tw.RawPath, @base, DirCacheEntry.STAGE_1, 0, 0);
                        Add(tw.RawPath, ours, DirCacheEntry.STAGE_2, 0, 0);
                        DirCacheEntry e = Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3, 0, 0);
                        // OURS was deleted checkout THEIRS
                        if (modeO == 0)
                        {
                            // Check worktree before checking out THEIRS
                            if (IsWorktreeDirty(work))
                            {
                                return(false);
                            }
                            if (NonTree(modeT))
                            {
                                if (e != null)
                                {
                                    toBeCheckedOut.Put(tw.PathString, e);
                                }
                            }
                        }
                        unmergedPaths.AddItem(tw.PathString);
                        // generate a MergeResult for the deleted file
                        mergeResults.Put(tw.PathString, ContentMerge(@base, ours, theirs).Upcast());
                    }
                }
            }
            return(true);
        }
Beispiel #9
0
 public _Iterator_137(MergeResult <S> _enclosing)
 {
     this._enclosing = _enclosing;
 }
Beispiel #10
0
        /// <summary>Processes one path and tries to merge.</summary>
        /// <remarks>
        /// Processes one path and tries to merge. This method will do all do all
        /// trivial (not content) merges and will also detect if a merge will fail.
        /// The merge will fail when one of the following is true
        /// <ul>
        /// <li>the index entry does not match the entry in ours. When merging one
        /// branch into the current HEAD, ours will point to HEAD and theirs will
        /// point to the other branch. It is assumed that the index matches the HEAD
        /// because it will only not match HEAD if it was populated before the merge
        /// operation. But the merge commit should not accidentally contain
        /// modifications done before the merge. Check the &lt;a href=
        /// "http://www.kernel.org/pub/software/scm/git/docs/git-read-tree.html#_3_way_merge"
        /// &gt;git read-tree</a> documentation for further explanations.</li>
        /// <li>A conflict was detected and the working-tree file is dirty. When a
        /// conflict is detected the content-merge algorithm will try to write a
        /// merged version into the working-tree. If the file is dirty we would
        /// override unsaved data.</li>
        /// </remarks>
        /// <param name="base">the common base for ours and theirs</param>
        /// <param name="ours">
        /// the ours side of the merge. When merging a branch into the
        /// HEAD ours will point to HEAD
        /// </param>
        /// <param name="theirs">
        /// the theirs side of the merge. When merging a branch into the
        /// current HEAD theirs will point to the branch which is merged
        /// into HEAD.
        /// </param>
        /// <param name="index">the index entry</param>
        /// <param name="work">the file in the working tree</param>
        /// <returns>
        /// <code>false</code> if the merge will fail because the index entry
        /// didn't match ours or the working-dir file was dirty and a
        /// conflict occurred
        /// </returns>
        /// <exception cref="NGit.Errors.MissingObjectException">NGit.Errors.MissingObjectException
        ///     </exception>
        /// <exception cref="NGit.Errors.IncorrectObjectTypeException">NGit.Errors.IncorrectObjectTypeException
        ///     </exception>
        /// <exception cref="NGit.Errors.CorruptObjectException">NGit.Errors.CorruptObjectException
        ///     </exception>
        /// <exception cref="System.IO.IOException">System.IO.IOException</exception>
        private bool ProcessEntry(CanonicalTreeParser @base, CanonicalTreeParser ours, CanonicalTreeParser
                                  theirs, DirCacheBuildIterator index, WorkingTreeIterator work)
        {
            enterSubtree = true;
            int modeO = tw.GetRawMode(T_OURS);
            int modeT = tw.GetRawMode(T_THEIRS);
            int modeB = tw.GetRawMode(T_BASE);

            if (modeO == 0 && modeT == 0 && modeB == 0)
            {
                // File is either untracked or new, staged but uncommitted
                return(true);
            }
            if (IsIndexDirty())
            {
                return(false);
            }
            if (NonTree(modeO) && modeO == modeT && tw.IdEqual(T_OURS, T_THEIRS))
            {
                // OURS and THEIRS are equal: it doesn't matter which one we choose.
                // OURS is chosen.
                Add(tw.RawPath, ours, DirCacheEntry.STAGE_0);
                // no checkout needed!
                return(true);
            }
            if (NonTree(modeO) && modeB == modeT && tw.IdEqual(T_BASE, T_THEIRS))
            {
                // THEIRS was not changed compared to BASE. All changes must be in
                // OURS. OURS is chosen.
                Add(tw.RawPath, ours, DirCacheEntry.STAGE_0);
                // no checkout needed!
                return(true);
            }
            if (modeB == modeO && tw.IdEqual(T_BASE, T_OURS))
            {
                // OURS was not changed compared to BASE. All changes must be in
                // THEIRS. THEIRS is chosen.
                // Check worktree before checking out THEIRS
                if (IsWorktreeDirty())
                {
                    return(false);
                }
                if (NonTree(modeT))
                {
                    DirCacheEntry e = Add(tw.RawPath, theirs, DirCacheEntry.STAGE_0);
                    if (e != null)
                    {
                        toBeCheckedOut.Put(tw.PathString, e);
                    }
                    return(true);
                }
                else
                {
                    if (modeT == 0 && modeB != 0)
                    {
                        // we want THEIRS ... but THEIRS contains the deletion of the
                        // file
                        toBeCheckedOut.Put(tw.PathString, null);
                        return(true);
                    }
                }
            }
            if (tw.IsSubtree)
            {
                // file/folder conflicts: here I want to detect only file/folder
                // conflict between ours and theirs. file/folder conflicts between
                // base/index/workingTree and something else are not relevant or
                // detected later
                if (NonTree(modeO) && !NonTree(modeT))
                {
                    if (NonTree(modeB))
                    {
                        Add(tw.RawPath, @base, DirCacheEntry.STAGE_1);
                    }
                    Add(tw.RawPath, ours, DirCacheEntry.STAGE_2);
                    unmergedPaths.AddItem(tw.PathString);
                    enterSubtree = false;
                    return(true);
                }
                if (NonTree(modeT) && !NonTree(modeO))
                {
                    if (NonTree(modeB))
                    {
                        Add(tw.RawPath, @base, DirCacheEntry.STAGE_1);
                    }
                    Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3);
                    unmergedPaths.AddItem(tw.PathString);
                    enterSubtree = false;
                    return(true);
                }
                // ours and theirs are both folders or both files (and treewalk
                // tells us we are in a subtree because of index or working-dir).
                // If they are both folders no content-merge is required - we can
                // return here.
                if (!NonTree(modeO))
                {
                    return(true);
                }
            }
            // ours and theirs are both files, just fall out of the if block
            // and do the content merge
            if (NonTree(modeO) && NonTree(modeT))
            {
                // Check worktree before modifying files
                if (IsWorktreeDirty())
                {
                    return(false);
                }
                if (!ContentMerge(@base, ours, theirs))
                {
                    unmergedPaths.AddItem(tw.PathString);
                }
                modifiedFiles.AddItem(tw.PathString);
            }
            else
            {
                if (modeO != modeT)
                {
                    // OURS or THEIRS has been deleted
                    if (((modeO != 0 && !tw.IdEqual(T_BASE, T_OURS)) || (modeT != 0 && !tw.IdEqual(T_BASE
                                                                                                   , T_THEIRS))))
                    {
                        Add(tw.RawPath, @base, DirCacheEntry.STAGE_1);
                        Add(tw.RawPath, ours, DirCacheEntry.STAGE_2);
                        DirCacheEntry e = Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3);
                        // OURS was deleted checkout THEIRS
                        if (modeO == 0)
                        {
                            // Check worktree before checking out THEIRS
                            if (IsWorktreeDirty())
                            {
                                return(false);
                            }
                            if (NonTree(modeT))
                            {
                                if (e != null)
                                {
                                    toBeCheckedOut.Put(tw.PathString, e);
                                }
                            }
                        }
                        unmergedPaths.AddItem(tw.PathString);
                        // generate a MergeResult for the deleted file
                        RawText baseText = @base == null ? RawText.EMPTY_TEXT : GetRawText(@base.EntryObjectId
                                                                                           , db);
                        RawText ourText = ours == null ? RawText.EMPTY_TEXT : GetRawText(ours.EntryObjectId
                                                                                         , db);
                        RawText theirsText = theirs == null ? RawText.EMPTY_TEXT : GetRawText(theirs.EntryObjectId
                                                                                              , db);
                        MergeResult <RawText> result = mergeAlgorithm.Merge(RawTextComparator.DEFAULT, baseText
                                                                            , ourText, theirsText);
                        mergeResults.Put(tw.PathString, result.Upcast());
                    }
                }
            }
            return(true);
        }
Beispiel #11
0
        /// <summary>Processes one path and tries to merge.</summary>
        /// <remarks>
        /// Processes one path and tries to merge. This method will do all do all
        /// trivial (not content) merges and will also detect if a merge will fail.
        /// The merge will fail when one of the following is true
        /// <ul>
        /// <li>the index entry does not match the entry in ours. When merging one
        /// branch into the current HEAD, ours will point to HEAD and theirs will
        /// point to the other branch. It is assumed that the index matches the HEAD
        /// because it will only not match HEAD if it was populated before the merge
        /// operation. But the merge commit should not accidentally contain
        /// modifications done before the merge. Check the &lt;a href=
        /// "http://www.kernel.org/pub/software/scm/git/docs/git-read-tree.html#_3_way_merge"
        /// &gt;git read-tree</a> documentation for further explanations.</li>
        /// <li>A conflict was detected and the working-tree file is dirty. When a
        /// conflict is detected the content-merge algorithm will try to write a
        /// merged version into the working-tree. If the file is dirty we would
        /// override unsaved data.</li>
        /// </remarks>
        /// <param name="base">the common base for ours and theirs</param>
        /// <param name="ours">
        /// the ours side of the merge. When merging a branch into the
        /// HEAD ours will point to HEAD
        /// </param>
        /// <param name="theirs">
        /// the theirs side of the merge. When merging a branch into the
        /// current HEAD theirs will point to the branch which is merged
        /// into HEAD.
        /// </param>
        /// <param name="index">the index entry</param>
        /// <param name="work">the file in the working tree</param>
        /// <returns>
        /// <code>false</code> if the merge will fail because the index entry
        /// didn't match ours or the working-dir file was dirty and a
        /// conflict occurred
        /// </returns>
        /// <exception cref="NGit.Errors.MissingObjectException">NGit.Errors.MissingObjectException
        ///     </exception>
        /// <exception cref="NGit.Errors.IncorrectObjectTypeException">NGit.Errors.IncorrectObjectTypeException
        ///     </exception>
        /// <exception cref="NGit.Errors.CorruptObjectException">NGit.Errors.CorruptObjectException
        ///     </exception>
        /// <exception cref="System.IO.IOException">System.IO.IOException</exception>
        private bool ProcessEntry(CanonicalTreeParser @base, CanonicalTreeParser ours, CanonicalTreeParser
                                  theirs, DirCacheBuildIterator index, WorkingTreeIterator work)
        {
            enterSubtree = true;
            int modeO = tw.GetRawMode(T_OURS);
            int modeT = tw.GetRawMode(T_THEIRS);
            int modeB = tw.GetRawMode(T_BASE);

            if (modeO == 0 && modeT == 0 && modeB == 0)
            {
                // File is either untracked or new, staged but uncommitted
                return(true);
            }
            if (IsIndexDirty())
            {
                return(false);
            }
            if (NonTree(modeO) && NonTree(modeT) && tw.IdEqual(T_OURS, T_THEIRS))
            {
                // OURS and THEIRS have equal content. Check the file mode
                if (modeO == modeT)
                {
                    // content and mode of OURS and THEIRS are equal: it doesn't
                    // matter which one we choose. OURS is chosen.
                    Add(tw.RawPath, ours, DirCacheEntry.STAGE_0);
                    // no checkout needed!
                    return(true);
                }
                else
                {
                    // same content but different mode on OURS and THEIRS.
                    // Try to merge the mode and report an error if this is
                    // not possible.
                    int newMode = MergeFileModes(modeB, modeO, modeT);
                    if (newMode != FileMode.MISSING.GetBits())
                    {
                        if (newMode == modeO)
                        {
                            // ours version is preferred
                            Add(tw.RawPath, ours, DirCacheEntry.STAGE_0);
                        }
                        else
                        {
                            // the preferred version THEIRS has a different mode
                            // than ours. Check it out!
                            if (IsWorktreeDirty(work))
                            {
                                return(false);
                            }
                            DirCacheEntry e = Add(tw.RawPath, theirs, DirCacheEntry.STAGE_0);
                            toBeCheckedOut.Put(tw.PathString, e);
                        }
                        return(true);
                    }
                    else
                    {
                        // FileModes are not mergeable. We found a conflict on modes
                        Add(tw.RawPath, @base, DirCacheEntry.STAGE_1);
                        Add(tw.RawPath, ours, DirCacheEntry.STAGE_2);
                        Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3);
                        unmergedPaths.AddItem(tw.PathString);
                        mergeResults.Put(tw.PathString, new MergeResult <RawText>(Sharpen.Collections.EmptyList
                                                                                  <RawText>()).Upcast());
                    }
                    return(true);
                }
            }
            if (NonTree(modeO) && modeB == modeT && tw.IdEqual(T_BASE, T_THEIRS))
            {
                // THEIRS was not changed compared to BASE. All changes must be in
                // OURS. OURS is chosen.
                Add(tw.RawPath, ours, DirCacheEntry.STAGE_0);
                // no checkout needed!
                return(true);
            }
            if (modeB == modeO && tw.IdEqual(T_BASE, T_OURS))
            {
                // OURS was not changed compared to BASE. All changes must be in
                // THEIRS. THEIRS is chosen.
                // Check worktree before checking out THEIRS
                if (IsWorktreeDirty(work))
                {
                    return(false);
                }
                if (NonTree(modeT))
                {
                    DirCacheEntry e = Add(tw.RawPath, theirs, DirCacheEntry.STAGE_0);
                    if (e != null)
                    {
                        toBeCheckedOut.Put(tw.PathString, e);
                    }
                    return(true);
                }
                else
                {
                    if (modeT == 0 && modeB != 0)
                    {
                        // we want THEIRS ... but THEIRS contains the deletion of the
                        // file
                        toBeDeleted.AddItem(tw.PathString);
                        return(true);
                    }
                }
            }
            if (tw.IsSubtree)
            {
                // file/folder conflicts: here I want to detect only file/folder
                // conflict between ours and theirs. file/folder conflicts between
                // base/index/workingTree and something else are not relevant or
                // detected later
                if (NonTree(modeO) && !NonTree(modeT))
                {
                    if (NonTree(modeB))
                    {
                        Add(tw.RawPath, @base, DirCacheEntry.STAGE_1);
                    }
                    Add(tw.RawPath, ours, DirCacheEntry.STAGE_2);
                    unmergedPaths.AddItem(tw.PathString);
                    enterSubtree = false;
                    return(true);
                }
                if (NonTree(modeT) && !NonTree(modeO))
                {
                    if (NonTree(modeB))
                    {
                        Add(tw.RawPath, @base, DirCacheEntry.STAGE_1);
                    }
                    Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3);
                    unmergedPaths.AddItem(tw.PathString);
                    enterSubtree = false;
                    return(true);
                }
                // ours and theirs are both folders or both files (and treewalk
                // tells us we are in a subtree because of index or working-dir).
                // If they are both folders no content-merge is required - we can
                // return here.
                if (!NonTree(modeO))
                {
                    return(true);
                }
            }
            // ours and theirs are both files, just fall out of the if block
            // and do the content merge
            if (NonTree(modeO) && NonTree(modeT))
            {
                // Check worktree before modifying files
                if (IsWorktreeDirty(work))
                {
                    return(false);
                }
                MergeResult <RawText> result = ContentMerge(@base, ours, theirs);
                FilePath of = WriteMergedFile(result);
                UpdateIndex(@base, ours, theirs, result, of);
                if (result.ContainsConflicts())
                {
                    unmergedPaths.AddItem(tw.PathString);
                }
                modifiedFiles.AddItem(tw.PathString);
            }
            else
            {
                if (modeO != modeT)
                {
                    // OURS or THEIRS has been deleted
                    if (((modeO != 0 && !tw.IdEqual(T_BASE, T_OURS)) || (modeT != 0 && !tw.IdEqual(T_BASE
                                                                                                   , T_THEIRS))))
                    {
                        Add(tw.RawPath, @base, DirCacheEntry.STAGE_1);
                        Add(tw.RawPath, ours, DirCacheEntry.STAGE_2);
                        DirCacheEntry e = Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3);
                        // OURS was deleted checkout THEIRS
                        if (modeO == 0)
                        {
                            // Check worktree before checking out THEIRS
                            if (IsWorktreeDirty(work))
                            {
                                return(false);
                            }
                            if (NonTree(modeT))
                            {
                                if (e != null)
                                {
                                    toBeCheckedOut.Put(tw.PathString, e);
                                }
                            }
                        }
                        unmergedPaths.AddItem(tw.PathString);
                        // generate a MergeResult for the deleted file
                        mergeResults.Put(tw.PathString, ContentMerge(@base, ours, theirs).Upcast());
                    }
                }
            }
            return(true);
        }