Example #1
0
        /// <exception cref="NGit.Errors.IncorrectObjectTypeException"></exception>
        /// <exception cref="System.IO.IOException"></exception>
        private CanonicalTreeParser ParserFor(AnyObjectId id)
        {
            CanonicalTreeParser p = new CanonicalTreeParser();

            p.Reset(reader, id);
            return(p);
        }
Example #2
0
 /// <summary>Back door to quickly create a subtree iterator for any subtree.</summary>
 /// <remarks>
 /// Back door to quickly create a subtree iterator for any subtree.
 /// <p>
 /// Don't use this unless you are ObjectWalk. The method is meant to be
 /// called only once the current entry has been identified as a tree and its
 /// identity has been converted into an ObjectId.
 /// </remarks>
 /// <param name="reader">reader to load the tree data from.</param>
 /// <param name="id">ObjectId of the tree to open.</param>
 /// <returns>a new parser that walks over the current subtree.</returns>
 /// <exception cref="System.IO.IOException">a loose object or pack file could not be read.
 ///     </exception>
 public NGit.Treewalk.CanonicalTreeParser CreateSubtreeIterator0(ObjectReader reader
                                                                 , AnyObjectId id)
 {
     NGit.Treewalk.CanonicalTreeParser p = new NGit.Treewalk.CanonicalTreeParser(this);
     p.Reset(reader, id);
     return(p);
 }
Example #3
0
 /// <summary>Reset this parser to walk through the given tree.</summary>
 /// <remarks>Reset this parser to walk through the given tree.</remarks>
 /// <param name="reader">reader to use during repository access.</param>
 /// <param name="id">
 /// identity of the tree being parsed; used only in exception
 /// messages if data corruption is found.
 /// </param>
 /// <returns>the root level parser.</returns>
 /// <exception cref="NGit.Errors.MissingObjectException">the object supplied is not available from the repository.
 ///     </exception>
 /// <exception cref="NGit.Errors.IncorrectObjectTypeException">
 /// the object supplied as an argument is not actually a tree and
 /// cannot be parsed as though it were a tree.
 /// </exception>
 /// <exception cref="System.IO.IOException">a loose object or pack file could not be read.
 ///     </exception>
 public virtual NGit.Treewalk.CanonicalTreeParser ResetRoot(ObjectReader reader, AnyObjectId
                                                            id)
 {
     NGit.Treewalk.CanonicalTreeParser p = this;
     while (p.parent != null)
     {
         p = (NGit.Treewalk.CanonicalTreeParser)p.parent;
     }
     p.Reset(reader, id);
     return(p);
 }
Example #4
0
        public ActionResult FileDiff(string path, string fromSha1,string toSha1)
        {
            var nGit = TM_UserData_Git.Current.NGit;

            Func<Repository, string, string, string, string> getDiff =
                (gitRepo, repoPath, fromCommitId, toCommitId) =>
                    {

                        var fromCommit = gitRepo.Resolve(fromCommitId);
                        var toCommit = gitRepo.Resolve(toCommitId);

                        var outputStream = "Sharpen.dll".assembly().type("ByteArrayOutputStream").ctor(new object[0]).cast<OutputStream>();
                        //return "diffing from {0} to  {1}".format(fromCommit, toCommit);
                        var diffFormater = new DiffFormatter(outputStream);
                        var pathFilter = PathFilter.Create(repoPath);
                        diffFormater.SetRepository(gitRepo);
                        diffFormater.SetPathFilter(pathFilter);
                        //diffFormater.Format(refLog.GetNewId(), refLog.GetOldId());
                        diffFormater.Format(fromCommit, toCommit);
                        return "result: " + outputStream.str();
                    };

            Func<Repository, string, string, string> getFistValue =
                (gitRepo, commitSha1, repoPath) =>
                    {
                        var revCommit = nGit.commit(commitSha1);
                        var outputStream = "Sharpen.dll".assembly().type("ByteArrayOutputStream").ctor(new object[0]).cast<OutputStream>();
                        var diffFormater = new DiffFormatter(outputStream);
                        var pathFilter = PathFilter.Create(repoPath);
                        diffFormater.SetRepository(gitRepo);
                        diffFormater.SetPathFilter(pathFilter);

                        var revWalk = new RevWalk(gitRepo);
                        var canonicalTreeParser = new CanonicalTreeParser(null, revWalk.GetObjectReader(), revCommit.Tree);
                        diffFormater.Format(new EmptyTreeIterator(), canonicalTreeParser);
                        return outputStream.str().fix_CRLF();
                    };

            var rawDiff = fromSha1 == NGit_Consts.EMPTY_SHA1
                            ? getFistValue(nGit.repository(), fromSha1, path)
                            :  getDiff(nGit.repository(), path, fromSha1, toSha1);

            var viewFile = new View_GitFileDiff()
                {
                    FilePath = path,
                    FromSha1 = fromSha1,
                    ToSha1 = toSha1,
                    Diff = rawDiff
                };
            return View(viewFile);
        }
Example #5
0
 /// <returns>this iterator, or its parent, if the tree is at eof.</returns>
 public virtual NGit.Treewalk.CanonicalTreeParser Next()
 {
     NGit.Treewalk.CanonicalTreeParser p = this;
     for (; ;)
     {
         if (p.nextPtr == p.raw.Length)
         {
             // This parser has reached EOF, return to the parent.
             if (p.parent == null)
             {
                 p.currPtr = p.nextPtr;
                 return(p);
             }
             p = (NGit.Treewalk.CanonicalTreeParser)p.parent;
             continue;
         }
         p.prevPtr = p.currPtr;
         p.currPtr = p.nextPtr;
         p.ParseEntry();
         return(p);
     }
 }
