/// <summary>Return the merge base of two commits.</summary> /// <remarks>Return the merge base of two commits.</remarks> /// <param name="aIdx"> /// index of the first commit in /// <see cref="sourceObjects">sourceObjects</see> /// . /// </param> /// <param name="bIdx"> /// index of the second commit in /// <see cref="sourceObjects">sourceObjects</see> /// . /// </param> /// <returns>the merge base of two commits</returns> /// <exception cref="NGit.Errors.IncorrectObjectTypeException">one of the input objects is not a commit. /// </exception> /// <exception cref="System.IO.IOException">objects are missing or multiple merge bases were found. /// </exception> public virtual RevCommit GetBaseCommit(int aIdx, int bIdx) { if (sourceCommits[aIdx] == null) { throw new IncorrectObjectTypeException(sourceObjects[aIdx], Constants.TYPE_COMMIT ); } if (sourceCommits[bIdx] == null) { throw new IncorrectObjectTypeException(sourceObjects[bIdx], Constants.TYPE_COMMIT ); } walk.Reset(); walk.SetRevFilter(RevFilter.MERGE_BASE); walk.MarkStart(sourceCommits[aIdx]); walk.MarkStart(sourceCommits[bIdx]); RevCommit @base = walk.Next(); if (@base == null) { return(null); } RevCommit base2 = walk.Next(); if (base2 != null) { throw new IOException(MessageFormat.Format(JGitText.Get().multipleMergeBasesFor, sourceCommits[aIdx].Name, sourceCommits[bIdx].Name, @base.Name, base2.Name)); } return(@base); }
private RevCommit ParseCommit(Repository repo, ObjectId id) { RevWalk rw = new RevWalk(repo); var head = rw.ParseCommit(id); rw.MarkStart(head); RevCommit commit = null; try { commit = rw.Next(); while (commit != null) { if (commit.Id.Name == id.Name) { return(commit); } commit = rw.Next(); } } finally { rw.Release(); } return(commit); }
/// <summary>Ensure this list contains at least a specified number of commits.</summary> /// <remarks> /// Ensure this list contains at least a specified number of commits. /// <p> /// The revision walker specified by /// <see cref="RevCommitList{E}.Source(RevWalk)">RevCommitList<E>.Source(RevWalk) /// </see> /// is pumped until /// the given number of commits are contained in this list. If there are /// fewer total commits available from the walk then the method will return /// early. Callers can test the final size of the list by /// <see cref="RevObjectList{E}.Count()">RevObjectList<E>.Count()</see> /// to /// determine if the high water mark specified was met. /// </remarks> /// <param name="highMark"> /// number of commits the caller wants this list to contain when /// the fill operation is complete. /// </param> /// <exception cref="System.IO.IOException"> /// see /// <see cref="RevWalk.Next()">RevWalk.Next()</see> /// </exception> /// <exception cref="NGit.Errors.IncorrectObjectTypeException"> /// see /// <see cref="RevWalk.Next()">RevWalk.Next()</see> /// </exception> /// <exception cref="NGit.Errors.MissingObjectException"> /// see /// <see cref="RevWalk.Next()">RevWalk.Next()</see> /// </exception> public virtual void FillTo(int highMark) { if (walker == null || size > highMark) { return; } RevCommit c = walker.Next(); if (c == null) { walker = null; return; } Enter(size, (E)c); AddItem((E)c); while (size <= highMark) { int index = size; RevObjectListBlock s = contents; while (index >> s.shift >= BLOCK_SIZE) { s = new RevObjectListBlock(s.shift + BLOCK_SHIFT); s.contents[0] = contents; contents = s; } while (s.shift > 0) { int i = index >> s.shift; index -= i << s.shift; if (s.contents[i] == null) { s.contents[i] = new RevObjectListBlock(s.shift - BLOCK_SHIFT); } s = (RevObjectListBlock)s.contents[i]; } object[] dst = s.contents; while (size <= highMark && index < BLOCK_SIZE) { c = walker.Next(); if (c == null) { walker = null; return; } Enter(size++, (E)c); dst[index++] = c; } } }
public virtual void TestFillToCommit() { Setup(3); RevWalk w = new RevWalk(db); w.MarkStart(w.LookupCommit(db.Resolve(Constants.HEAD))); w.Next(); RevCommit c = w.Next(); NUnit.Framework.Assert.IsNotNull(c, "should have found 2. commit"); list.FillTo(c, 5); NUnit.Framework.Assert.AreEqual(2, list.Count); NUnit.Framework.Assert.AreEqual("commit 1", list[1].GetFullMessage()); NUnit.Framework.Assert.IsNull(list[3]); }
/// <exception cref="System.IO.IOException"></exception> private bool WantSatisfied(RevObject want) { if (want.Has(SATISFIED)) { return(true); } walk.ResetRetain(SAVE); walk.MarkStart((RevCommit)want); if (oldestTime != 0) { walk.SetRevFilter(CommitTimeRevFilter.After(oldestTime * 1000L)); } for (; ;) { RevCommit c = walk.Next(); if (c == null) { break; } if (c.Has(PEER_HAS)) { AddCommonBase(c); want.Add(SATISFIED); return(true); } } return(false); }
/// <summary>Configure the generator to compute reverse blame (history of deletes).</summary> /// <remarks> /// Configure the generator to compute reverse blame (history of deletes). /// <p> /// This method is expensive as it immediately runs a RevWalk over the /// history spanning the expression /// <code>start..end</code> /// (end being more recent /// than start) and then performs the equivalent operation as /// <see cref="Push(string, NGit.AnyObjectId)">Push(string, NGit.AnyObjectId)</see> /// to begin blame traversal from the /// commit named by /// <code>start</code> /// walking forwards through history until /// <code>end</code> /// blaming line deletions. /// <p> /// A reverse blame may produce multiple sources for the same result line, /// each of these is a descendant commit that removed the line, typically /// this occurs when the same deletion appears in multiple side branches such /// as due to a cherry-pick. Applications relying on reverse should use /// <see cref="BlameResult">BlameResult</see> /// as it filters these duplicate sources and only /// remembers the first (oldest) deletion. /// </remarks> /// <param name="start"> /// oldest commit to traverse from. The result file will be loaded /// from this commit's tree. /// </param> /// <param name="end"> /// most recent commits to stop traversal at. Usually an active /// branch tip, tag, or HEAD. /// </param> /// <returns> /// /// <code>this</code> /// </returns> /// <exception cref="System.IO.IOException">the repository cannot be read.</exception> public virtual NGit.Blame.BlameGenerator Reverse <_T0>(AnyObjectId start, ICollection <_T0> end) where _T0 : ObjectId { InitRevPool(true); ReverseWalk.ReverseCommit result = (ReverseWalk.ReverseCommit)revPool.ParseCommit (start); if (!Find(result, resultPath)) { return(this); } revPool.MarkUninteresting(result); foreach (ObjectId id in end) { revPool.MarkStart(revPool.ParseCommit(id)); } while (revPool.Next() != null) { } // just pump the queue Candidate.ReverseCandidate c = new Candidate.ReverseCandidate(result, resultPath); c.sourceBlob = idBuf.ToObjectId(); c.LoadText(reader); c.regionList = new Region(0, 0, c.sourceText.Size()); remaining = c.sourceText.Size(); Push(c); return(this); }
/// <summary> /// Find the list of branches a given commit is reachable from when following /// parent.s /// <p> /// Note that this method calls /// <see cref="RevWalk.Reset()">RevWalk.Reset()</see> /// at the beginning. /// <p> /// In order to improve performance this method assumes clock skew among /// committers is never larger than 24 hours. /// </summary> /// <param name="commit">the commit we are looking at</param> /// <param name="revWalk">The RevWalk to be used.</param> /// <param name="refs">the set of branches we want to see reachability from</param> /// <returns>the list of branches a given commit is reachable from</returns> /// <exception cref="NGit.Errors.MissingObjectException">NGit.Errors.MissingObjectException /// </exception> /// <exception cref="NGit.Errors.IncorrectObjectTypeException">NGit.Errors.IncorrectObjectTypeException /// </exception> /// <exception cref="System.IO.IOException">System.IO.IOException</exception> public static IList <Ref> FindBranchesReachableFrom(RevCommit commit, RevWalk revWalk , ICollection <Ref> refs) { IList <Ref> result = new AList <Ref>(); // searches from branches can be cut off early if any parent of the // search-for commit is found. This is quite likely, so optimize for this. revWalk.MarkStart(Arrays.AsList(commit.Parents)); ObjectIdSubclassMap <ObjectId> cutOff = new ObjectIdSubclassMap <ObjectId>(); int SKEW = 24 * 3600; // one day clock skew foreach (Ref @ref in refs) { RevObject maybehead = revWalk.ParseAny(@ref.GetObjectId()); if (!(maybehead is RevCommit)) { continue; } RevCommit headCommit = (RevCommit)maybehead; // if commit is in the ref branch, then the tip of ref should be // newer than the commit we are looking for. Allow for a large // clock skew. if (headCommit.CommitTime + SKEW < commit.CommitTime) { continue; } IList <ObjectId> maybeCutOff = new AList <ObjectId>(cutOff.Size()); // guess rough size revWalk.ResetRetain(); revWalk.MarkStart(headCommit); RevCommit current; Ref found = null; while ((current = revWalk.Next()) != null) { if (AnyObjectId.Equals(current, commit)) { found = @ref; break; } if (cutOff.Contains(current)) { break; } maybeCutOff.AddItem(current.ToObjectId()); } if (found != null) { result.AddItem(@ref); } else { foreach (ObjectId id in maybeCutOff) { cutOff.AddIfAbsent(id); } } } return(result); }
/// <summary> /// Compute the tracking status for the <code>branchName</code> in /// <code>repository</code>. /// </summary> /// <remarks> /// Compute the tracking status for the <code>branchName</code> in /// <code>repository</code>. /// </remarks> /// <param name="repository">the git repository to compute the status from</param> /// <param name="branchName">the local branch</param> /// <returns>the tracking status, or null if it is not known</returns> /// <exception cref="System.IO.IOException">System.IO.IOException</exception> public static NGit.BranchTrackingStatus Of(Repository repository, string branchName ) { BranchConfig branchConfig = new BranchConfig(repository.GetConfig(), branchName); string remoteTrackingBranch = branchConfig.GetRemoteTrackingBranch(); if (remoteTrackingBranch == null) { return(null); } Ref tracking = repository.GetRef(remoteTrackingBranch); if (tracking == null) { return(null); } Ref local = repository.GetRef(branchName); if (local == null) { return(null); } RevWalk walk = new RevWalk(repository); RevCommit localCommit = walk.ParseCommit(local.GetObjectId()); RevCommit trackingCommit = walk.ParseCommit(tracking.GetObjectId()); walk.SetRevFilter(RevFilter.MERGE_BASE); walk.MarkStart(localCommit); walk.MarkStart(trackingCommit); RevCommit mergeBase = walk.Next(); walk.Reset(); walk.SetRevFilter(RevFilter.ALL); int aheadCount = RevWalkUtils.Count(walk, localCommit, mergeBase); int behindCount = RevWalkUtils.Count(walk, trackingCommit, mergeBase); return(new NGit.BranchTrackingStatus(remoteTrackingBranch, aheadCount, behindCount )); }
// Utility class /// <summary> /// Count the number of commits that are reachable from <code>start</code> /// until a commit that is reachable from <code>end</code> is encountered. /// </summary> /// <remarks> /// Count the number of commits that are reachable from <code>start</code> /// until a commit that is reachable from <code>end</code> is encountered. In /// other words, count the number of commits that are in <code>start</code>, /// but not in <code>end</code>. /// <p> /// Note that this method calls /// <see cref="RevWalk.Reset()">RevWalk.Reset()</see> /// at the beginning. /// Also note that the existing rev filter on the walk is left as-is, so be /// sure to set the right rev filter before calling this method. /// </remarks> /// <param name="walk">the rev walk to use</param> /// <param name="start">the commit to start counting from</param> /// <param name="end"> /// the commit where counting should end, or null if counting /// should be done until there are no more commits /// </param> /// <returns>the number of commits</returns> /// <exception cref="NGit.Errors.MissingObjectException">NGit.Errors.MissingObjectException /// </exception> /// <exception cref="NGit.Errors.IncorrectObjectTypeException">NGit.Errors.IncorrectObjectTypeException /// </exception> /// <exception cref="System.IO.IOException">System.IO.IOException</exception> public static int Count(RevWalk walk, RevCommit start, RevCommit end) { walk.Reset(); walk.MarkStart(start); if (end != null) { walk.MarkUninteresting(end); } int count = 0; for (RevCommit c = walk.Next(); c != null; c = walk.Next()) { count++; } return count; }
private RevCommit ParseCommit(Repository repo, ObjectId id) { RevWalk rw = new RevWalk(repo); var head = rw.ParseCommit(id); rw.MarkStart(head); RevCommit commit = null; try { commit = rw.Next(); while( commit != null ) { if (commit.Id.Name == id.Name) { return commit; } commit = rw.Next(); } } finally { rw.Release(); } return commit; }
/// <exception cref="NGit.Errors.TransportException"></exception> private void VerifyPrerequisites() { if (prereqs.IsEmpty()) { return; } RevWalk rw = new RevWalk(transport.local); try { RevFlag PREREQ = rw.NewFlag("PREREQ"); RevFlag SEEN = rw.NewFlag("SEEN"); IDictionary <ObjectId, string> missing = new Dictionary <ObjectId, string>(); IList <RevObject> commits = new AList <RevObject>(); foreach (KeyValuePair <ObjectId, string> e in prereqs.EntrySet()) { ObjectId p = e.Key; try { RevCommit c = rw.ParseCommit(p); if (!c.Has(PREREQ)) { c.Add(PREREQ); commits.AddItem(c); } } catch (MissingObjectException) { missing.Put(p, e.Value); } catch (IOException err) { throw new TransportException(transport.uri, MessageFormat.Format(JGitText.Get().cannotReadCommit , p.Name), err); } } if (!missing.IsEmpty()) { throw new MissingBundlePrerequisiteException(transport.uri, missing); } foreach (Ref r in transport.local.GetAllRefs().Values) { try { rw.MarkStart(rw.ParseCommit(r.GetObjectId())); } catch (IOException) { } } // If we cannot read the value of the ref skip it. int remaining = commits.Count; try { RevCommit c; while ((c = rw.Next()) != null) { if (c.Has(PREREQ)) { c.Add(SEEN); if (--remaining == 0) { break; } } } } catch (IOException err) { throw new TransportException(transport.uri, JGitText.Get().cannotReadObject, err); } if (remaining > 0) { foreach (RevObject o in commits) { if (!o.Has(SEEN)) { missing.Put(o, prereqs.Get(o)); } } throw new MissingBundlePrerequisiteException(transport.uri, missing); } } finally { rw.Release(); } }
/// <exception cref="NGit.Errors.TransportException"></exception> private void VerifyPrerequisites() { if (prereqs.IsEmpty()) { return; } RevWalk rw = new RevWalk(transport.local); try { RevFlag PREREQ = rw.NewFlag("PREREQ"); RevFlag SEEN = rw.NewFlag("SEEN"); IDictionary<ObjectId, string> missing = new Dictionary<ObjectId, string>(); IList<RevObject> commits = new AList<RevObject>(); foreach (KeyValuePair<ObjectId, string> e in prereqs.EntrySet()) { ObjectId p = e.Key; try { RevCommit c = rw.ParseCommit(p); if (!c.Has(PREREQ)) { c.Add(PREREQ); commits.AddItem(c); } } catch (MissingObjectException) { missing.Put(p, e.Value); } catch (IOException err) { throw new TransportException(transport.uri, MessageFormat.Format(JGitText.Get().cannotReadCommit , p.Name), err); } } if (!missing.IsEmpty()) { throw new MissingBundlePrerequisiteException(transport.uri, missing); } foreach (Ref r in transport.local.GetAllRefs().Values) { try { rw.MarkStart(rw.ParseCommit(r.GetObjectId())); } catch (IOException) { } } // If we cannot read the value of the ref skip it. int remaining = commits.Count; try { RevCommit c; while ((c = rw.Next()) != null) { if (c.Has(PREREQ)) { c.Add(SEEN); if (--remaining == 0) { break; } } } } catch (IOException err) { throw new TransportException(transport.uri, JGitText.Get().cannotReadObject, err); } if (remaining > 0) { foreach (RevObject o in commits) { if (!o.Has(SEEN)) { missing.Put(o, prereqs.Get(o)); } } throw new MissingBundlePrerequisiteException(transport.uri, missing); } } finally { rw.Release(); } }
public static void MergeTest(EngineContext engineContext) { // TODO: Currently hardcoded var db = new FileRepository(new FilePath(@"C:\DEV\hotei_scene", Constants.DOT_GIT)); var git = new Git(db); var tree1Ref = db.GetRef("test"); var tree2Ref = db.GetRef(Constants.HEAD); var tree1CommitId = tree1Ref.GetObjectId(); var tree2CommitId = tree2Ref.GetObjectId(); // Merge tree1 into current tree var mergeResult = git.Merge().Include(tree1CommitId).Call(); if (mergeResult.GetMergeStatus() == MergeStatus.CONFLICTING) { foreach (var conflict in mergeResult.GetConflicts()) { if (conflict.Key.EndsWith(".hotei")) { // Search base tree (common ancestor), if any var walk = new RevWalk(db); walk.SetRevFilter(RevFilter.MERGE_BASE); walk.MarkStart(walk.ParseCommit(tree1CommitId)); walk.MarkStart(walk.ParseCommit(tree2CommitId)); var baseTree = walk.Next(); var tw = new NameConflictTreeWalk(db); tw.AddTree(new RevWalk(db).ParseTree(tree1CommitId).ToObjectId()); tw.AddTree(new RevWalk(db).ParseTree(tree2CommitId).ToObjectId()); if (baseTree != null) { tw.AddTree(new RevWalk(db).ParseTree(baseTree.ToObjectId()).ToObjectId()); } tw.Filter = PathFilter.Create(conflict.Key); // Should be only one iteration while (tw.Next()) { var tree0 = baseTree != null?tw.GetTree <AbstractTreeIterator>(2) : null; var tree1 = tw.GetTree <AbstractTreeIterator>(0); var tree2 = tw.GetTree <AbstractTreeIterator>(1); // Get contents of every versions for the 3-way merge var data0 = baseTree != null?LoadEntities(new MemoryStream(tw.ObjectReader.Open(tree0.EntryObjectId).GetBytes())) : null; var data1 = LoadEntities(new MemoryStream(tw.ObjectReader.Open(tree1.EntryObjectId).GetBytes())); var data2 = LoadEntities(new MemoryStream(tw.ObjectReader.Open(tree2.EntryObjectId).GetBytes())); // Perform 3-way merge var entities = new List <EntityDefinition>(); ThreeWayMergeOrdered.Merge(entities, data0, data1, data2, x => x.Guid, (x, y) => x == y, ResolveEntityConflicts); // Save new merged file var fileStream = new FileStream(new FilePath(db.WorkTree, conflict.Key), FileMode.Create, FileAccess.Write); var stream = new BinarySerializationWriter(fileStream); stream.Context.Serializer = Serializer; stream.SerializeClass(null, ref entities, ArchiveMode.Serialize); fileStream.Close(); // TODO: Check if all conflicts are really resolved // Add resolved file for merge commit git.Add().AddFilepattern(conflict.Key).Call(); } } } } }
/// <summary> /// Find the list of branches a given commit is reachable from when following /// parent.s /// <p> /// Note that this method calls /// <see cref="RevWalk.Reset()">RevWalk.Reset()</see> /// at the beginning. /// <p> /// In order to improve performance this method assumes clock skew among /// committers is never larger than 24 hours. /// </summary> /// <param name="commit">the commit we are looking at</param> /// <param name="revWalk">The RevWalk to be used.</param> /// <param name="refs">the set of branches we want to see reachability from</param> /// <returns>the list of branches a given commit is reachable from</returns> /// <exception cref="NGit.Errors.MissingObjectException">NGit.Errors.MissingObjectException /// </exception> /// <exception cref="NGit.Errors.IncorrectObjectTypeException">NGit.Errors.IncorrectObjectTypeException /// </exception> /// <exception cref="System.IO.IOException">System.IO.IOException</exception> public static IList<Ref> FindBranchesReachableFrom(RevCommit commit, RevWalk revWalk , ICollection<Ref> refs) { IList<Ref> result = new AList<Ref>(); // searches from branches can be cut off early if any parent of the // search-for commit is found. This is quite likely, so optimize for this. revWalk.MarkStart(Arrays.AsList(commit.Parents)); ObjectIdSubclassMap<ObjectId> cutOff = new ObjectIdSubclassMap<ObjectId>(); int SKEW = 24 * 3600; // one day clock skew foreach (Ref @ref in refs) { RevObject maybehead = revWalk.ParseAny(@ref.GetObjectId()); if (!(maybehead is RevCommit)) { continue; } RevCommit headCommit = (RevCommit)maybehead; // if commit is in the ref branch, then the tip of ref should be // newer than the commit we are looking for. Allow for a large // clock skew. if (headCommit.CommitTime + SKEW < commit.CommitTime) { continue; } IList<ObjectId> maybeCutOff = new AList<ObjectId>(cutOff.Size()); // guess rough size revWalk.ResetRetain(); revWalk.MarkStart(headCommit); RevCommit current; Ref found = null; while ((current = revWalk.Next()) != null) { if (AnyObjectId.Equals(current, commit)) { found = @ref; break; } if (cutOff.Contains(current)) { break; } maybeCutOff.AddItem(current.ToObjectId()); } if (found != null) { result.AddItem(@ref); } else { foreach (ObjectId id in maybeCutOff) { cutOff.AddIfAbsent(id); } } } return result; }
public virtual void TestFillToCommit() { Setup(3); RevWalk w = new RevWalk(db); w.MarkStart(w.LookupCommit(db.Resolve(Constants.HEAD))); w.Next(); RevCommit c = w.Next(); NUnit.Framework.Assert.IsNotNull(c, "should have found 2. commit"); list.FillTo(c, 5); NUnit.Framework.Assert.AreEqual(2, list.Count); NUnit.Framework.Assert.AreEqual("commit 1", list[1].GetFullMessage()); NUnit.Framework.Assert.IsNull(list[3]); }
/// <summary> /// Compute the tracking status for the <code>branchName</code> in /// <code>repository</code>. /// </summary> /// <remarks> /// Compute the tracking status for the <code>branchName</code> in /// <code>repository</code>. /// </remarks> /// <param name="repository">the git repository to compute the status from</param> /// <param name="branchName">the local branch</param> /// <returns>the tracking status, or null if it is not known</returns> /// <exception cref="System.IO.IOException">System.IO.IOException</exception> public static NGit.BranchTrackingStatus Of(Repository repository, string branchName ) { BranchConfig branchConfig = new BranchConfig(repository.GetConfig(), branchName); string trackingBranch = branchConfig.GetTrackingBranch(); if (trackingBranch == null) { return null; } Ref tracking = repository.GetRef(trackingBranch); if (tracking == null) { return null; } Ref local = repository.GetRef(branchName); if (local == null) { return null; } RevWalk walk = new RevWalk(repository); RevCommit localCommit = walk.ParseCommit(local.GetObjectId()); RevCommit trackingCommit = walk.ParseCommit(tracking.GetObjectId()); walk.SetRevFilter(RevFilter.MERGE_BASE); walk.MarkStart(localCommit); walk.MarkStart(trackingCommit); RevCommit mergeBase = walk.Next(); walk.Reset(); walk.SetRevFilter(RevFilter.ALL); int aheadCount = RevWalkUtils.Count(walk, localCommit, mergeBase); int behindCount = RevWalkUtils.Count(walk, trackingCommit, mergeBase); return new NGit.BranchTrackingStatus(trackingBranch, aheadCount, behindCount); }
public static void MergeTest(EngineContext engineContext) { // TODO: Currently hardcoded var db = new FileRepository(new FilePath(@"C:\DEV\hotei_scene", Constants.DOT_GIT)); var git = new Git(db); var tree1Ref = db.GetRef("test"); var tree2Ref = db.GetRef(Constants.HEAD); var tree1CommitId = tree1Ref.GetObjectId(); var tree2CommitId = tree2Ref.GetObjectId(); // Merge tree1 into current tree var mergeResult = git.Merge().Include(tree1CommitId).Call(); if (mergeResult.GetMergeStatus() == MergeStatus.CONFLICTING) { foreach (var conflict in mergeResult.GetConflicts()) { if (conflict.Key.EndsWith(".hotei")) { // Search base tree (common ancestor), if any var walk = new RevWalk(db); walk.SetRevFilter(RevFilter.MERGE_BASE); walk.MarkStart(walk.ParseCommit(tree1CommitId)); walk.MarkStart(walk.ParseCommit(tree2CommitId)); var baseTree = walk.Next(); var tw = new NameConflictTreeWalk(db); tw.AddTree(new RevWalk(db).ParseTree(tree1CommitId).ToObjectId()); tw.AddTree(new RevWalk(db).ParseTree(tree2CommitId).ToObjectId()); if (baseTree != null) tw.AddTree(new RevWalk(db).ParseTree(baseTree.ToObjectId()).ToObjectId()); tw.Filter = PathFilter.Create(conflict.Key); // Should be only one iteration while (tw.Next()) { var tree0 = baseTree != null ? tw.GetTree<AbstractTreeIterator>(2) : null; var tree1 = tw.GetTree<AbstractTreeIterator>(0); var tree2 = tw.GetTree<AbstractTreeIterator>(1); // Get contents of every versions for the 3-way merge var data0 = baseTree != null ? LoadEntities(new MemoryStream(tw.ObjectReader.Open(tree0.EntryObjectId).GetBytes())) : null; var data1 = LoadEntities(new MemoryStream(tw.ObjectReader.Open(tree1.EntryObjectId).GetBytes())); var data2 = LoadEntities(new MemoryStream(tw.ObjectReader.Open(tree2.EntryObjectId).GetBytes())); // Perform 3-way merge var entities = new List<EntityDefinition>(); ThreeWayMergeOrdered.Merge(entities, data0, data1, data2, x => x.Guid, (x, y) => x == y, ResolveEntityConflicts); // Save new merged file var fileStream = new FileStream(new FilePath(db.WorkTree, conflict.Key), FileMode.Create, FileAccess.Write); var stream = new BinarySerializationWriter(fileStream); stream.Context.Serializer = Serializer; stream.SerializeClass(null, ref entities, ArchiveMode.Serialize); fileStream.Close(); // TODO: Check if all conflicts are really resolved // Add resolved file for merge commit git.Add().AddFilepattern(conflict.Key).Call(); } } } } }