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(); } }
public override bool Include(TreeWalk walker) { DirCacheIterator i = walker.GetTree <DirCacheIterator>(treeIdx); if (i == null) { return(true); } DirCacheEntry e = i.GetDirCacheEntry(); return(e == null || !e.IsSkipWorkTree); }
/// <exception cref="System.IO.IOException"></exception> private void ResetIndex(RevCommit commit) { DirCache dc = repo.LockDirCache(); TreeWalk walk = null; try { DirCacheEditor editor = dc.Editor(); walk = new TreeWalk(repo); walk.AddTree(commit.Tree); walk.AddTree(new DirCacheIterator(dc)); walk.Recursive = true; while (walk.Next()) { AbstractTreeIterator cIter = walk.GetTree <AbstractTreeIterator>(0); if (cIter == null) { editor.Add(new DirCacheEditor.DeletePath(walk.PathString)); continue; } DirCacheEntry entry = new DirCacheEntry(walk.RawPath); entry.FileMode = cIter.EntryFileMode; entry.SetObjectIdFromRaw(cIter.IdBuffer, cIter.IdOffset); DirCacheIterator dcIter = walk.GetTree <DirCacheIterator>(1); if (dcIter != null && dcIter.IdEqual(cIter)) { DirCacheEntry indexEntry = dcIter.GetDirCacheEntry(); entry.LastModified = indexEntry.LastModified; entry.SetLength(indexEntry.Length); } editor.Add(new _PathEdit_356(entry, entry)); } editor.Commit(); } finally { dc.Unlock(); if (walk != null) { walk.Release(); } } }
public static List <string> GetConflictedFiles(NGit.Repository repo) { List <string> list = new List <string> (); TreeWalk treeWalk = new TreeWalk(repo); treeWalk.Reset(); treeWalk.Recursive = true; DirCache dc = repo.ReadDirCache(); treeWalk.AddTree(new DirCacheIterator(dc)); while (treeWalk.Next()) { DirCacheIterator dirCacheIterator = treeWalk.GetTree <DirCacheIterator>(0); var ce = dirCacheIterator.GetDirCacheEntry(); if (ce != null && ce.Stage == 1) { list.Add(ce.PathString); } } return(list); }
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)); }
/// <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>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); } }
/// <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(); } }
/// <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)); }