Example #6
0
 private static bool IsValidPath(CanonicalTreeParser t)
 {
     for (CanonicalTreeParser i = t; i != null; i = i.GetParent())
     {
         if (!IsValidPathSegment(i))
         {
             return false;
         }
     }
     return true;
 }
Example #7
0
        /// <summary>Here the main work is done.</summary>
        /// <remarks>
        /// Here the main work is done. This method is called for each existing path
        /// in head, index and merge. This method decides what to do with the
        /// corresponding index entry: keep it, update it, remove it or mark a
        /// conflict.
        /// </remarks>
        /// <param name="h">the entry for the head</param>
        /// <param name="m">the entry for the merge</param>
        /// <param name="i">the entry for the index</param>
        /// <param name="f">the file in the working tree</param>
        /// <exception cref="System.IO.IOException">System.IO.IOException</exception>
        internal virtual void ProcessEntry(CanonicalTreeParser h, CanonicalTreeParser m, 
			DirCacheBuildIterator i, WorkingTreeIterator f)
        {
            DirCacheEntry dce = i != null ? i.GetDirCacheEntry() : null;
            string name = walk.PathString;
            if (m != null && !IsValidPath(m))
            {
                throw new InvalidPathException(m.EntryPathString);
            }
            if (i == null && m == null && h == null)
            {
                // File/Directory conflict case #20
                if (walk.IsDirectoryFileConflict())
                {
                    // TODO: check whether it is always correct to report a conflict here
                    Conflict(name, null, null, null);
                }
                // file only exists in working tree -> ignore it
                return;
            }
            ObjectId iId = (i == null ? null : i.EntryObjectId);
            ObjectId mId = (m == null ? null : m.EntryObjectId);
            ObjectId hId = (h == null ? null : h.EntryObjectId);
            FileMode iMode = (i == null ? null : i.EntryFileMode);
            FileMode mMode = (m == null ? null : m.EntryFileMode);
            FileMode hMode = (h == null ? null : h.EntryFileMode);
            // The information whether head,index,merge iterators are currently
            // pointing to file/folder/non-existing is encoded into this variable.
            //
            // To decode write down ffMask in hexadecimal form. The last digit
            // represents the state for the merge iterator, the second last the
            // state for the index iterator and the third last represents the state
            // for the head iterator. The hexadecimal constant "F" stands for
            // "file",
            // an "D" stands for "directory" (tree), and a "0" stands for
            // non-existing
            //
            // Examples:
            // ffMask == 0xFFD -> Head=File, Index=File, Merge=Tree
            // ffMask == 0xDD0 -> Head=Tree, Index=Tree, Merge=Non-Existing
            int ffMask = 0;
            if (h != null)
            {
                ffMask = FileMode.TREE.Equals(hMode) ? unchecked((int)(0xD00)) : unchecked((int)(
                    0xF00));
            }
            if (i != null)
            {
                ffMask |= FileMode.TREE.Equals(iMode) ? unchecked((int)(0x0D0)) : unchecked((int)
                    (0x0F0));
            }
            if (m != null)
            {
                ffMask |= FileMode.TREE.Equals(mMode) ? unchecked((int)(0x00D)) : unchecked((int)
                    (0x00F));
            }
            // Check whether we have a possible file/folder conflict. Therefore we
            // need a least one file and one folder.
            if (((ffMask & unchecked((int)(0x222))) != unchecked((int)(0x000))) && (((ffMask
                & unchecked((int)(0x00F))) == unchecked((int)(0x00D))) || ((ffMask & unchecked((
                int)(0x0F0))) == unchecked((int)(0x0D0))) || ((ffMask & unchecked((int)(0xF00)))
                 == unchecked((int)(0xD00)))))
            {
                switch (ffMask)
                {
                    case unchecked((int)(0xDDF)):
                    {
                        // There are 3*3*3=27 possible combinations of file/folder
                        // conflicts. Some of them are not-relevant because
                        // they represent no conflict, e.g. 0xFFF, 0xDDD, ... The following
                        // switch processes all relevant cases.
                        // 1 2
                        if (IsModified(name))
                        {
                            Conflict(name, dce, h, m);
                        }
                        else
                        {
                            // 1
                            Update(name, mId, mMode);
                        }
                        // 2
                        break;
                    }

                    case unchecked((int)(0xDFD)):
                    {
                        // 3 4
                        // CAUTION: I put it into removed instead of updated, because
                        // that's what our tests expect
                        // updated.put(name, mId);
                        Remove(name);
                        break;
                    }

                    case unchecked((int)(0xF0D)):
                    {
                        // 18
                        Remove(name);
                        break;
                    }

                    case unchecked((int)(0xDFF)):
                    case unchecked((int)(0xFDD)):
                    {
                        // 5 6
                        // 10 11
                        // TODO: make use of tree extension as soon as available in jgit
                        // we would like to do something like
                        // if (!equalIdAndMode(iId, iMode, mId, mMode)
                        //   conflict(name, i.getDirCacheEntry(), h, m);
                        // But since we don't know the id of a tree in the index we do
                        // nothing here and wait that conflicts between index and merge
                        // are found later
                        break;
                    }

                    case unchecked((int)(0xD0F)):
                    {
                        // 19
                        Update(name, mId, mMode);
                        break;
                    }

                    case unchecked((int)(0xDF0)):
                    case unchecked((int)(0x0FD)):
                    {
                        // conflict without a rule
                        // 15
                        Conflict(name, dce, h, m);
                        break;
                    }

                    case unchecked((int)(0xFDF)):
                    {
                        // 7 8 9
                        if (EqualIdAndMode(hId, hMode, mId, mMode))
                        {
                            if (IsModified(name))
                            {
                                Conflict(name, dce, h, m);
                            }
                            else
                            {
                                // 8
                                Update(name, mId, mMode);
                            }
                        }
                        else
                        {
                            // 7
                            if (!IsModified(name))
                            {
                                Update(name, mId, mMode);
                            }
                            else
                            {
                                // 9
                                // To be confirmed - this case is not in the table.
                                Conflict(name, dce, h, m);
                            }
                        }
                        break;
                    }

                    case unchecked((int)(0xFD0)):
                    {
                        // keep without a rule
                        Keep(dce);
                        break;
                    }

                    case unchecked((int)(0xFFD)):
                    {
                        // 12 13 14
                        if (EqualIdAndMode(hId, hMode, iId, iMode))
                        {
                            if (f == null || f.IsModified(dce, true))
                            {
                                Conflict(name, dce, h, m);
                            }
                            else
                            {
                                Remove(name);
                            }
                        }
                        else
                        {
                            Conflict(name, dce, h, m);
                        }
                        break;
                    }

                    case unchecked((int)(0x0DF)):
                    {
                        // 16 17
                        if (!IsModified(name))
                        {
                            Update(name, mId, mMode);
                        }
                        else
                        {
                            Conflict(name, dce, h, m);
                        }
                        break;
                    }

                    default:
                    {
                        Keep(dce);
                        break;
                    }
                }
                return;
            }
            // if we have no file at all then there is nothing to do
            if ((ffMask & unchecked((int)(0x222))) == 0)
            {
                return;
            }
            if ((ffMask == unchecked((int)(0x00F))) && f != null && FileMode.TREE.Equals(f.EntryFileMode
                ))
            {
                // File/Directory conflict case #20
                Conflict(name, null, h, m);
            }
            if (i == null)
            {
                // make sure not to overwrite untracked files
                if (f != null)
                {
                    // A submodule is not a file. We should ignore it
                    if (!FileMode.GITLINK.Equals(mMode))
                    {
                        // a dirty worktree: the index is empty but we have a
                        // workingtree-file
                        if (mId == null || !EqualIdAndMode(mId, mMode, f.EntryObjectId, f.EntryFileMode))
                        {
                            Conflict(name, null, h, m);
                            return;
                        }
                    }
                }
                if (h == null)
                {
                    Update(name, mId, mMode);
                }
                else
                {
                    // 1
                    if (m == null)
                    {
                        Remove(name);
                    }
                    else
                    {
                        // 2
                        Update(name, mId, mMode);
                    }
                }
            }
            else
            {
                // 3
                if (h == null)
                {
                    if (m == null || EqualIdAndMode(mId, mMode, iId, iMode))
                    {
                        if (m == null && walk.IsDirectoryFileConflict())
                        {
                            if (dce != null && (f == null || f.IsModified(dce, true)))
                            {
                                Conflict(name, dce, h, m);
                            }
                            else
                            {
                                Remove(name);
                            }
                        }
                        else
                        {
                            Keep(dce);
                        }
                    }
                    else
                    {
                        Conflict(name, dce, h, m);
                    }
                }
                else
                {
                    if (m == null)
                    {
                        if (iMode == FileMode.GITLINK)
                        {
                            // Submodules that disappear from the checkout must
                            // be removed from the index, but not deleted from disk.
                            Remove(name);
                        }
                        else
                        {
                            if (EqualIdAndMode(hId, hMode, iId, iMode))
                            {
                                if (f == null || f.IsModified(dce, true))
                                {
                                    Conflict(name, dce, h, m);
                                }
                                else
                                {
                                    Remove(name);
                                }
                            }
                            else
                            {
                                Conflict(name, dce, h, m);
                            }
                        }
                    }
                    else
                    {
                        if (!EqualIdAndMode(hId, hMode, mId, mMode) && !EqualIdAndMode(hId, hMode, iId, iMode
                            ) && !EqualIdAndMode(mId, mMode, iId, iMode))
                        {
                            Conflict(name, dce, h, m);
                        }
                        else
                        {
                            if (EqualIdAndMode(hId, hMode, iId, iMode) && !EqualIdAndMode(mId, mMode, iId, iMode
                                ))
                            {
                                // For submodules just update the index with the new SHA-1
                                if (dce != null && FileMode.GITLINK.Equals(dce.FileMode))
                                {
                                    Update(name, mId, mMode);
                                }
                                else
                                {
                                    if (dce != null && (f == null || f.IsModified(dce, true)))
                                    {
                                        Conflict(name, dce, h, m);
                                    }
                                    else
                                    {
                                        Update(name, mId, mMode);
                                    }
                                }
                            }
                            else
                            {
                                Keep(dce);
                            }
                        }
                    }
                }
            }
        }
