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 virtual void TestUpdateSmudgedEntries() { git.BranchCreate().SetName("test2").Call(); RefUpdate rup = db.UpdateRef(Constants.HEAD); rup.Link("refs/heads/test2"); FilePath file = new FilePath(db.WorkTree, "Test.txt"); long size = file.Length(); long mTime = file.LastModified() - 5000L; NUnit.Framework.Assert.IsTrue(file.SetLastModified(mTime)); DirCache cache = DirCache.Lock(db.GetIndexFile(), db.FileSystem); DirCacheEntry entry = cache.GetEntry("Test.txt"); NUnit.Framework.Assert.IsNotNull(entry); entry.SetLength(0); entry.LastModified = 0; cache.Write(); NUnit.Framework.Assert.IsTrue(cache.Commit()); cache = DirCache.Read(db.GetIndexFile(), db.FileSystem); entry = cache.GetEntry("Test.txt"); NUnit.Framework.Assert.IsNotNull(entry); NUnit.Framework.Assert.AreEqual(0, entry.Length); NUnit.Framework.Assert.AreEqual(0, entry.LastModified); db.GetIndexFile().SetLastModified(db.GetIndexFile().LastModified() - 5000); NUnit.Framework.Assert.IsNotNull(git.Checkout().SetName("test").Call()); cache = DirCache.Read(db.GetIndexFile(), db.FileSystem); entry = cache.GetEntry("Test.txt"); NUnit.Framework.Assert.IsNotNull(entry); NUnit.Framework.Assert.AreEqual(size, entry.Length); NUnit.Framework.Assert.AreEqual(mTime, entry.LastModified); }
/// <summary> /// adds a entry to the index builder which is a copy of the specified /// DirCacheEntry /// </summary> /// <param name="e">the entry which should be copied</param> /// <returns>the entry which was added to the index</returns> private DirCacheEntry Keep(DirCacheEntry e) { DirCacheEntry newEntry = new DirCacheEntry(e.PathString, e.Stage); newEntry.FileMode = e.FileMode; newEntry.SetObjectId(e.GetObjectId()); newEntry.LastModified = e.LastModified; newEntry.SetLength(e.Length); builder.Add(newEntry); return(newEntry); }
/// <summary>adds a new path with the specified stage to the index builder</summary> /// <param name="path"></param> /// <param name="p"></param> /// <param name="stage"></param> /// <param name="lastMod"></param> /// <param name="len"></param> /// <returns>the entry which was added to the index</returns> private DirCacheEntry Add(byte[] path, CanonicalTreeParser p, int stage, long lastMod , long len) { if (p != null && !p.EntryFileMode.Equals(FileMode.TREE)) { DirCacheEntry e = new DirCacheEntry(path, stage); e.FileMode = p.EntryFileMode; e.SetObjectId(p.EntryObjectId); e.LastModified = lastMod; e.SetLength(len); builder.Add(e); return(e); } return(null); }
/// <exception cref="System.IO.IOException"></exception> private DirCacheEntry AddEntryToBuilder(string path, FilePath file, ObjectInserter newObjectInserter, DirCacheBuilder builder, int stage) { FileInputStream inputStream = new FileInputStream(file); ObjectId id = newObjectInserter.Insert(Constants.OBJ_BLOB, file.Length(), inputStream ); inputStream.Close(); DirCacheEntry entry = new DirCacheEntry(path, stage); entry.SetObjectId(id); entry.FileMode = FileMode.REGULAR_FILE; entry.LastModified = file.LastModified(); entry.SetLength((int)file.Length()); builder.Add(entry); return(entry); }
/// <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(); } } }
/// <summary>Updates the index after a content merge has happened.</summary> /// <remarks> /// Updates the index after a content merge has happened. If no conflict has /// occurred this includes persisting the merged content to the object /// database. In case of conflicts this method takes care to write the /// correct stages to the index. /// </remarks> /// <param name="base"></param> /// <param name="ours"></param> /// <param name="theirs"></param> /// <param name="result"></param> /// <param name="of"></param> /// <exception cref="System.IO.FileNotFoundException">System.IO.FileNotFoundException /// </exception> /// <exception cref="System.IO.IOException">System.IO.IOException</exception> private void UpdateIndex(CanonicalTreeParser @base, CanonicalTreeParser ours, CanonicalTreeParser theirs, MergeResult <RawText> result, FilePath of) { if (result.ContainsConflicts()) { // a conflict occurred, the file will contain conflict markers // the index will be populated with the three stages and only the // workdir (if used) contains the halfways merged content Add(tw.RawPath, @base, DirCacheEntry.STAGE_1, 0, 0); Add(tw.RawPath, ours, DirCacheEntry.STAGE_2, 0, 0); Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3, 0, 0); mergeResults.Put(tw.PathString, result.Upcast()); } else { // no conflict occurred, the file will contain fully merged content. // the index will be populated with the new merged version DirCacheEntry dce = new DirCacheEntry(tw.PathString); int newMode = MergeFileModes(tw.GetRawMode(0), tw.GetRawMode(1), tw.GetRawMode(2) ); // set the mode for the new content. Fall back to REGULAR_FILE if // you can't merge modes of OURS and THEIRS dce.FileMode = (newMode == FileMode.MISSING.GetBits()) ? FileMode.REGULAR_FILE : FileMode.FromBits(newMode); dce.LastModified = of.LastModified(); dce.SetLength((int)of.Length()); InputStream @is = new FileInputStream(of); try { dce.SetObjectId(GetObjectInserter().Insert(Constants.OBJ_BLOB, of.Length(), @is)); } finally { @is.Close(); if (inCore) { FileUtils.Delete(of); } } builder.Add(dce); } }
/// <summary>Compares the entries content with the content in the filesystem.</summary> /// <remarks> /// Compares the entries content with the content in the filesystem. /// Unsmudges the entry when it is detected that it is clean. /// </remarks> /// <param name="entry">the entry to be checked</param> /// <returns> /// <code>true</code> if the content matches, <code>false</code> /// otherwise /// </returns> private bool ContentCheck(DirCacheEntry entry) { if (EntryObjectId.Equals(entry.GetObjectId())) { // Content has not changed // We know the entry can't be racily clean because it's still clean. // Therefore we unsmudge the entry! // If by any chance we now unsmudge although we are still in the // same time-slot as the last modification to the index file the // next index write operation will smudge again. // Caution: we are unsmudging just by setting the length of the // in-memory entry object. It's the callers task to detect that we // have modified the entry and to persist the modified index. entry.SetLength((int)GetEntryLength()); return(false); } else { // Content differs: that's a real change! return(true); } }
/// <summary>Resets the index to represent exactly some filesystem content.</summary> /// <remarks> /// Resets the index to represent exactly some filesystem content. E.g. the /// following call will replace the index with the working tree content: /// <p> /// <code>resetIndex(new FileSystemIterator(db))</code> /// <p> /// This method can be used by testcases which first prepare a new commit /// somewhere in the filesystem (e.g. in the working-tree) and then want to /// have an index which matches their prepared content. /// </remarks> /// <param name="treeItr"> /// a /// <see cref="NGit.Treewalk.FileTreeIterator">NGit.Treewalk.FileTreeIterator</see> /// which determines which files should /// go into the new index /// </param> /// <exception cref="System.IO.FileNotFoundException">System.IO.FileNotFoundException /// </exception> /// <exception cref="System.IO.IOException">System.IO.IOException</exception> protected internal virtual void ResetIndex(FileTreeIterator treeItr) { ObjectInserter inserter = db.NewObjectInserter(); DirCacheBuilder builder = db.LockDirCache().Builder(); DirCacheEntry dce; while (!treeItr.Eof) { long len = treeItr.GetEntryLength(); dce = new DirCacheEntry(treeItr.EntryPathString); dce.FileMode = treeItr.EntryFileMode; dce.LastModified = treeItr.GetEntryLastModified(); dce.SetLength((int)len); FileInputStream @in = new FileInputStream(treeItr.GetEntryFile()); dce.SetObjectId(inserter.Insert(Constants.OBJ_BLOB, len, @in)); @in.Close(); builder.Add(dce); treeItr.Next(1); } builder.Commit(); inserter.Flush(); inserter.Release(); }
/// <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); }
/// <exception cref="System.IO.IOException"></exception> private DirCache CreateTemporaryIndex(ObjectId headId, DirCache index) { ObjectInserter inserter = null; // get DirCacheEditor to modify the index if required DirCacheEditor dcEditor = index.Editor(); // get DirCacheBuilder for newly created in-core index to build a // temporary index for this commit DirCache inCoreIndex = DirCache.NewInCore(); DirCacheBuilder dcBuilder = inCoreIndex.Builder(); onlyProcessed = new bool[only.Count]; bool emptyCommit = true; TreeWalk treeWalk = new TreeWalk(repo); int dcIdx = treeWalk.AddTree(new DirCacheIterator(index)); int fIdx = treeWalk.AddTree(new FileTreeIterator(repo)); int hIdx = -1; if (headId != null) { hIdx = treeWalk.AddTree(new RevWalk(repo).ParseTree(headId)); } treeWalk.Recursive = true; while (treeWalk.Next()) { string path = treeWalk.PathString; // check if current entry's path matches a specified path int pos = LookupOnly(path); CanonicalTreeParser hTree = null; if (hIdx != -1) { hTree = treeWalk.GetTree <CanonicalTreeParser>(hIdx); } if (pos >= 0) { // include entry in commit DirCacheIterator dcTree = treeWalk.GetTree <DirCacheIterator>(dcIdx); FileTreeIterator fTree = treeWalk.GetTree <FileTreeIterator>(fIdx); // check if entry refers to a tracked file bool tracked = dcTree != null || hTree != null; if (!tracked) { break; } if (fTree != null) { // create a new DirCacheEntry with data retrieved from disk DirCacheEntry dcEntry = new DirCacheEntry(path); long entryLength = fTree.GetEntryLength(); dcEntry.SetLength(entryLength); dcEntry.LastModified = fTree.GetEntryLastModified(); dcEntry.FileMode = fTree.GetIndexFileMode(dcTree); bool objectExists = (dcTree != null && fTree.IdEqual(dcTree)) || (hTree != null && fTree.IdEqual(hTree)); if (objectExists) { dcEntry.SetObjectId(fTree.EntryObjectId); } else { if (FileMode.GITLINK.Equals(dcEntry.FileMode)) { dcEntry.SetObjectId(fTree.EntryObjectId); } else { // insert object if (inserter == null) { inserter = repo.NewObjectInserter(); } long contentLength = fTree.GetEntryContentLength(); InputStream inputStream = fTree.OpenEntryStream(); try { dcEntry.SetObjectId(inserter.Insert(Constants.OBJ_BLOB, contentLength, inputStream )); } finally { inputStream.Close(); } } } // update index dcEditor.Add(new _PathEdit_375(dcEntry, path)); // add to temporary in-core index dcBuilder.Add(dcEntry); if (emptyCommit && (hTree == null || !hTree.IdEqual(fTree) || hTree.EntryRawMode != fTree.EntryRawMode)) { // this is a change emptyCommit = false; } } else { // if no file exists on disk, remove entry from index and // don't add it to temporary in-core index dcEditor.Add(new DirCacheEditor.DeletePath(path)); if (emptyCommit && hTree != null) { // this is a change emptyCommit = false; } } // keep track of processed path onlyProcessed[pos] = true; } else { // add entries from HEAD for all other paths if (hTree != null) { // create a new DirCacheEntry with data retrieved from HEAD DirCacheEntry dcEntry = new DirCacheEntry(path); dcEntry.SetObjectId(hTree.EntryObjectId); dcEntry.FileMode = hTree.EntryFileMode; // add to temporary in-core index dcBuilder.Add(dcEntry); } } } // there must be no unprocessed paths left at this point; otherwise an // untracked or unknown path has been specified for (int i = 0; i < onlyProcessed.Length; i++) { if (!onlyProcessed[i]) { throw new JGitInternalException(MessageFormat.Format(JGitText.Get().entryNotFoundByPath , only[i])); } } // there must be at least one change if (emptyCommit) { throw new JGitInternalException(JGitText.Get().emptyCommit); } // update index dcEditor.Commit(); // finish temporary in-core index used for this commit dcBuilder.Finish(); return(inCoreIndex); }
/// <exception cref="System.IO.FileNotFoundException"></exception> /// <exception cref="System.InvalidOperationException"></exception> /// <exception cref="System.IO.IOException"></exception> private bool ContentMerge(CanonicalTreeParser @base, CanonicalTreeParser ours, CanonicalTreeParser theirs) { MergeFormatter fmt = new MergeFormatter(); RawText baseText = @base == null ? RawText.EMPTY_TEXT : GetRawText(@base.EntryObjectId , db); // do the merge MergeResult <RawText> result = mergeAlgorithm.Merge(RawTextComparator.DEFAULT, baseText , GetRawText(ours.EntryObjectId, db), GetRawText(theirs.EntryObjectId, db)); FilePath of = null; FileOutputStream fos; if (!inCore) { FilePath workTree = db.WorkTree; if (workTree == null) { // TODO: This should be handled by WorkingTreeIterators which // support write operations throw new NotSupportedException(); } of = new FilePath(workTree, tw.PathString); fos = new FileOutputStream(of); try { fmt.FormatMerge(fos, result, Arrays.AsList(commitNames), Constants.CHARACTER_ENCODING ); } finally { fos.Close(); } } else { if (!result.ContainsConflicts()) { // When working inCore, only trivial merges can be handled, // so we generate objects only in conflict free cases of = FilePath.CreateTempFile("merge_", "_temp", null); fos = new FileOutputStream(of); try { fmt.FormatMerge(fos, result, Arrays.AsList(commitNames), Constants.CHARACTER_ENCODING ); } finally { fos.Close(); } } } if (result.ContainsConflicts()) { // a conflict occurred, the file will contain conflict markers // the index will be populated with the three stages and only the // workdir (if used) contains the halfways merged content Add(tw.RawPath, @base, DirCacheEntry.STAGE_1); Add(tw.RawPath, ours, DirCacheEntry.STAGE_2); Add(tw.RawPath, theirs, DirCacheEntry.STAGE_3); mergeResults.Put(tw.PathString, result.Upcast()); return(false); } else { // no conflict occurred, the file will contain fully merged content. // the index will be populated with the new merged version DirCacheEntry dce = new DirCacheEntry(tw.PathString); dce.FileMode = tw.GetFileMode(0); dce.LastModified = of.LastModified(); dce.SetLength((int)of.Length()); InputStream @is = new FileInputStream(of); try { dce.SetObjectId(oi.Insert(Constants.OBJ_BLOB, of.Length(), @is)); } finally { @is.Close(); if (inCore) { FileUtils.Delete(of); } } builder.Add(dce); return(true); } }
/// <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(); } }
public override void Apply(DirCacheEntry ent) { ent.FileMode = FileMode.REGULAR_FILE; ent.SetLength(f.Length()); ent.SetObjectId(id); }