Beispiel #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();
            }
        }
Beispiel #2
0
        /// <summary>
        /// Executes the
        /// <code>Add</code>
        /// command. Each instance of this class should only
        /// be used for one invocation of the command. Don't call this method twice
        /// on an instance.
        /// </summary>
        /// <returns>the DirCache after Add</returns>
        /// <exception cref="NGit.Api.Errors.GitAPIException"></exception>
        /// <exception cref="NGit.Api.Errors.NoFilepatternException"></exception>
        public override DirCache Call()
        {
            if (filepatterns.IsEmpty())
            {
                throw new NoFilepatternException(JGitText.Get().atLeastOnePatternIsRequired);
            }
            CheckCallable();
            DirCache dc     = null;
            bool     addAll = false;

            if (filepatterns.Contains("."))
            {
                addAll = true;
            }
            ObjectInserter inserter = repo.NewObjectInserter();

            try
            {
                dc = repo.LockDirCache();
                DirCacheIterator c;
                DirCacheBuilder  builder = dc.Builder();
                TreeWalk         tw      = new TreeWalk(repo);
                tw.AddTree(new DirCacheBuildIterator(builder));
                if (workingTreeIterator == null)
                {
                    workingTreeIterator = new FileTreeIterator(repo);
                }
                tw.AddTree(workingTreeIterator);
                tw.Recursive = true;
                if (!addAll)
                {
                    tw.Filter = PathFilterGroup.CreateFromStrings(filepatterns);
                }
                string lastAddedFile = null;
                while (tw.Next())
                {
                    string path           = tw.PathString;
                    WorkingTreeIterator f = tw.GetTree <WorkingTreeIterator>(1);
                    if (tw.GetTree <DirCacheIterator>(0) == null && f != null && f.IsEntryIgnored())
                    {
                    }
                    else
                    {
                        // file is not in index but is ignored, do nothing
                        // In case of an existing merge conflict the
                        // DirCacheBuildIterator iterates over all stages of
                        // this path, we however want to add only one
                        // new DirCacheEntry per path.
                        if (!(path.Equals(lastAddedFile)))
                        {
                            if (!(update && tw.GetTree <DirCacheIterator>(0) == null))
                            {
                                c = tw.GetTree <DirCacheIterator>(0);
                                if (f != null)
                                {
                                    // the file exists
                                    long          sz    = f.GetEntryLength();
                                    DirCacheEntry entry = new DirCacheEntry(path);
                                    if (c == null || c.GetDirCacheEntry() == null || !c.GetDirCacheEntry().IsAssumeValid)
                                    {
                                        FileMode mode = f.GetIndexFileMode(c);
                                        entry.FileMode = mode;
                                        if (FileMode.GITLINK != mode)
                                        {
                                            entry.SetLength(sz);
                                            entry.LastModified = f.GetEntryLastModified();
                                            long        contentSize = f.GetEntryContentLength();
                                            InputStream @in         = f.OpenEntryStream();
                                            try
                                            {
                                                entry.SetObjectId(inserter.Insert(Constants.OBJ_BLOB, contentSize, @in));
                                            }
                                            finally
                                            {
                                                @in.Close();
                                            }
                                        }
                                        else
                                        {
                                            entry.SetObjectId(f.EntryObjectId);
                                        }
                                        builder.Add(entry);
                                        lastAddedFile = path;
                                    }
                                    else
                                    {
                                        builder.Add(c.GetDirCacheEntry());
                                    }
                                }
                                else
                                {
                                    if (c != null && (!update || FileMode.GITLINK == c.EntryFileMode))
                                    {
                                        builder.Add(c.GetDirCacheEntry());
                                    }
                                }
                            }
                        }
                    }
                }
                inserter.Flush();
                builder.Commit();
                SetCallable(false);
            }
            catch (IOException e)
            {
                throw new JGitInternalException(JGitText.Get().exceptionCaughtDuringExecutionOfAddCommand
                                                , e);
            }
            finally
            {
                inserter.Release();
                if (dc != null)
                {
                    dc.Unlock();
                }
            }
            return(dc);
        }
Beispiel #3
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);
                        }
                    }
                }
            }
        }