Example #8
0
		public override string ToString()
		{
			byte[] raw = ToByteArray();
			CanonicalTreeParser p = new CanonicalTreeParser();
			p.Reset(raw);
			StringBuilder r = new StringBuilder();
			r.Append("Tree={");
			if (!p.Eof)
			{
				r.Append('\n');
				try
				{
					new ObjectChecker().CheckTree(raw);
				}
				catch (CorruptObjectException error)
				{
					r.Append("*** ERROR: ").Append(error.Message).Append("\n");
					r.Append('\n');
				}
			}
			while (!p.Eof)
			{
				FileMode mode = p.EntryFileMode;
				r.Append(mode);
				r.Append(' ');
				r.Append(Constants.TypeString(mode.GetObjectType()));
				r.Append(' ');
				r.Append(p.EntryObjectId.Name);
				r.Append(' ');
				r.Append(p.EntryPathString);
				r.Append('\n');
				p.Next();
			}
			r.Append("}");
			return r.ToString();
		}
Example #9
0
 private CanonicalTreeParser(NGit.Treewalk.CanonicalTreeParser p) : base(p)
 {
 }
Example #10
0
        /// <summary>Does the content merge.</summary>
        /// <remarks>
        /// Does the content merge. The three texts base, ours and theirs are
        /// specified with
        /// <see cref="NGit.Treewalk.CanonicalTreeParser">NGit.Treewalk.CanonicalTreeParser</see>
        /// . If any of the parsers is
        /// specified as <code>null</code> then an empty text will be used instead.
        /// </remarks>
        /// <param name="base"></param>
        /// <param name="ours"></param>
        /// <param name="theirs"></param>
        /// <returns>the result of the content merge</returns>
        /// <exception cref="System.IO.IOException">System.IO.IOException</exception>
        private MergeResult<RawText> ContentMerge(CanonicalTreeParser @base, CanonicalTreeParser
			 ours, CanonicalTreeParser theirs)
        {
            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);
            return (mergeAlgorithm.Merge(RawTextComparator.DEFAULT, baseText, ourText, theirsText
                ));
        }
