Пример #1
0
        ObjectId WriteWorkingDirectoryTree(RevTree headTree, DirCache index)
        {
            DirCache        dc = DirCache.NewInCore();
            DirCacheBuilder cb = dc.Builder();

            ObjectInserter oi = _repo.NewObjectInserter();

            try {
                TreeWalk tw = new TreeWalk(_repo);
                tw.Reset();
                tw.AddTree(new FileTreeIterator(_repo));
                tw.AddTree(headTree);
                tw.AddTree(new DirCacheIterator(index));

                while (tw.Next())
                {
                    // Ignore untracked files
                    if (tw.IsSubtree)
                    {
                        tw.EnterSubtree();
                    }
                    else if (tw.GetFileMode(0) != NGit.FileMode.MISSING && (tw.GetFileMode(1) != NGit.FileMode.MISSING || tw.GetFileMode(2) != NGit.FileMode.MISSING))
                    {
                        WorkingTreeIterator f            = tw.GetTree <WorkingTreeIterator>(0);
                        DirCacheIterator    dcIter       = tw.GetTree <DirCacheIterator>(2);
                        DirCacheEntry       currentEntry = dcIter.GetDirCacheEntry();
                        DirCacheEntry       ce           = new DirCacheEntry(tw.PathString);
                        if (!f.IsModified(currentEntry, true))
                        {
                            ce.SetLength(currentEntry.Length);
                            ce.LastModified = currentEntry.LastModified;
                            ce.FileMode     = currentEntry.FileMode;
                            ce.SetObjectId(currentEntry.GetObjectId());
                        }
                        else
                        {
                            long sz = f.GetEntryLength();
                            ce.SetLength(sz);
                            ce.LastModified = f.GetEntryLastModified();
                            ce.FileMode     = f.EntryFileMode;
                            var data = f.OpenEntryStream();
                            try {
                                ce.SetObjectId(oi.Insert(Constants.OBJ_BLOB, sz, data));
                            } finally {
                                data.Close();
                            }
                        }
                        cb.Add(ce);
                    }
                }

                cb.Finish();
                return(dc.WriteTree(oi));
            } finally {
                oi.Release();
            }
        }
Пример #2
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 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;
		}
