From 4bd28bc9589abe7bf9ea6bc4dde8b4d683baf61a Mon Sep 17 00:00:00 2001 From: Shawn Pearce Date: Fri, 8 Aug 2014 11:19:45 -0700 Subject: [PATCH] RecursiveMerger: do not insert virtual commits into repository When merging common ancestors to create a single virtual common ancestor the commit does not need to be inserted into the Git repository. Instead just mock it out in memory as part of the merger's RevWalk pool. Make the author and committer stable and predictable for any given pair of merge bases. It is not necessary for the caller's name or email to be used as the commit will not be written out. Change-Id: I88d5ee4de121950e1b032a5c10486c9d2c42656c --- .../eclipse/jgit/merge/RecursiveMerger.java | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java index af6c1f964..4889293ad 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java @@ -52,7 +52,9 @@ import java.io.IOException; import java.text.MessageFormat; import java.util.ArrayList; +import java.util.Date; import java.util.List; +import java.util.TimeZone; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheBuilder; @@ -62,7 +64,6 @@ import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.CommitBuilder; import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.ObjectInserter; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; @@ -90,8 +91,6 @@ public class RecursiveMerger extends ResolveMerger { */ public final int MAX_BASES = 200; - private PersonIdent ident = new PersonIdent(db); - /** * Normal recursive merge when you want a choice of DirCache placement * inCore @@ -137,7 +136,9 @@ protected RevCommit getBaseCommit(RevCommit a, RevCommit b) * the second commit to be merged * @param callDepth * the callDepth when this method is called recursively - * @return the merge base of two commits + * @return the merge base of two commits. If a criss-cross merge required a + * synthetic merge base this commit is visible only the merger's + * RevWalk and will not be in the repository. * @throws IOException * @throws IncorrectObjectTypeException * one of the input objects is not a commit. @@ -228,22 +229,28 @@ protected RevCommit getBaseCommit(RevCommit a, RevCommit b, int callDepth) * the tree this commit should capture * @param parents * the list of parent commits - * @return a new (persisted) commit + * @return a new commit visible only within this merger's RevWalk. * @throws IOException */ private RevCommit createCommitForTree(ObjectId tree, List parents) throws IOException { CommitBuilder c = new CommitBuilder(); - c.setParentIds(parents); c.setTreeId(tree); - c.setAuthor(ident); - c.setCommitter(ident); - ObjectInserter odi = db.newObjectInserter(); - ObjectId newCommitId = odi.insert(c); - odi.flush(); - RevCommit ret = walk.lookupCommit(newCommitId); - walk.parseHeaders(ret); - return ret; + c.setParentIds(parents); + c.setAuthor(mockAuthor(parents)); + c.setCommitter(c.getAuthor()); + return RevCommit.parse(walk, c.build()); + } + + private static PersonIdent mockAuthor(List parents) { + String name = RecursiveMerger.class.getSimpleName(); + int time = 0; + for (RevCommit p : parents) + time = Math.max(time, p.getCommitTime()); + return new PersonIdent( + name, name + "@JGit", //$NON-NLS-1$ + new Date((time + 1) * 1000L), + TimeZone.getTimeZone("GMT+0000")); //$NON-NLS-1$ } /**