Example #11
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);
                Add(tw.RawPath, ours, DirCacheEntry.STAGE_2);
                Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3);
                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(oi.Insert(Constants.OBJ_BLOB, of.Length(), @is));
                }
                finally
                {
                    @is.Close();
                    if (inCore)
                    {
                        FileUtils.Delete(of);
                    }
                }
                builder.Add(dce);
            }
        }
Example #12
0
		protected internal override void Reset(int retainFlags)
		{
			base.Reset(retainFlags);
			foreach (RevObject obj in rootObjects)
			{
				obj.flags &= ~IN_PENDING;
			}
			rootObjects = new AList<RevObject>();
			pendingObjects = new BlockObjQueue();
			treeWalk = new CanonicalTreeParser();
			currentTree = null;
			last = null;
			firstCommit = null;
			lastCommit = null;
		}
Example #13
0
		/// <exception cref="NGit.Errors.MissingObjectException"></exception>
		/// <exception cref="NGit.Errors.IncorrectObjectTypeException"></exception>
		/// <exception cref="System.IO.IOException"></exception>
		private void MarkTreeUninteresting(RevTree tree)
		{
			if ((tree.flags & UNINTERESTING) != 0)
			{
				return;
			}
			tree.flags |= UNINTERESTING;
			treeWalk = treeWalk.ResetRoot(reader, tree);
			while (!treeWalk.Eof)
			{
				FileMode mode = treeWalk.EntryFileMode;
				int sType = mode.GetObjectType();
				switch (sType)
				{
					case Constants.OBJ_BLOB:
					{
						treeWalk.GetEntryObjectId(idBuffer);
						LookupBlob(idBuffer).flags |= UNINTERESTING;
						break;
					}

					case Constants.OBJ_TREE:
					{
						treeWalk.GetEntryObjectId(idBuffer);
						RevTree t = LookupTree(idBuffer);
						if ((t.flags & UNINTERESTING) == 0)
						{
							t.flags |= UNINTERESTING;
							treeWalk = treeWalk.CreateSubtreeIterator0(reader, t);
							continue;
						}
						break;
					}

					default:
					{
						if (FileMode.GITLINK.Equals(mode))
						{
							break;
						}
						treeWalk.GetEntryObjectId(idBuffer);
						throw new CorruptObjectException(MessageFormat.Format(JGitText.Get().corruptObjectInvalidMode3
							, mode, idBuffer.Name, treeWalk.EntryPathString, tree));
					}
				}
				treeWalk = treeWalk.Next();
			}
		}