Пример #3
0
        private GitFileStatus GetFileStatus(TreeWalk treeWalk)
        {
            AbstractTreeIterator treeIterator        = treeWalk.GetTree <AbstractTreeIterator>(TREE);
            DirCacheIterator     dirCacheIterator    = treeWalk.GetTree <DirCacheIterator>(INDEX);
            WorkingTreeIterator  workingTreeIterator = treeWalk.GetTree <WorkingTreeIterator>(WORKDIR);

            if (dirCacheIterator != null)
            {
                DirCacheEntry dirCacheEntry = dirCacheIterator.GetDirCacheEntry();
                if (dirCacheEntry != null && dirCacheEntry.Stage > 0)
                {
                    return(GitFileStatus.Conflict);
                }

                if (workingTreeIterator == null)
                {
                    // in index, not in workdir => missing
                    return(GitFileStatus.Deleted);
                }
                else
                {
                    if (workingTreeIterator.IsModified(dirCacheIterator.GetDirCacheEntry(), true))
                    {
                        // in index, in workdir, content differs => modified
                        return(GitFileStatus.Modified);
                    }
                }
            }
            if (treeIterator != null)
            {
                if (dirCacheIterator != null)
                {
                    if (!treeIterator.IdEqual(dirCacheIterator) || treeIterator.EntryRawMode != dirCacheIterator.EntryRawMode)
                    {
                        // in repo, in index, content diff => changed
                        return(GitFileStatus.Staged);
                    }
                }
                else
                {
                    return(GitFileStatus.Removed);
                }
            }
            else
            {
                if (dirCacheIterator != null)
                {
                    // not in repo, in index => added
                    return(GitFileStatus.Added);
                }
                else
                {
                    // not in repo, not in index => untracked
                    if (workingTreeIterator != null)
                    {
                        return(!workingTreeIterator.IsEntryIgnored() ? GitFileStatus.New : GitFileStatus.Ignored);
                    }
                }
            }

            return(GitFileStatus.NotControlled);
        }
        /// <exception cref="NGit.Errors.MissingObjectException"></exception>
        /// <exception cref="NGit.Errors.IncorrectObjectTypeException"></exception>
        /// <exception cref="System.IO.IOException"></exception>
        public override bool Include(TreeWalk tw)
        {
            int    cnt  = tw.TreeCount;
            int    wm   = tw.GetRawMode(workingTree);
            string path = tw.PathString;

            if (!tw.PostOrderTraversal)
            {
                // detect untracked Folders
                // Whenever we enter a folder in the workingtree assume it will
                // contain only untracked files and add it to
                // untrackedParentFolders. If we later find tracked files we will
                // remove it from this list
                if (FileMode.TREE.Equals(wm))
                {
                    // Clean untrackedParentFolders. This potentially moves entries
                    // from untrackedParentFolders to untrackedFolders
                    CopyUntrackedFolders(path);
                    // add the folder we just entered to untrackedParentFolders
                    untrackedParentFolders.AddFirst(path);
                }
                // detect untracked Folders
                // Whenever we see a tracked file we know that all of its parent
                // folders do not belong into untrackedParentFolders anymore. Clean
                // it.
                for (int i = 0; i < cnt; i++)
                {
                    int rmode = tw.GetRawMode(i);
                    if (i != workingTree && rmode != 0 && FileMode.TREE.Equals(rmode))
                    {
                        untrackedParentFolders.Clear();
                        break;
                    }
                }
            }
            // If the working tree file doesn't exist, it does exist for at least
            // one other so include this difference.
            if (wm == 0)
            {
                return(true);
            }
            // If the path does not appear in the DirCache and its ignored
            // we can avoid returning a result here, but only if its not in any
            // other tree.
            int dm = tw.GetRawMode(dirCache);
            WorkingTreeIterator wi = WorkingTree(tw);

            if (dm == 0)
            {
                if (honorIgnores && wi.IsEntryIgnored())
                {
                    ignoredPaths.AddItem(wi.EntryPathString);
                    int i = 0;
                    for (; i < cnt; i++)
                    {
                        if (i == dirCache || i == workingTree)
                        {
                            continue;
                        }
                        if (tw.GetRawMode(i) != 0)
                        {
                            break;
                        }
                    }
                    // If i is cnt then the path does not appear in any other tree,
                    // and this working tree entry can be safely ignored.
                    return(i == cnt ? false : true);
                }
                else
                {
                    // In working tree and not ignored, and not in DirCache.
                    return(true);
                }
            }
            // Always include subtrees as WorkingTreeIterator cannot provide
            // efficient elimination of unmodified subtrees.
            if (tw.IsSubtree)
            {
                return(true);
            }
            // Try the inexpensive comparisons between index and all real trees
            // first. Only if we don't find a diff here we have to bother with
            // the working tree
            for (int i_1 = 0; i_1 < cnt; i_1++)
            {
                if (i_1 == dirCache || i_1 == workingTree)
                {
                    continue;
                }
                if (tw.GetRawMode(i_1) != dm || !tw.IdEqual(i_1, dirCache))
                {
                    return(true);
                }
            }
            // Only one chance left to detect a diff: between index and working
            // tree. Make use of the WorkingTreeIterator#isModified() method to
            // avoid computing SHA1 on filesystem content if not really needed.
            DirCacheIterator di = tw.GetTree <DirCacheIterator>(dirCache);

            return(wi.IsModified(di.GetDirCacheEntry(), true));
        }
Пример #5
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);
                        }
                    }
                }
            }
        }
Пример #6
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);
                            }
                        }
                    }
                }
            }
        }
Пример #7
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)
			{
				// 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());
					}
				}
			}
		}
Пример #8
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>
		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());
					}
				}
			}
		}
