summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Borowitz <dborowitz@google.com>2017-03-31 11:49:12 -0400
committerJonathan Nieder <jrn@google.com>2017-04-05 17:50:54 -0400
commit4c3e274588060d9ab2e05d7919f506789bcbbc0b (patch)
tree241e54a6bfdba3a7036c030d094e3da5a5b733da
parentaec22e74cf76d7b7ea53d526b908613eaeac5b55 (diff)
downloadjgit-4c3e274588060d9ab2e05d7919f506789bcbbc0b.tar.gz
jgit-4c3e274588060d9ab2e05d7919f506789bcbbc0b.zip
Support creating Mergers without a Repository
All that's really required to run a merge operation is a single ObjectInserter, from which we can construct a RevWalk, plus a Config that declares a diff algorithm. Provide some factory methods that don't take Repository. Change-Id: Ib884dce2528424b5bcbbbbfc043baec1886b9bbd
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java133
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java30
-rw-r--r--org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeStrategy.java18
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java60
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java13
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java51
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyOneSided.java12
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyRecursive.java7
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyResolve.java9
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategySimpleTwoWayInCore.java12
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java12
13 files changed, 337 insertions, 22 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java
index 255262255a..d8b8750ba3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java
@@ -42,12 +42,17 @@
*/
package org.eclipse.jgit.merge;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
+import java.util.Arrays;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.MergeResult;
@@ -59,8 +64,14 @@ import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.errors.NoMergeBaseException;
import org.eclipse.jgit.errors.NoMergeBaseException.MergeBaseFailureReason;
import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason;
import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.revwalk.RevTree;
+import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils;
@@ -408,7 +419,7 @@ public class ResolveMergerTest extends RepositoryTestCase {
/**
* Merging two equal subtrees with an incore merger should lead to a merged
- * state (The 'Gerrit' use case).
+ * state.
*
* @param strategy
* @throws Exception
@@ -442,6 +453,43 @@ public class ResolveMergerTest extends RepositoryTestCase {
}
/**
+ * Merging two equal subtrees with an incore merger should lead to a merged
+ * state, without using a Repository (the 'Gerrit' use case).
+ *
+ * @param strategy
+ * @throws Exception
+ */
+ @Theory
+ public void checkMergeEqualTreesInCore_noRepo(MergeStrategy strategy)
+ throws Exception {
+ Git git = Git.wrap(db);
+
+ writeTrashFile("d/1", "orig");
+ git.add().addFilepattern("d/1").call();
+ RevCommit first = git.commit().setMessage("added d/1").call();
+
+ writeTrashFile("d/1", "modified");
+ RevCommit masterCommit = git.commit().setAll(true)
+ .setMessage("modified d/1 on master").call();
+
+ git.checkout().setCreateBranch(true).setStartPoint(first)
+ .setName("side").call();
+ writeTrashFile("d/1", "modified");
+ RevCommit sideCommit = git.commit().setAll(true)
+ .setMessage("modified d/1 on side").call();
+
+ git.rm().addFilepattern("d/1").call();
+ git.rm().addFilepattern("d").call();
+
+ try (ObjectInserter ins = db.newObjectInserter()) {
+ ThreeWayMerger resolveMerger =
+ (ThreeWayMerger) strategy.newMerger(ins, db.getConfig());
+ boolean noProblems = resolveMerger.merge(masterCommit, sideCommit);
+ assertTrue(noProblems);
+ }
+ }
+
+ /**
* Merging two equal subtrees when the index and HEAD does not contain any
* file in that subtree should lead to a merged state.
*
@@ -613,6 +661,35 @@ public class ResolveMergerTest extends RepositoryTestCase {
}
@Theory
+ public void checkContentMergeNoConflict_noRepo(MergeStrategy strategy)
+ throws Exception {
+ Git git = Git.wrap(db);
+
+ writeTrashFile("file", "1\n2\n3");
+ git.add().addFilepattern("file").call();
+ RevCommit first = git.commit().setMessage("added file").call();
+
+ writeTrashFile("file", "1master\n2\n3");
+ RevCommit masterCommit = git.commit().setAll(true)
+ .setMessage("modified file on master").call();
+
+ git.checkout().setCreateBranch(true).setStartPoint(first)
+ .setName("side").call();
+ writeTrashFile("file", "1\n2\n3side");
+ RevCommit sideCommit = git.commit().setAll(true)
+ .setMessage("modified file on side").call();
+
+ try (ObjectInserter ins = db.newObjectInserter()) {
+ ResolveMerger merger =
+ (ResolveMerger) strategy.newMerger(ins, db.getConfig());
+ boolean noProblems = merger.merge(masterCommit, sideCommit);
+ assertTrue(noProblems);
+ assertEquals("1master\n2\n3side",
+ readBlob(merger.getResultTreeId(), "file"));
+ }
+ }
+
+ @Theory
public void checkContentMergeConflict(MergeStrategy strategy)
throws Exception {
Git git = Git.wrap(db);
@@ -644,6 +721,49 @@ public class ResolveMergerTest extends RepositoryTestCase {
assertEquals(expected, read("file"));
}
+ @Theory
+ public void checkContentMergeConflict_noTree(MergeStrategy strategy)
+ throws Exception {
+ Git git = Git.wrap(db);
+
+ writeTrashFile("file", "1\n2\n3");
+ git.add().addFilepattern("file").call();
+ RevCommit first = git.commit().setMessage("added file").call();
+
+ writeTrashFile("file", "1master\n2\n3");
+ RevCommit masterCommit = git.commit().setAll(true)
+ .setMessage("modified file on master").call();
+
+ git.checkout().setCreateBranch(true).setStartPoint(first)
+ .setName("side").call();
+ writeTrashFile("file", "1side\n2\n3");
+ RevCommit sideCommit = git.commit().setAll(true)
+ .setMessage("modified file on side").call();
+
+ try (ObjectInserter ins = db.newObjectInserter()) {
+ ResolveMerger merger =
+ (ResolveMerger) strategy.newMerger(ins, db.getConfig());
+ boolean noProblems = merger.merge(masterCommit, sideCommit);
+ assertFalse(noProblems);
+ assertEquals(Arrays.asList("file"), merger.getUnmergedPaths());
+
+ MergeFormatter fmt = new MergeFormatter();
+ merger.getMergeResults().get("file");
+ try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+ fmt.formatMerge(out, merger.getMergeResults().get("file"),
+ "BASE", "OURS", "THEIRS", UTF_8.name());
+ String expected = "<<<<<<< OURS\n"
+ + "1master\n"
+ + "=======\n"
+ + "1side\n"
+ + ">>>>>>> THEIRS\n"
+ + "2\n"
+ + "3";
+ assertEquals(expected, new String(out.toByteArray(), UTF_8));
+ }
+ }
+ }
+
/**
* Merging after criss-cross merges. In this case we merge together two
* commits which have two equally good common ancestors
@@ -875,4 +995,15 @@ public class ResolveMergerTest extends RepositoryTestCase {
curMod >= lastMod);
}
}
+
+ private String readBlob(ObjectId treeish, String path) throws Exception {
+ TestRepository<?> tr = new TestRepository<>(db);
+ RevWalk rw = tr.getRevWalk();
+ RevTree tree = rw.parseTree(treeish);
+ RevObject obj = tr.get(tree, path);
+ if (obj == null) {
+ return null;
+ }
+ return new String(rw.getObjectReader().open(obj, OBJ_BLOB).getBytes(), UTF_8);
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java
index db9d87dd17..951568e7bb 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java
@@ -72,6 +72,16 @@ public class SimpleMergeTest extends SampleDataRepositoryTestCase {
}
@Test
+ public void testOurs_noRepo() throws IOException {
+ try (ObjectInserter ins = db.newObjectInserter()) {
+ Merger ourMerger = MergeStrategy.OURS.newMerger(ins, db.getConfig());
+ boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a"), db.resolve("c") });
+ assertTrue(merge);
+ assertEquals(db.resolve("a^{tree}"), ourMerger.getResultTreeId());
+ }
+ }
+
+ @Test
public void testTheirs() throws IOException {
Merger ourMerger = MergeStrategy.THEIRS.newMerger(db);
boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a"), db.resolve("c") });
@@ -80,6 +90,16 @@ public class SimpleMergeTest extends SampleDataRepositoryTestCase {
}
@Test
+ public void testTheirs_noRepo() throws IOException {
+ try (ObjectInserter ins = db.newObjectInserter()) {
+ Merger ourMerger = MergeStrategy.THEIRS.newMerger(db);
+ boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a"), db.resolve("c") });
+ assertTrue(merge);
+ assertEquals(db.resolve("c^{tree}"), ourMerger.getResultTreeId());
+ }
+ }
+
+ @Test
public void testTrivialTwoWay() throws IOException {
Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a"), db.resolve("c") });
@@ -104,6 +124,16 @@ public class SimpleMergeTest extends SampleDataRepositoryTestCase {
}
@Test
+ public void testTrivialTwoWay_noRepo() throws IOException {
+ try (ObjectInserter ins = db.newObjectInserter()) {
+ Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(ins, db.getConfig());
+ boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a^0^0^0"), db.resolve("a^0^0^1") });
+ assertTrue(merge);
+ assertEquals(db.resolve("a^0^0^{tree}"), ourMerger.getResultTreeId());
+ }
+ }
+
+ @Test
public void testTrivialTwoWay_conflict() throws IOException {
Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("f"), db.resolve("g") });
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
index 4ac399f9ec..da076dcb7f 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -538,6 +538,7 @@ renamesFindingExact=Finding exact renames
renamesRejoiningModifies=Rejoining modified file pairs
repositoryAlreadyExists=Repository already exists: {0}
repositoryConfigFileInvalid=Repository config file {0} invalid {1}
+repositoryIsRequired=repository is required
repositoryNotFound=repository not found: {0}
repositoryState_applyMailbox=Apply mailbox
repositoryState_bare=Bare
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index a81c93a013..0e52fccaaa 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -597,6 +597,7 @@ public class JGitText extends TranslationBundle {
/***/ public String renamesRejoiningModifies;
/***/ public String repositoryAlreadyExists;
/***/ public String repositoryConfigFileInvalid;
+ /***/ public String repositoryIsRequired;
/***/ public String repositoryNotFound;
/***/ public String repositoryState_applyMailbox;
/***/ public String repositoryState_bare;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeStrategy.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeStrategy.java
index 656480e468..af3d5ca078 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeStrategy.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeStrategy.java
@@ -49,6 +49,8 @@ import java.text.MessageFormat;
import java.util.HashMap;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.Repository;
/**
@@ -170,4 +172,20 @@ public abstract class MergeStrategy {
* @return the new merge instance which implements this strategy.
*/
public abstract Merger newMerger(Repository db, boolean inCore);
+
+ /**
+ * Create a new merge instance.
+ * <p>
+ * The merge will happen in memory, working folder will not be modified, in
+ * case of a non-trivial merge that requires manual resolution, the merger
+ * will fail.
+ *
+ * @param inserter
+ * inserter to write results back to.
+ * @param config
+ * repo config for reading diff algorithm settings.
+ * @return the new merge instance which implements this strategy.
+ * @since 4.8
+ */
+ public abstract Merger newMerger(ObjectInserter inserter, Config config);
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java
index bee2d03523..0c4488c984 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java
@@ -47,6 +47,7 @@ package org.eclipse.jgit.merge;
import java.io.IOException;
import java.text.MessageFormat;
+import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.NoMergeBaseException;
import org.eclipse.jgit.errors.NoMergeBaseException.MergeBaseFailureReason;
@@ -70,7 +71,15 @@ import org.eclipse.jgit.treewalk.CanonicalTreeParser;
* Instance of a specific {@link MergeStrategy} for a single {@link Repository}.
*/
public abstract class Merger {
- /** The repository this merger operates on. */
+ /**
+ * The repository this merger operates on.
+ * <p>
+ * Null if and only if the merger was constructed with {@link
+ * #Merger(ObjectInserter)}. Callers that want to assume the repo is not null
+ * (e.g. because of a previous check that the merger is not in-core) may use
+ * {@link #nonNullRepo()}.
+ */
+ @Nullable
protected final Repository db;
/** Reader to support {@link #walk} and other object loading. */
@@ -104,20 +113,55 @@ public abstract class Merger {
* the repository this merger will read and write data on.
*/
protected Merger(final Repository local) {
+ if (local == null) {
+ throw new NullPointerException(JGitText.get().repositoryIsRequired);
+ }
db = local;
- inserter = db.newObjectInserter();
+ inserter = local.newObjectInserter();
reader = inserter.newReader();
walk = new RevWalk(reader);
}
/**
+ * Create a new in-core merge instance from an inserter.
+ *
+ * @param oi
+ * the inserter to write objects to. Will be closed at the
+ * conclusion of {@code merge}, unless {@code flush} is false.
+ * @since 4.8
+ */
+ protected Merger(ObjectInserter oi) {
+ db = null;
+ inserter = oi;
+ reader = oi.newReader();
+ walk = new RevWalk(reader);
+ }
+
+ /**
* @return the repository this merger operates on.
*/
+ @Nullable
public Repository getRepository() {
return db;
}
- /** @return an object writer to create objects in {@link #getRepository()}. */
+ /**
+ * @return non-null repository instance
+ * @throws NullPointerException
+ * if the merger was constructed without a repository.
+ * @since 4.8
+ */
+ protected Repository nonNullRepo() {
+ if (db == null) {
+ throw new NullPointerException(JGitText.get().repositoryIsRequired);
+ }
+ return db;
+ }
+
+ /**
+ * @return an object writer to create objects, writing objects to {@link
+ * #getRepository()} (if a repository was provided).
+ */
public ObjectInserter getObjectInserter() {
return inserter;
}
@@ -131,7 +175,9 @@ public abstract class Merger {
*
* @param oi
* the inserter instance to use. Must be associated with the
- * repository instance returned by {@link #getRepository()}.
+ * repository instance returned by {@link #getRepository()} (if a
+ * repository was provided). Will be closed at the conclusion of
+ * {@code merge}, unless {@code flush} is false.
*/
public void setObjectInserter(ObjectInserter oi) {
walk.close();
@@ -173,9 +219,9 @@ public abstract class Merger {
*
* @since 3.5
* @param flush
- * whether to flush the underlying object inserter when finished to
- * store any content-merged blobs and virtual merged bases; if
- * false, callers are responsible for flushing.
+ * whether to flush and close the underlying object inserter when
+ * finished to store any content-merged blobs and virtual merged
+ * bases; if false, callers are responsible for flushing.
* @param tips
* source trees to be combined together. The merge base is not
* included in this set.
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 f8e1998ed7..1375cd3ea2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java
@@ -61,7 +61,9 @@ import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.NoMergeBaseException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.Config;
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;
@@ -111,6 +113,17 @@ public class RecursiveMerger extends ResolveMerger {
}
/**
+ * Normal recursive merge, implies inCore.
+ *
+ * @param inserter
+ * @param config
+ * @since 4.8
+ */
+ protected RecursiveMerger(ObjectInserter inserter, Config config) {
+ super(inserter, config);
+ }
+
+ /**
* Get a single base commit for two given commits. If the two source commits
* have more than one base commit recursively merge the base commits
* together until you end up with a single base commit.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
index f667af278a..1aac352d74 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
@@ -44,6 +44,9 @@
*/
package org.eclipse.jgit.merge;
+import static org.eclipse.jgit.diff.DiffAlgorithm.SupportedAlgorithm.HISTOGRAM;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFF_SECTION;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_ALGORITHM;
import static org.eclipse.jgit.lib.Constants.CHARACTER_ENCODING;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
@@ -79,9 +82,10 @@ import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.IndexWriteException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.NoWorkTreeException;
-import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevTree;
@@ -266,18 +270,25 @@ public class ResolveMerger extends ThreeWayMerger {
*/
protected MergeAlgorithm mergeAlgorithm;
+ private static MergeAlgorithm getMergeAlgorithm(Config config) {
+ SupportedAlgorithm diffAlg = config.getEnum(
+ CONFIG_DIFF_SECTION, null, CONFIG_KEY_ALGORITHM,
+ HISTOGRAM);
+ return new MergeAlgorithm(DiffAlgorithm.getAlgorithm(diffAlg));
+ }
+
+ private static String[] defaultCommitNames() {
+ return new String[] { "BASE", "OURS", "THEIRS" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
/**
* @param local
* @param inCore
*/
protected ResolveMerger(Repository local, boolean inCore) {
super(local);
- SupportedAlgorithm diffAlg = local.getConfig().getEnum(
- ConfigConstants.CONFIG_DIFF_SECTION, null,
- ConfigConstants.CONFIG_KEY_ALGORITHM,
- SupportedAlgorithm.HISTOGRAM);
- mergeAlgorithm = new MergeAlgorithm(DiffAlgorithm.getAlgorithm(diffAlg));
- commitNames = new String[] { "BASE", "OURS", "THEIRS" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ mergeAlgorithm = getMergeAlgorithm(local.getConfig());
+ commitNames = defaultCommitNames();
this.inCore = inCore;
if (inCore) {
@@ -295,10 +306,24 @@ public class ResolveMerger extends ThreeWayMerger {
this(local, false);
}
+ /**
+ * @param inserter
+ * @param config
+ * @since 4.8
+ */
+ protected ResolveMerger(ObjectInserter inserter, Config config) {
+ super(inserter);
+ mergeAlgorithm = getMergeAlgorithm(config);
+ commitNames = defaultCommitNames();
+ inCore = true;
+ implicitDirCache = false;
+ dircache = DirCache.newInCore();
+ }
+
@Override
protected boolean mergeImpl() throws IOException {
if (implicitDirCache)
- dircache = getRepository().lockDirCache();
+ dircache = nonNullRepo().lockDirCache();
try {
return mergeTrees(mergeBase(), sourceTrees[0], sourceTrees[1],
@@ -315,7 +340,7 @@ public class ResolveMerger extends ThreeWayMerger {
// of a non-empty directory, for which delete() would fail.
for (int i = toBeDeleted.size() - 1; i >= 0; i--) {
String fileName = toBeDeleted.get(i);
- File f = new File(db.getWorkTree(), fileName);
+ File f = new File(nonNullRepo().getWorkTree(), fileName);
if (!f.delete())
if (!f.isDirectory())
failingPaths.put(fileName,
@@ -348,7 +373,7 @@ public class ResolveMerger extends ThreeWayMerger {
return;
}
- DirCache dc = db.readDirCache();
+ DirCache dc = nonNullRepo().readDirCache();
Iterator<String> mpathsIt=modifiedFiles.iterator();
while(mpathsIt.hasNext()) {
String mpath=mpathsIt.next();
@@ -785,8 +810,8 @@ public class ResolveMerger extends ThreeWayMerger {
*/
private File writeMergedFile(MergeResult<RawText> result)
throws FileNotFoundException, IOException {
- File workTree = db.getWorkTree();
- FS fs = db.getFS();
+ File workTree = nonNullRepo().getWorkTree();
+ FS fs = nonNullRepo().getFS();
File of = new File(workTree, tw.getPathString());
File parentFolder = of.getParentFile();
if (!fs.exists(parentFolder))
@@ -802,7 +827,7 @@ public class ResolveMerger extends ThreeWayMerger {
private ObjectId insertMergeResult(MergeResult<RawText> result)
throws IOException {
TemporaryBuffer.LocalFile buf = new TemporaryBuffer.LocalFile(
- db.getDirectory(), 10 << 20);
+ db != null ? nonNullRepo().getDirectory() : null, 10 << 20);
try {
new MergeFormatter().formatMerge(buf, result,
Arrays.asList(commitNames), CHARACTER_ENCODING);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyOneSided.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyOneSided.java
index 12d6c6b413..2224dbc448 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyOneSided.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyOneSided.java
@@ -46,7 +46,9 @@ package org.eclipse.jgit.merge;
import java.io.IOException;
+import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.Repository;
/**
@@ -89,6 +91,11 @@ public class StrategyOneSided extends MergeStrategy {
return new OneSide(db, treeIndex);
}
+ @Override
+ public Merger newMerger(final ObjectInserter inserter, final Config config) {
+ return new OneSide(inserter, treeIndex);
+ }
+
static class OneSide extends Merger {
private final int treeIndex;
@@ -97,6 +104,11 @@ public class StrategyOneSided extends MergeStrategy {
treeIndex = index;
}
+ protected OneSide(final ObjectInserter inserter, final int index) {
+ super(inserter);
+ treeIndex = index;
+ }
+
@Override
protected boolean mergeImpl() throws IOException {
return treeIndex < sourceTrees.length;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyRecursive.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyRecursive.java
index 22e608ec9d..56128dd93e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyRecursive.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyRecursive.java
@@ -43,6 +43,8 @@
package org.eclipse.jgit.merge;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.Repository;
/**
@@ -63,6 +65,11 @@ public class StrategyRecursive extends StrategyResolve {
}
@Override
+ public ThreeWayMerger newMerger(ObjectInserter inserter, Config config) {
+ return new RecursiveMerger(inserter, config);
+ }
+
+ @Override
public String getName() {
return "recursive"; //$NON-NLS-1$
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyResolve.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyResolve.java
index 07368e5746..1691bf9e43 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyResolve.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyResolve.java
@@ -43,6 +43,8 @@
*/
package org.eclipse.jgit.merge;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.Repository;
/**
@@ -61,7 +63,12 @@ public class StrategyResolve extends ThreeWayMergeStrategy {
}
@Override
+ public ThreeWayMerger newMerger(ObjectInserter inserter, Config config) {
+ return new ResolveMerger(inserter, config);
+ }
+
+ @Override
public String getName() {
return "resolve"; //$NON-NLS-1$
}
-} \ No newline at end of file
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategySimpleTwoWayInCore.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategySimpleTwoWayInCore.java
index ec903c139d..d05e2d4c8d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategySimpleTwoWayInCore.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategySimpleTwoWayInCore.java
@@ -49,6 +49,7 @@ import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.errors.UnmergedPathException;
+import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
@@ -89,6 +90,11 @@ public class StrategySimpleTwoWayInCore extends ThreeWayMergeStrategy {
return newMerger(db);
}
+ @Override
+ public ThreeWayMerger newMerger(ObjectInserter inserter, Config config) {
+ return new InCoreMerger(inserter);
+ }
+
private static class InCoreMerger extends ThreeWayMerger {
private static final int T_BASE = 0;
@@ -110,6 +116,12 @@ public class StrategySimpleTwoWayInCore extends ThreeWayMergeStrategy {
cache = DirCache.newInCore();
}
+ InCoreMerger(final ObjectInserter inserter) {
+ super(inserter);
+ tw = new NameConflictTreeWalk(null, reader);
+ cache = DirCache.newInCore();
+ }
+
@Override
protected boolean mergeImpl() throws IOException {
tw.addTree(mergeBase());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java
index fbedaef865..b3ef0fb3e4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java
@@ -50,6 +50,7 @@ import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
@@ -85,6 +86,17 @@ public abstract class ThreeWayMerger extends Merger {
}
/**
+ * Create a new in-core merge instance from an inserter.
+ *
+ * @param inserter
+ * the inserter to write objects to.
+ * @since 4.8
+ */
+ protected ThreeWayMerger(ObjectInserter inserter) {
+ super(inserter);
+ }
+
+ /**
* Set the common ancestor tree.
*
* @param id