Example #14
0
		/// <summary>Pop the next most recent object.</summary>
		/// <remarks>Pop the next most recent object.</remarks>
		/// <returns>next most recent object; null if traversal is over.</returns>
		/// <exception cref="NGit.Errors.MissingObjectException">
		/// one or or more of the next objects are not available from the
		/// object database, but were thought to be candidates for
		/// traversal. This usually indicates a broken link.
		/// </exception>
		/// <exception cref="NGit.Errors.IncorrectObjectTypeException">
		/// one or or more of the objects in a tree do not match the type
		/// indicated.
		/// </exception>
		/// <exception cref="System.IO.IOException">a pack file or loose object could not be read.
		/// 	</exception>
		public virtual RevObject NextObject()
		{
			if (last != null)
			{
				treeWalk = last is RevTree ? Enter(last) : treeWalk.Next();
			}
			while (!treeWalk.Eof)
			{
				FileMode mode = treeWalk.EntryFileMode;
				switch (mode.GetObjectType())
				{
					case Constants.OBJ_BLOB:
					{
						treeWalk.GetEntryObjectId(idBuffer);
						RevBlob o = LookupBlob(idBuffer);
						if ((o.flags & SEEN) != 0)
						{
							break;
						}
						o.flags |= SEEN;
						if (ShouldSkipObject(o))
						{
							break;
						}
						last = o;
						return o;
					}

					case Constants.OBJ_TREE:
					{
						treeWalk.GetEntryObjectId(idBuffer);
						RevTree o = LookupTree(idBuffer);
						if ((o.flags & SEEN) != 0)
						{
							break;
						}
						o.flags |= SEEN;
						if (ShouldSkipObject(o))
						{
							break;
						}
						last = o;
						return o;
					}

					default:
					{
						if (FileMode.GITLINK.Equals(mode))
						{
							break;
						}
						treeWalk.GetEntryObjectId(idBuffer);
						throw new CorruptObjectException(MessageFormat.Format(JGitText.Get().corruptObjectInvalidMode3
							, mode, idBuffer.Name, treeWalk.EntryPathString, currentTree.Name));
					}
				}
				treeWalk = treeWalk.Next();
			}
			if (firstCommit != null)
			{
				reader.WalkAdviceBeginTrees(this, firstCommit, lastCommit);
				firstCommit = null;
				lastCommit = null;
			}
			last = null;
			for (; ; )
			{
				RevObject o = pendingObjects.Next();
				if (o == null)
				{
					reader.WalkAdviceEnd();
					return null;
				}
				if ((o.flags & SEEN) != 0)
				{
					continue;
				}
				o.flags |= SEEN;
				if (ShouldSkipObject(o))
				{
					continue;
				}
				if (o is RevTree)
				{
					currentTree = (RevTree)o;
					treeWalk = treeWalk.ResetRoot(reader, currentTree);
				}
				return o;
			}
		}
Example #15
0
		public override void Dispose()
		{
			base.Dispose();
			pendingObjects = new BlockObjQueue();
			treeWalk = new CanonicalTreeParser();
			currentTree = null;
			last = null;
			firstCommit = null;
			lastCommit = null;
		}
Example #16
0
		/// <summary>Create a new revision and object walker for a given repository.</summary>
		/// <remarks>Create a new revision and object walker for a given repository.</remarks>
		/// <param name="or">
		/// the reader the walker will obtain data from. The reader should
		/// be released by the caller when the walker is no longer
		/// required.
		/// </param>
		public ObjectWalk(ObjectReader or) : base(or)
		{
			rootObjects = new AList<RevObject>();
			pendingObjects = new BlockObjQueue();
			treeWalk = new CanonicalTreeParser();
		}
Example #17
0
 /// <exception cref="System.IO.IOException"></exception>
 private AbstractTreeIterator GetTreeIterator(string name)
 {
     ObjectId id = db.Resolve(name);
     if (id == null)
     {
         throw new ArgumentException(name);
     }
     CanonicalTreeParser p = new CanonicalTreeParser();
     ObjectReader or = db.NewObjectReader();
     try
     {
         p.Reset(or, new RevWalk(db).ParseTree(id));
         return p;
     }
     finally
     {
         or.Release();
     }
 }
Example #18
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);
			}
			return true;
		}