Пример #9
0
        /// <summary>Run the diff operation.</summary>
        /// <remarks>
        /// Run the diff operation. Until this is called, all lists will be empty.
        /// <p>
        /// The operation may be aborted by the progress monitor. In that event it
        /// will report what was found before the cancel operation was detected.
        /// Callers should ignore the result if monitor.isCancelled() is true. If a
        /// progress monitor is not needed, callers should use
        /// <see cref="Diff()">Diff()</see>
        /// instead. Progress reporting is crude and approximate and only intended
        /// for informing the user.
        /// </remarks>
        /// <param name="monitor">for reporting progress, may be null</param>
        /// <param name="estWorkTreeSize">number or estimated files in the working tree</param>
        /// <param name="estIndexSize">number of estimated entries in the cache</param>
        /// <param name="title"></param>
        /// <returns>if anything is different between index, tree, and workdir</returns>
        /// <exception cref="System.IO.IOException">System.IO.IOException</exception>
        public virtual bool Diff(ProgressMonitor monitor, int estWorkTreeSize, int estIndexSize
                                 , string title)
        {
            dirCache = repository.ReadDirCache();
            TreeWalk treeWalk = new TreeWalk(repository);

            treeWalk.Recursive = true;
            // add the trees (tree, dirchache, workdir)
            if (tree != null)
            {
                treeWalk.AddTree(tree);
            }
            else
            {
                treeWalk.AddTree(new EmptyTreeIterator());
            }
            treeWalk.AddTree(new DirCacheIterator(dirCache));
            treeWalk.AddTree(initialWorkingTreeIterator);
            ICollection <TreeFilter> filters = new AList <TreeFilter>(4);

            if (monitor != null)
            {
                // Get the maximum size of the work tree and index
                // and add some (quite arbitrary)
                if (estIndexSize == 0)
                {
                    estIndexSize = dirCache.GetEntryCount();
                }
                int total = Math.Max(estIndexSize * 10 / 9, estWorkTreeSize * 10 / 9);
                monitor.BeginTask(title, total);
                filters.AddItem(new IndexDiff.ProgressReportingFilter(monitor, total));
            }
            if (filter != null)
            {
                filters.AddItem(filter);
            }
            filters.AddItem(new SkipWorkTreeFilter(INDEX));
            filters.AddItem(new IndexDiffFilter(INDEX, WORKDIR));
            treeWalk.Filter = AndTreeFilter.Create(filters);
            while (treeWalk.Next())
            {
                AbstractTreeIterator treeIterator        = treeWalk.GetTree <AbstractTreeIterator>(TREE);
                DirCacheIterator     dirCacheIterator    = treeWalk.GetTree <DirCacheIterator>(INDEX);
                WorkingTreeIterator  workingTreeIterator = treeWalk.GetTree <WorkingTreeIterator>(WORKDIR
                                                                                                  );
                if (dirCacheIterator != null)
                {
                    DirCacheEntry dirCacheEntry = dirCacheIterator.GetDirCacheEntry();
                    if (dirCacheEntry != null && dirCacheEntry.Stage > 0)
                    {
                        conflicts.AddItem(treeWalk.PathString);
                        continue;
                    }
                }
                if (treeIterator != null)
                {
                    if (dirCacheIterator != null)
                    {
                        if (!treeIterator.IdEqual(dirCacheIterator) || treeIterator.EntryRawMode != dirCacheIterator
                            .EntryRawMode)
                        {
                            // in repo, in index, content diff => changed
                            changed.AddItem(treeWalk.PathString);
                        }
                    }
                    else
                    {
                        // in repo, not in index => removed
                        removed.AddItem(treeWalk.PathString);
                        if (workingTreeIterator != null)
                        {
                            untracked.AddItem(treeWalk.PathString);
                        }
                    }
                }
                else
                {
                    if (dirCacheIterator != null)
                    {
                        // not in repo, in index => added
                        added.AddItem(treeWalk.PathString);
                    }
                    else
                    {
                        // not in repo, not in index => untracked
                        if (workingTreeIterator != null && !workingTreeIterator.IsEntryIgnored())
                        {
                            untracked.AddItem(treeWalk.PathString);
                        }
                    }
                }
                if (dirCacheIterator != null)
                {
                    if (workingTreeIterator == null)
                    {
                        // in index, not in workdir => missing
                        missing.AddItem(treeWalk.PathString);
                    }
                    else
                    {
                        if (workingTreeIterator.IsModified(dirCacheIterator.GetDirCacheEntry(), true))
                        {
                            // in index, in workdir, content differs => modified
                            modified.AddItem(treeWalk.PathString);
                        }
                    }
                }
            }
            // consume the remaining work
            if (monitor != null)
            {
                monitor.EndTask();
            }
            if (added.IsEmpty() && changed.IsEmpty() && removed.IsEmpty() && missing.IsEmpty(
                    ) && modified.IsEmpty() && untracked.IsEmpty())
            {
                return(false);
            }
            else
            {
                return(true);
            }
        }
Пример #10
0
        /// <exception cref="NGit.Errors.MissingObjectException"></exception>
        /// <exception cref="NGit.Errors.IncorrectObjectTypeException"></exception>
        /// <exception cref="System.IO.IOException"></exception>
        public override bool Include(TreeWalk tw)
        {
            // If the working tree file doesn't exist, it does exist for at least
            // one other so include this difference.
            int wm = tw.GetRawMode(workingTree);

            if (wm == 0)
            {
                return(true);
            }
            // If the path does not appear in the DirCache and its ignored
            // we can avoid returning a result here, but only if its not in any
            // other tree.
            int cnt = tw.TreeCount;
            int dm  = tw.GetRawMode(dirCache);

            if (dm == 0)
            {
                if (honorIgnores && WorkingTree(tw).IsEntryIgnored())
                {
                    int i = 0;
                    for (; i < cnt; i++)
                    {
                        if (i == dirCache || i == workingTree)
                        {
                            continue;
                        }
                        if (tw.GetRawMode(i) != 0)
                        {
                            break;
                        }
                    }
                    // If i is cnt then the path does not appear in any other tree,
                    // and this working tree entry can be safely ignored.
                    return(i == cnt ? false : true);
                }
                else
                {
                    // In working tree and not ignored, and not in DirCache.
                    return(true);
                }
            }
            // Always include subtrees as WorkingTreeIterator cannot provide
            // efficient elimination of unmodified subtrees.
            if (tw.IsSubtree)
            {
                return(true);
            }
            // Try the inexpensive comparisons between index and all real trees
            // first. Only if we don't find a diff here we have to bother with
            // the working tree
            for (int i_1 = 0; i_1 < cnt; i_1++)
            {
                if (i_1 == dirCache || i_1 == workingTree)
                {
                    continue;
                }
                if (tw.GetRawMode(i_1) != dm || !tw.IdEqual(i_1, dirCache))
                {
                    return(true);
                }
            }
            // Only one chance left to detect a diff: between index and working
            // tree. Make use of the WorkingTreeIterator#isModified() method to
            // avoid computing SHA1 on filesystem content if not really needed.
            WorkingTreeIterator wi = WorkingTree(tw);
            DirCacheIterator    di = tw.GetTree <DirCacheIterator>(dirCache);

            return(wi.IsModified(di.GetDirCacheEntry(), true));
        }