Beispiel #4
0
        /// <summary>
        /// Run the diff operation. Until this is called, all lists will be empty
        /// </summary>
        /// <returns>true if anything is different between index, tree, and workdir</returns>
        private void UpdateDirectory(IEnumerable <string> paths, bool recursive)
        {
            RevWalk  rw     = new RevWalk(Repository);
            ObjectId id     = Repository.Resolve(Constants.HEAD);
            var      commit = id != null?rw.ParseCommit(id) : null;

            TreeWalk treeWalk = new TreeWalk(Repository);

            treeWalk.Reset();
            treeWalk.Recursive = false;

            if (commit != null)
            {
                treeWalk.AddTree(commit.Tree);
            }
            else
            {
                treeWalk.AddTree(new EmptyTreeIterator());
            }

            DirCache dc = Repository.ReadDirCache();

            treeWalk.AddTree(new DirCacheIterator(dc));

            FileTreeIterator workTree = new FileTreeIterator(Repository.WorkTree, Repository.FileSystem, WorkingTreeOptions.KEY.Parse(Repository.GetConfig()));

            treeWalk.AddTree(workTree);

            List <TreeFilter> filters = new List <TreeFilter> ();

            filters.Add(new SkipWorkTreeFilter(1));

            var pathFilters = paths.Where(p => p != ".").Select(p => PathFilter.Create(p)).ToArray();

            if (pathFilters.Length > 1)
            {
                filters.Add(OrTreeFilter.Create(pathFilters));                   // Use an OR to join all path filters
            }
            else if (pathFilters.Length == 1)
            {
                filters.Add(pathFilters[0]);
            }

            if (filters.Count > 1)
            {
                treeWalk.Filter = AndTreeFilter.Create(filters);
            }
            else
            {
                treeWalk.Filter = filters[0];
            }

            while (treeWalk.Next())
            {
                AbstractTreeIterator treeIterator        = treeWalk.GetTree <AbstractTreeIterator>(0);
                DirCacheIterator     dirCacheIterator    = treeWalk.GetTree <DirCacheIterator>(1);
                WorkingTreeIterator  workingTreeIterator = treeWalk.GetTree <WorkingTreeIterator>(2);
                NGit.FileMode        fileModeTree        = treeWalk.GetFileMode(0);

                if (treeWalk.IsSubtree)
                {
                    treeWalk.EnterSubtree();
                    continue;
                }

                int stage = dirCacheIterator != null?dirCacheIterator.GetDirCacheEntry().Stage : 0;

                if (stage > 1)
                {
                    continue;
                }
                else if (stage == 1)
                {
                    MergeConflict.Add(dirCacheIterator.EntryPathString);
                    changesExist = true;
                    continue;
                }

                if (treeIterator != null)
                {
                    if (dirCacheIterator != null)
                    {
                        if (!treeIterator.EntryObjectId.Equals(dirCacheIterator.EntryObjectId))
                        {
                            // in repo, in index, content diff => changed
                            Modified.Add(dirCacheIterator.EntryPathString);
                            changesExist = true;
                        }
                    }
                    else
                    {
                        // in repo, not in index => removed
                        if (!fileModeTree.Equals(NGit.FileMode.TYPE_TREE))
                        {
                            Removed.Add(treeIterator.EntryPathString);
                            changesExist = true;
                        }
                    }
                }
                else
                {
                    if (dirCacheIterator != null)
                    {
                        // not in repo, in index => added
                        Added.Add(dirCacheIterator.EntryPathString);
                        changesExist = true;
                    }
                    else
                    {
                        // not in repo, not in index => untracked
                        if (workingTreeIterator != null && !workingTreeIterator.IsEntryIgnored())
                        {
                            Untracked.Add(workingTreeIterator.EntryPathString);
                            changesExist = true;
                        }
                    }
                }
                if (dirCacheIterator != null)
                {
                    if (workingTreeIterator == null)
                    {
                        // in index, not in workdir => missing
                        Missing.Add(dirCacheIterator.EntryPathString);
                        changesExist = true;
                    }
                    else
                    {
                        // Workaround to file time resolution issues
                        long itime = dirCacheIterator.GetDirCacheEntry().LastModified;
                        long ftime = workingTreeIterator.GetEntryLastModified();
                        if (itime / 1000 != ftime / 1000)
                        {
                            if (!dirCacheIterator.IdEqual(workingTreeIterator))
                            {
                                // in index, in workdir, content differs => modified
                                Modified.Add(dirCacheIterator.EntryPathString);
                                changesExist = true;
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Stash the contents on the working directory and index in separate commits
        /// and reset to the current HEAD commit.
        /// </summary>
        /// <remarks>
        /// Stash the contents on the working directory and index in separate commits
        /// and reset to the current HEAD commit.
        /// </remarks>
        /// <returns>stashed commit or null if no changes to stash</returns>
        /// <exception cref="NGit.Api.Errors.GitAPIException">NGit.Api.Errors.GitAPIException
        ///     </exception>
        public override RevCommit Call()
        {
            CheckCallable();
            Ref          head   = GetHead();
            ObjectReader reader = repo.NewObjectReader();

            try
            {
                RevCommit      headCommit = ParseCommit(reader, head.GetObjectId());
                DirCache       cache      = repo.LockDirCache();
                ObjectInserter inserter   = repo.NewObjectInserter();
                ObjectId       commitId;
                try
                {
                    TreeWalk treeWalk = new TreeWalk(reader);
                    treeWalk.Recursive = true;
                    treeWalk.AddTree(headCommit.Tree);
                    treeWalk.AddTree(new DirCacheIterator(cache));
                    treeWalk.AddTree(new FileTreeIterator(repo));
                    treeWalk.Filter = AndTreeFilter.Create(new SkipWorkTreeFilter(1), new IndexDiffFilter
                                                               (1, 2));
                    // Return null if no local changes to stash
                    if (!treeWalk.Next())
                    {
                        return(null);
                    }
                    MutableObjectId id = new MutableObjectId();
                    IList <DirCacheEditor.PathEdit> wtEdits = new AList <DirCacheEditor.PathEdit>();
                    IList <string> wtDeletes = new AList <string>();
                    do
                    {
                        AbstractTreeIterator headIter  = treeWalk.GetTree <AbstractTreeIterator>(0);
                        DirCacheIterator     indexIter = treeWalk.GetTree <DirCacheIterator>(1);
                        WorkingTreeIterator  wtIter    = treeWalk.GetTree <WorkingTreeIterator>(2);
                        if (headIter != null && indexIter != null && wtIter != null)
                        {
                            if (!indexIter.GetDirCacheEntry().IsMerged())
                            {
                                throw new UnmergedPathsException(new UnmergedPathException(indexIter.GetDirCacheEntry
                                                                                               ()));
                            }
                            if (wtIter.IdEqual(indexIter) || wtIter.IdEqual(headIter))
                            {
                                continue;
                            }
                            treeWalk.GetObjectId(id, 0);
                            DirCacheEntry entry = new DirCacheEntry(treeWalk.RawPath);
                            entry.SetLength(wtIter.GetEntryLength());
                            entry.LastModified = wtIter.GetEntryLastModified();
                            entry.FileMode     = wtIter.EntryFileMode;
                            long        contentLength = wtIter.GetEntryContentLength();
                            InputStream @in           = wtIter.OpenEntryStream();
                            try
                            {
                                entry.SetObjectId(inserter.Insert(Constants.OBJ_BLOB, contentLength, @in));
                            }
                            finally
                            {
                                @in.Close();
                            }
                            wtEdits.AddItem(new _PathEdit_273(entry, entry));
                        }
                        else
                        {
                            if (indexIter == null)
                            {
                                wtDeletes.AddItem(treeWalk.PathString);
                            }
                            else
                            {
                                if (wtIter == null && headIter != null)
                                {
                                    wtDeletes.AddItem(treeWalk.PathString);
                                }
                            }
                        }
                    }while (treeWalk.Next());
                    string branch = Repository.ShortenRefName(head.GetTarget().GetName());
                    // Commit index changes
                    NGit.CommitBuilder builder = CreateBuilder(headCommit);
                    builder.TreeId  = cache.WriteTree(inserter);
                    builder.Message = MessageFormat.Format(indexMessage, branch, headCommit.Abbreviate
                                                               (7).Name, headCommit.GetShortMessage());
                    ObjectId indexCommit = inserter.Insert(builder);
                    // Commit working tree changes
                    if (!wtEdits.IsEmpty() || !wtDeletes.IsEmpty())
                    {
                        DirCacheEditor editor = cache.Editor();
                        foreach (DirCacheEditor.PathEdit edit in wtEdits)
                        {
                            editor.Add(edit);
                        }
                        foreach (string path in wtDeletes)
                        {
                            editor.Add(new DirCacheEditor.DeletePath(path));
                        }
                        editor.Finish();
                    }
                    builder.AddParentId(indexCommit);
                    builder.Message = MessageFormat.Format(workingDirectoryMessage, branch, headCommit
                                                           .Abbreviate(7).Name, headCommit.GetShortMessage());
                    builder.TreeId = cache.WriteTree(inserter);
                    commitId       = inserter.Insert(builder);
                    inserter.Flush();
                    UpdateStashRef(commitId, builder.Author, builder.Message);
                }
                finally
                {
                    inserter.Release();
                    cache.Unlock();
                }
                // Hard reset to HEAD
                new ResetCommand(repo).SetMode(ResetCommand.ResetType.HARD).Call();
                // Return stashed commit
                return(ParseCommit(reader, commitId));
            }
            catch (IOException e)
            {
                throw new JGitInternalException(JGitText.Get().stashFailed, e);
            }
            finally
            {
                reader.Release();
            }
        }