Example #19
0
 private static bool IsValidPathSegment(CanonicalTreeParser t)
 {
     string osName = SystemReader.GetInstance().GetProperty("os.name");
     bool isWindows = "Windows".Equals(osName);
     bool isOSX = "Darwin".Equals(osName) || "Mac OS X".Equals(osName);
     bool ignCase = isOSX || isWindows;
     int ptr = t.GetNameOffset();
     byte[] raw = t.GetEntryPathBuffer();
     int end = ptr + t.NameLength;
     // Validate path component at this level of the tree
     int start = ptr;
     while (ptr < end)
     {
         if (raw[ptr] == '/')
         {
             return false;
         }
         if (isWindows)
         {
             if (raw[ptr] == '\\')
             {
                 return false;
             }
             if (raw[ptr] == ':')
             {
                 return false;
             }
         }
         ptr++;
     }
     // '.' and '.'' are invalid here
     if (ptr - start == 1)
     {
         if (raw[start] == '.')
         {
             return false;
         }
     }
     else
     {
         if (ptr - start == 2)
         {
             if (raw[start] == '.')
             {
                 if (raw[start + 1] == '.')
                 {
                     return false;
                 }
             }
         }
         else
         {
             if (ptr - start == 4)
             {
                 // .git (possibly case insensitive) is disallowed
                 if (raw[start] == '.')
                 {
                     if (raw[start + 1] == 'g' || (ignCase && raw[start + 1] == 'G'))
                     {
                         if (raw[start + 2] == 'i' || (ignCase && raw[start + 2] == 'I'))
                         {
                             if (raw[start + 3] == 't' || (ignCase && raw[start + 3] == 'T'))
                             {
                                 return false;
                             }
                         }
                     }
                 }
             }
         }
     }
     if (isWindows)
     {
         // Space or period at end of file name is ignored by Windows.
         // Treat this as a bad path for now. We may want to handle
         // this as case insensitivity in the future.
         if (raw[ptr - 1] == '.' || raw[ptr - 1] == ' ')
         {
             return false;
         }
         int i;
         // Bad names, eliminate suffix first
         for (i = start; i < ptr; ++i)
         {
             if (raw[i] == '.')
             {
                 break;
             }
         }
         int len = i - start;
         if (len == 3 || len == 4)
         {
             for (int j = 0; j < forbidden.Length; ++j)
             {
                 if (forbidden[j].Length == len)
                 {
                     if (((sbyte)ToUpper(raw[start])) < forbidden[j][0])
                     {
                         break;
                     }
                     int k;
                     for (k = 0; k < len; ++k)
                     {
                         if (ToUpper(raw[start + k]) != forbidden[j][k])
                         {
                             break;
                         }
                     }
                     if (k == len)
                     {
                         return false;
                     }
                 }
             }
         }
     }
     return true;
 }
		/// <summary>
		/// Processing an entry in the context of
		/// <see cref="PrescanOneTree()">PrescanOneTree()</see>
		/// when only
		/// one tree is given
		/// </summary>
		/// <param name="m">the tree to merge</param>
		/// <param name="i">the index</param>
		/// <param name="f">the working tree</param>
		/// <exception cref="System.IO.IOException">System.IO.IOException</exception>
		internal virtual void ProcessEntry(CanonicalTreeParser m, DirCacheBuildIterator i
			, WorkingTreeIterator f)
		{
			if (m != null)
			{
				// There is an entry in the merge commit. Means: we want to update
				// what's currently in the index and working-tree to that one
				if (i == null)
				{
					// The index entry is missing
					if (f != null && !FileMode.TREE.Equals(f.EntryFileMode) && !f.IsEntryIgnored())
					{
						// don't overwrite an untracked and not ignored file
						conflicts.AddItem(walk.PathString);
					}
					else
					{
						Update(m.EntryPathString, m.EntryObjectId, m.EntryFileMode);
					}
				}
				else
				{
					if (f == null || !m.IdEqual(i))
					{
						// The working tree file is missing or the merge content differs
						// from index content
						Update(m.EntryPathString, m.EntryObjectId, m.EntryFileMode);
					}
					else
					{
						if (i.GetDirCacheEntry() != null)
						{
							// The index contains a file (and not a folder)
							if (f.IsModified(i.GetDirCacheEntry(), true) || i.GetDirCacheEntry().Stage != 0)
							{
								// The working tree file is dirty or the index contains a
								// conflict
								Update(m.EntryPathString, m.EntryObjectId, m.EntryFileMode);
							}
							else
							{
								Keep(i.GetDirCacheEntry());
							}
						}
						else
						{
							// The index contains a folder
							Keep(i.GetDirCacheEntry());
						}
					}
				}
			}
			else
			{
				// There is no entry in the merge commit. Means: we want to delete
				// what's currently in the index and working tree
				if (f != null)
				{
					// There is a file/folder for that path in the working tree
					if (walk.IsDirectoryFileConflict())
					{
						conflicts.AddItem(walk.PathString);
					}
					else
					{
						// No file/folder conflict exists. All entries are files or
						// all entries are folders
						if (i != null)
						{
							// ... and the working tree contained a file or folder
							// -> add it to the removed set and remove it from
							// conflicts set
							Remove(i.EntryPathString);
							conflicts.Remove(i.EntryPathString);
						}
					}
				}
				else
				{
					// untracked file, neither contained in tree to merge
					// nor in index
					// There is no file/folder for that path in the working tree.
					// The only entry we have is the index entry. If that entry is a
					// conflict simply remove it. Otherwise keep that entry in the
					// index
					if (i.GetDirCacheEntry().Stage == 0)
					{
						Keep(i.GetDirCacheEntry());
					}
				}
			}
		}
Example #21
0
		internal BaseSearch(ProgressMonitor countingMonitor, ICollection<RevTree> bases, 
			ObjectIdOwnerMap<ObjectToPack> objects, IList<ObjectToPack> edges, ObjectReader 
			or)
		{
			progress = countingMonitor;
			reader = or;
			baseTrees = Sharpen.Collections.ToArray(bases, new ObjectId[bases.Count]);
			objectsMap = objects;
			edgeObjects = edges;
			alreadyProcessed = new IntSet();
			treeCache = new ObjectIdOwnerMap<BaseSearch.TreeWithData>();
			parser = new CanonicalTreeParser();
			idBuf = new MutableObjectId();
		}
		/// <summary>
		/// Processing an entry in the context of
		/// <see cref="PrescanOneTree()">PrescanOneTree()</see>
		/// when only
		/// one tree is given
		/// </summary>
		/// <param name="m">the tree to merge</param>
		/// <param name="i">the index</param>
		/// <param name="f">the working tree</param>
		internal virtual void ProcessEntry(CanonicalTreeParser m, DirCacheBuildIterator i
			, WorkingTreeIterator f)
		{
			if (m != null)
			{
				if (i == null || f == null || !m.IdEqual(i) || (i.GetDirCacheEntry() != null && (
					f.IsModified(i.GetDirCacheEntry(), true) || i.GetDirCacheEntry().Stage != 0)))
				{
					Update(m.EntryPathString, m.EntryObjectId, m.EntryFileMode);
				}
				else
				{
					Keep(i.GetDirCacheEntry());
				}
			}
			else
			{
				if (f != null)
				{
					if (walk.IsDirectoryFileConflict())
					{
						conflicts.AddItem(walk.PathString);
					}
					else
					{
						if (i != null)
						{
							// ... and the working dir contained a file or folder ->
							// add it to the removed set and remove it from
							// conflicts set
							Remove(i.EntryPathString);
							conflicts.Remove(i.EntryPathString);
						}
					}
				}
				else
				{
					if (i.GetDirCacheEntry().Stage == 0)
					{
						Keep(i.GetDirCacheEntry());
					}
				}
			}
		}