Пример #11
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(AbstractTreeIterator h, AbstractTreeIterator m
                                           , DirCacheBuildIterator i, WorkingTreeIterator f)
        {
            DirCacheEntry dce;
            string        name = walk.PathString;

            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);
            // 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(h.EntryFileMode) ? unchecked ((int)(0xD00)) : unchecked (
                    (int)(0xF00));
            }
            if (i != null)
            {
                ffMask |= FileMode.TREE.Equals(i.EntryFileMode) ? unchecked ((int)(0x0D0)) : unchecked (
                    (int)(0x0F0));
            }
            if (m != null)
            {
                ffMask |= FileMode.TREE.Equals(m.EntryFileMode) ? 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, i.GetDirCacheEntry(), h, m);
                    }
                    else
                    {
                        // 1
                        Update(name, m.EntryObjectId, m.EntryFileMode);
                    }
                    // 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 (!iId.equals(mId))
                    //   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, m.EntryFileMode);
                    break;
                }

                case unchecked ((int)(0xDF0)):
                case unchecked ((int)(0x0FD)):
                {
                    // conflict without a rule
                    // 15
                    Conflict(name, (i != null) ? i.GetDirCacheEntry() : null, h, m);
                    break;
                }

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

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

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

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

                default:
                {
                    Keep(i.GetDirCacheEntry());
                    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 dirty worktree: the index is empty but we have a
                    // workingtree-file
                    if (mId == null || !mId.Equals(f.EntryObjectId))
                    {
                        Conflict(name, null, h, m);
                        return;
                    }
                }
                if (h == null)
                {
                    Update(name, mId, m.EntryFileMode);
                }
                else
                {
                    // 1
                    if (m == null)
                    {
                        Remove(name);
                    }
                    else
                    {
                        // 2
                        Update(name, mId, m.EntryFileMode);
                    }
                }
            }
            else
            {
                // 3
                dce = i.GetDirCacheEntry();
                if (h == null)
                {
                    if (m == null || mId.Equals(iId))
                    {
                        if (m == null && walk.IsDirectoryFileConflict())
                        {
                            if (dce != null && (f == null || f.IsModified(dce, true)))
                            {
                                Conflict(name, i.GetDirCacheEntry(), h, m);
                            }
                            else
                            {
                                Remove(name);
                            }
                        }
                        else
                        {
                            Keep(i.GetDirCacheEntry());
                        }
                    }
                    else
                    {
                        Conflict(name, i.GetDirCacheEntry(), h, m);
                    }
                }
                else
                {
                    if (m == null)
                    {
                        if (hId.Equals(iId))
                        {
                            if (f == null || f.IsModified(dce, true))
                            {
                                Conflict(name, i.GetDirCacheEntry(), h, m);
                            }
                            else
                            {
                                Remove(name);
                            }
                        }
                        else
                        {
                            Conflict(name, i.GetDirCacheEntry(), h, m);
                        }
                    }
                    else
                    {
                        if (!hId.Equals(mId) && !hId.Equals(iId) && !mId.Equals(iId))
                        {
                            Conflict(name, i.GetDirCacheEntry(), h, m);
                        }
                        else
                        {
                            if (hId.Equals(iId) && !mId.Equals(iId))
                            {
                                if (dce != null && (f == null || f.IsModified(dce, true)))
                                {
                                    Conflict(name, i.GetDirCacheEntry(), h, m);
                                }
                                else
                                {
                                    Update(name, mId, m.EntryFileMode);
                                }
                            }
                            else
                            {
                                Keep(i.GetDirCacheEntry());
                            }
                        }
                    }
                }
            }
        }
Пример #12
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)
     {
         // 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());
             }
         }
     }
 }
Пример #13
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 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);
        }