Example #23
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())
                            {
                                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())
                {
                    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;
                }
                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())
                            {
                                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;
        }
		/// <summary>adds a new path with the specified stage to the index builder</summary>
		/// <param name="path"></param>
		/// <param name="p"></param>
		/// <param name="stage"></param>
		/// <returns>the entry which was added to the index</returns>
		private DirCacheEntry Add(byte[] path, CanonicalTreeParser p, int stage)
		{
			if (p != null && !p.EntryFileMode.Equals(FileMode.TREE))
			{
				DirCacheEntry e = new DirCacheEntry(path, stage);
				e.FileMode = p.EntryFileMode;
				e.SetObjectId(p.EntryObjectId);
				builder.Add(e);
				return e;
			}
			return null;
		}
Example #25
0
		public virtual void TestTreeIteratorWithGitmodules()
		{
			ObjectId subId = ObjectId.FromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
			string path = "sub";
			Config gitmodules = new Config();
			gitmodules.SetString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, ConfigConstants
				.CONFIG_KEY_PATH, "sub");
			gitmodules.SetString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, ConfigConstants
				.CONFIG_KEY_URL, "git://example.com/sub");
			RevCommit commit = testDb.GetRevWalk().ParseCommit(testDb.Commit().NoParents().Add
				(Constants.DOT_GIT_MODULES, gitmodules.ToText()).Edit(new _PathEdit_397(subId, path
				)).Create());
			CanonicalTreeParser p = new CanonicalTreeParser();
			p.Reset(testDb.GetRevWalk().GetObjectReader(), commit.Tree);
			SubmoduleWalk gen = SubmoduleWalk.ForPath(db, p, "sub");
			NUnit.Framework.Assert.AreEqual(path, gen.GetPath());
			NUnit.Framework.Assert.AreEqual(subId, gen.GetObjectId());
			NUnit.Framework.Assert.AreEqual(new FilePath(db.WorkTree, path), gen.GetDirectory
				());
			NUnit.Framework.Assert.IsNull(gen.GetConfigUpdate());
			NUnit.Framework.Assert.IsNull(gen.GetConfigUrl());
			NUnit.Framework.Assert.AreEqual("sub", gen.GetModulesPath());
			NUnit.Framework.Assert.IsNull(gen.GetModulesUpdate());
			NUnit.Framework.Assert.AreEqual("git://example.com/sub", gen.GetModulesUrl());
			NUnit.Framework.Assert.IsNull(gen.GetRepository());
			NUnit.Framework.Assert.IsFalse(gen.Next());
		}
		/// <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 occured, 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 occured, 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;
			}
		}
Example #27
0
		/// <summary>Create a new revision and object walker for a given repository.</summary>
		/// <remarks>Create a new revision and object walker for a given repository.</remarks>
		/// <param name="or">
		/// the reader the walker will obtain data from. The reader should
		/// be released by the caller when the walker is no longer
		/// required.
		/// </param>
		public ObjectWalk(ObjectReader or) : base(or)
		{
			pendingObjects = new BlockObjQueue();
			treeWalk = new CanonicalTreeParser();
		}
Example #28
0
		/// <summary>
		/// Set the tree used by this walk for finding
		/// <code>.gitmodules</code>
		/// .
		/// <p>
		/// The root tree is not read until the first submodule is encountered by the
		/// walk.
		/// <p>
		/// This method need only be called if constructing a walk manually instead of
		/// with one of the static factory methods above.
		/// </summary>
		/// <param name="id">ID of a tree containing .gitmodules</param>
		/// <returns>this generator</returns>
		/// <exception cref="System.IO.IOException">System.IO.IOException</exception>
		public virtual NGit.Submodule.SubmoduleWalk SetRootTree(AnyObjectId id)
		{
			CanonicalTreeParser p = new CanonicalTreeParser();
			p.Reset(walk.ObjectReader, id);
			rootTree = p;
			modulesConfig = null;
			return this;
		}
Example #29
0
		public static IEnumerable<DiffEntry> CompareCommits (NGit.Repository repo, AnyObjectId reference, ObjectId compared)
		{
			var diff = new MyersDiff (repo);

			var firstTree = new CanonicalTreeParser ();
			firstTree.Reset (repo.NewObjectReader (), new RevWalk (repo).ParseTree (reference));
			diff.SetNewTree (firstTree);
			
			if (compared != ObjectId.ZeroId) {
				var secondTree = new CanonicalTreeParser ();
				secondTree.Reset (repo.NewObjectReader (), new RevWalk (repo).ParseTree (compared));

				if (compared != ObjectId.ZeroId)
					diff.SetOldTree (secondTree);
			}
			return diff.Call ();
		}
Example #30
0
		protected internal override void Reset(int retainFlags)
		{
			base.Reset(retainFlags);
			pendingObjects = new BlockObjQueue();
			treeWalk = new CanonicalTreeParser();
			currentTree = null;
			last = null;
			firstCommit = null;
			lastCommit = null;
		}
		/// <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 occured
		/// </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 modeI = tw.GetRawMode(T_INDEX);
			// Each index entry has to match ours, means: it has to be clean
			if (NonTree(modeI) && !(tw.IdEqual(T_INDEX, T_OURS) && modeO == modeI))
			{
				failingPaths.Put(tw.PathString, ResolveMerger.MergeFailureReason.DIRTY_INDEX);
				return false;
			}
			int modeT = tw.GetRawMode(T_THEIRS);
			if (NonTree(modeO) && modeO == modeT && tw.IdEqual(T_OURS, T_THEIRS))
			{
				// ours and theirs are equal: it doesn'nt matter
				// which one we choose. OURS is choosen here.
				Add(tw.RawPath, ours, DirCacheEntry.STAGE_0);
				// no checkout needed!
				return true;
			}
			int modeB = tw.GetRawMode(T_BASE);
			if (NonTree(modeO) && modeB == modeT && tw.IdEqual(T_BASE, T_THEIRS))
			{
				// THEIRS was not changed compared to base. All changes must be in
				// OURS. Choose OURS.
				Add(tw.RawPath, ours, DirCacheEntry.STAGE_0);
				return true;
			}
			if (modeB == modeO && tw.IdEqual(T_BASE, T_OURS))
			{
				// OURS was not changed compared to base. All changes must be in
				// THEIRS. Choose THEIRS.
				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))
			{
				if (!inCore)
				{
					// We are going to update the worktree. Make sure the worktree
					// is not modified
					if (work != null && (!NonTree(work.EntryRawMode) || work.IsModified(index.GetDirCacheEntry
						(), true)))
					{
						failingPaths.Put(tw.PathString, ResolveMerger.MergeFailureReason.DIRTY_WORKTREE);
						return false;
					}
				}
				if (!ContentMerge(@base, ours, theirs))
				{
					unmergedPaths.AddItem(tw.PathString);
				}
				modifiedFiles.AddItem(tw.PathString);
			}
			return true;
		}
Example #32
0
        /// <summary>
        /// Processing an entry in the context of
        /// <see cref="PrescanOneTree()">PrescanOneTree()</see>
        /// when only
        /// one tree is given
        /// </summary>
        /// <param name="m">the tree to merge</param>
        /// <param name="i">the index</param>
        /// <param name="f">the working tree</param>
        /// <exception cref="System.IO.IOException">System.IO.IOException</exception>
        internal virtual void ProcessEntry(CanonicalTreeParser m, DirCacheBuildIterator i
			, WorkingTreeIterator f)
        {
            if (m != null)
            {
                if (!IsValidPath(m))
                {
                    throw new InvalidPathException(m.EntryPathString);
                }
                // There is an entry in the merge commit. Means: we want to update
                // what's currently in the index and working-tree to that one
                if (i == null)
                {
                    // The index entry is missing
                    if (f != null && !FileMode.TREE.Equals(f.EntryFileMode) && !f.IsEntryIgnored())
                    {
                        // don't overwrite an untracked and not ignored file
                        conflicts.AddItem(walk.PathString);
                    }
                    else
                    {
                        Update(m.EntryPathString, m.EntryObjectId, m.EntryFileMode);
                    }
                }
                else
                {
                    if (f == null || !m.IdEqual(i))
                    {
                        // The working tree file is missing or the merge content differs
                        // from index content
                        Update(m.EntryPathString, m.EntryObjectId, m.EntryFileMode);
                    }
                    else
                    {
                        if (i.GetDirCacheEntry() != null)
                        {
                            // The index contains a file (and not a folder)
                            if (f.IsModified(i.GetDirCacheEntry(), true) || i.GetDirCacheEntry().Stage != 0)
                            {
                                // The working tree file is dirty or the index contains a
                                // conflict
                                Update(m.EntryPathString, m.EntryObjectId, m.EntryFileMode);
                            }
                            else
                            {
                                // update the timestamp of the index with the one from the
                                // file if not set, as we are sure to be in sync here.
                                DirCacheEntry entry = i.GetDirCacheEntry();
                                if (entry.LastModified == 0)
                                {
                                    entry.LastModified = f.GetEntryLastModified();
                                }
                                Keep(entry);
                            }
                        }
                        else
                        {
                            // The index contains a folder
                            Keep(i.GetDirCacheEntry());
                        }
                    }
                }
            }
            else
            {
                // There is no entry in the merge commit. Means: we want to delete
                // what's currently in the index and working tree
                if (f != null)
                {
                    // There is a file/folder for that path in the working tree
                    if (walk.IsDirectoryFileConflict())
                    {
                        conflicts.AddItem(walk.PathString);
                    }
                    else
                    {
                        // No file/folder conflict exists. All entries are files or
                        // all entries are folders
                        if (i != null)
                        {
                            // ... and the working tree contained a file or folder
                            // -> add it to the removed set and remove it from
                            // conflicts set
                            Remove(i.EntryPathString);
                            conflicts.Remove(i.EntryPathString);
                        }
                    }
                }
            }
        }
Example #33
0
        /// <summary>Back door to quickly create a subtree iterator for any subtree.</summary>
        /// <remarks>
        /// Back door to quickly create a subtree iterator for any subtree.
        /// <p/>
        /// Don't use this unless you are ObjectWalk. The method is meant to be
        /// called only once the current entry has been identified as a tree and its
        /// identity has been converted into an ObjectId.
        /// </remarks>
        /// <param name="reader">reader to load the tree data from.</param>
        /// <param name="id">ObjectId of the tree to open.</param>
        /// <returns>a new parser that walks over the current subtree.</returns>
        /// <exception cref="System.IO.IOException">a loose object or pack file could not be read.
        /// 	</exception>
        public NGit.Treewalk.CanonicalTreeParser CreateSubtreeIterator0(ObjectReader reader
			, AnyObjectId id)
        {
            NGit.Treewalk.CanonicalTreeParser p = new NGit.Treewalk.CanonicalTreeParser(this);
            p.Reset(reader, id);
            return p;
        }
Example #34
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;
		}