Browse Source

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
stable-4.8
Dave Borowitz 8 years ago committed by Jonathan Nieder
parent
commit
4c3e274588
  1. 133
      org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java
  2. 30
      org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java
  3. 1
      org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
  4. 1
      org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
  5. 18
      org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeStrategy.java
  6. 60
      org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java
  7. 13
      org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java
  8. 51
      org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
  9. 12
      org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyOneSided.java
  10. 7
      org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyRecursive.java
  11. 7
      org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyResolve.java
  12. 12
      org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategySimpleTwoWayInCore.java
  13. 12
      org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java

133
org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java

@ -42,12 +42,17 @@
*/ */
package org.eclipse.jgit.merge; 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.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.MergeResult; 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;
import org.eclipse.jgit.errors.NoMergeBaseException.MergeBaseFailureReason; import org.eclipse.jgit.errors.NoMergeBaseException.MergeBaseFailureReason;
import org.eclipse.jgit.junit.RepositoryTestCase; 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.merge.ResolveMerger.MergeFailureReason;
import org.eclipse.jgit.revwalk.RevCommit; 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.treewalk.FileTreeIterator;
import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils; 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 * Merging two equal subtrees with an incore merger should lead to a merged
* state (The 'Gerrit' use case). * state.
* *
* @param strategy * @param strategy
* @throws Exception * @throws Exception
@ -441,6 +452,43 @@ public class ResolveMergerTest extends RepositoryTestCase {
assertTrue(noProblems); assertTrue(noProblems);
} }
/**
* 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 * Merging two equal subtrees when the index and HEAD does not contain any
* file in that subtree should lead to a merged state. * file in that subtree should lead to a merged state.
@ -612,6 +660,35 @@ public class ResolveMergerTest extends RepositoryTestCase {
assertEquals(expected, read("file")); assertEquals(expected, read("file"));
} }
@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 @Theory
public void checkContentMergeConflict(MergeStrategy strategy) public void checkContentMergeConflict(MergeStrategy strategy)
throws Exception { throws Exception {
@ -644,6 +721,49 @@ public class ResolveMergerTest extends RepositoryTestCase {
assertEquals(expected, read("file")); 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 * Merging after criss-cross merges. In this case we merge together two
* commits which have two equally good common ancestors * commits which have two equally good common ancestors
@ -875,4 +995,15 @@ public class ResolveMergerTest extends RepositoryTestCase {
curMod >= lastMod); 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);
}
} }

30
org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java

@ -71,6 +71,16 @@ public class SimpleMergeTest extends SampleDataRepositoryTestCase {
assertEquals(db.resolve("a^{tree}"), ourMerger.getResultTreeId()); assertEquals(db.resolve("a^{tree}"), ourMerger.getResultTreeId());
} }
@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 @Test
public void testTheirs() throws IOException { public void testTheirs() throws IOException {
Merger ourMerger = MergeStrategy.THEIRS.newMerger(db); Merger ourMerger = MergeStrategy.THEIRS.newMerger(db);
@ -79,6 +89,16 @@ public class SimpleMergeTest extends SampleDataRepositoryTestCase {
assertEquals(db.resolve("c^{tree}"), ourMerger.getResultTreeId()); assertEquals(db.resolve("c^{tree}"), ourMerger.getResultTreeId());
} }
@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 @Test
public void testTrivialTwoWay() throws IOException { public void testTrivialTwoWay() throws IOException {
Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db); Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
@ -103,6 +123,16 @@ public class SimpleMergeTest extends SampleDataRepositoryTestCase {
assertEquals(db.resolve("a^0^0^{tree}"), ourMerger.getResultTreeId()); assertEquals(db.resolve("a^0^0^{tree}"), ourMerger.getResultTreeId());
} }
@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 @Test
public void testTrivialTwoWay_conflict() throws IOException { public void testTrivialTwoWay_conflict() throws IOException {
Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db); Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);

1
org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties

@ -538,6 +538,7 @@ renamesFindingExact=Finding exact renames
renamesRejoiningModifies=Rejoining modified file pairs renamesRejoiningModifies=Rejoining modified file pairs
repositoryAlreadyExists=Repository already exists: {0} repositoryAlreadyExists=Repository already exists: {0}
repositoryConfigFileInvalid=Repository config file {0} invalid {1} repositoryConfigFileInvalid=Repository config file {0} invalid {1}
repositoryIsRequired=repository is required
repositoryNotFound=repository not found: {0} repositoryNotFound=repository not found: {0}
repositoryState_applyMailbox=Apply mailbox repositoryState_applyMailbox=Apply mailbox
repositoryState_bare=Bare repositoryState_bare=Bare

1
org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java

@ -597,6 +597,7 @@ public class JGitText extends TranslationBundle {
/***/ public String renamesRejoiningModifies; /***/ public String renamesRejoiningModifies;
/***/ public String repositoryAlreadyExists; /***/ public String repositoryAlreadyExists;
/***/ public String repositoryConfigFileInvalid; /***/ public String repositoryConfigFileInvalid;
/***/ public String repositoryIsRequired;
/***/ public String repositoryNotFound; /***/ public String repositoryNotFound;
/***/ public String repositoryState_applyMailbox; /***/ public String repositoryState_applyMailbox;
/***/ public String repositoryState_bare; /***/ public String repositoryState_bare;

18
org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeStrategy.java

@ -49,6 +49,8 @@ import java.text.MessageFormat;
import java.util.HashMap; import java.util.HashMap;
import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
/** /**
@ -170,4 +172,20 @@ public abstract class MergeStrategy {
* @return the new merge instance which implements this strategy. * @return the new merge instance which implements this strategy.
*/ */
public abstract Merger newMerger(Repository db, boolean inCore); 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);
} }

60
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.io.IOException;
import java.text.MessageFormat; import java.text.MessageFormat;
import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.NoMergeBaseException; import org.eclipse.jgit.errors.NoMergeBaseException;
import org.eclipse.jgit.errors.NoMergeBaseException.MergeBaseFailureReason; 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}. * Instance of a specific {@link MergeStrategy} for a single {@link Repository}.
*/ */
public abstract class Merger { 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; protected final Repository db;
/** Reader to support {@link #walk} and other object loading. */ /** 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. * the repository this merger will read and write data on.
*/ */
protected Merger(final Repository local) { protected Merger(final Repository local) {
if (local == null) {
throw new NullPointerException(JGitText.get().repositoryIsRequired);
}
db = local; db = local;
inserter = db.newObjectInserter(); inserter = local.newObjectInserter();
reader = inserter.newReader(); reader = inserter.newReader();
walk = new RevWalk(reader); 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. * @return the repository this merger operates on.
*/ */
@Nullable
public Repository getRepository() { public Repository getRepository() {
return db; 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() { public ObjectInserter getObjectInserter() {
return inserter; return inserter;
} }
@ -131,7 +175,9 @@ public abstract class Merger {
* *
* @param oi * @param oi
* the inserter instance to use. Must be associated with the * 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) { public void setObjectInserter(ObjectInserter oi) {
walk.close(); walk.close();
@ -173,9 +219,9 @@ public abstract class Merger {
* *
* @since 3.5 * @since 3.5
* @param flush * @param flush
* whether to flush the underlying object inserter when finished to * whether to flush and close the underlying object inserter when
* store any content-merged blobs and virtual merged bases; if * finished to store any content-merged blobs and virtual merged
* false, callers are responsible for flushing. * bases; if false, callers are responsible for flushing.
* @param tips * @param tips
* source trees to be combined together. The merge base is not * source trees to be combined together. The merge base is not
* included in this set. * included in this set.

13
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.errors.NoMergeBaseException;
import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.CommitBuilder; import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
@ -110,6 +112,17 @@ public class RecursiveMerger extends ResolveMerger {
this(local, false); this(local, false);
} }
/**
* 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 * 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 * have more than one base commit recursively merge the base commits

51
org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java

@ -44,6 +44,9 @@
*/ */
package org.eclipse.jgit.merge; 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.CHARACTER_ENCODING;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; 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.IndexWriteException;
import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.NoWorkTreeException; 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.FileMode;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.revwalk.RevTree;
@ -266,18 +270,25 @@ public class ResolveMerger extends ThreeWayMerger {
*/ */
protected MergeAlgorithm mergeAlgorithm; 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 local
* @param inCore * @param inCore
*/ */
protected ResolveMerger(Repository local, boolean inCore) { protected ResolveMerger(Repository local, boolean inCore) {
super(local); super(local);
SupportedAlgorithm diffAlg = local.getConfig().getEnum( mergeAlgorithm = getMergeAlgorithm(local.getConfig());
ConfigConstants.CONFIG_DIFF_SECTION, null, commitNames = defaultCommitNames();
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$
this.inCore = inCore; this.inCore = inCore;
if (inCore) { if (inCore) {
@ -295,10 +306,24 @@ public class ResolveMerger extends ThreeWayMerger {
this(local, false); 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 @Override
protected boolean mergeImpl() throws IOException { protected boolean mergeImpl() throws IOException {
if (implicitDirCache) if (implicitDirCache)
dircache = getRepository().lockDirCache(); dircache = nonNullRepo().lockDirCache();
try { try {
return mergeTrees(mergeBase(), sourceTrees[0], sourceTrees[1], 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. // of a non-empty directory, for which delete() would fail.
for (int i = toBeDeleted.size() - 1; i >= 0; i--) { for (int i = toBeDeleted.size() - 1; i >= 0; i--) {
String fileName = toBeDeleted.get(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.delete())
if (!f.isDirectory()) if (!f.isDirectory())
failingPaths.put(fileName, failingPaths.put(fileName,
@ -348,7 +373,7 @@ public class ResolveMerger extends ThreeWayMerger {
return; return;
} }
DirCache dc = db.readDirCache(); DirCache dc = nonNullRepo().readDirCache();
Iterator<String> mpathsIt=modifiedFiles.iterator(); Iterator<String> mpathsIt=modifiedFiles.iterator();
while(mpathsIt.hasNext()) { while(mpathsIt.hasNext()) {
String mpath=mpathsIt.next(); String mpath=mpathsIt.next();
@ -785,8 +810,8 @@ public class ResolveMerger extends ThreeWayMerger {
*/ */
private File writeMergedFile(MergeResult<RawText> result) private File writeMergedFile(MergeResult<RawText> result)
throws FileNotFoundException, IOException { throws FileNotFoundException, IOException {
File workTree = db.getWorkTree(); File workTree = nonNullRepo().getWorkTree();
FS fs = db.getFS(); FS fs = nonNullRepo().getFS();
File of = new File(workTree, tw.getPathString()); File of = new File(workTree, tw.getPathString());
File parentFolder = of.getParentFile(); File parentFolder = of.getParentFile();
if (!fs.exists(parentFolder)) if (!fs.exists(parentFolder))
@ -802,7 +827,7 @@ public class ResolveMerger extends ThreeWayMerger {
private ObjectId insertMergeResult(MergeResult<RawText> result) private ObjectId insertMergeResult(MergeResult<RawText> result)
throws IOException { throws IOException {
TemporaryBuffer.LocalFile buf = new TemporaryBuffer.LocalFile( TemporaryBuffer.LocalFile buf = new TemporaryBuffer.LocalFile(
db.getDirectory(), 10 << 20); db != null ? nonNullRepo().getDirectory() : null, 10 << 20);
try { try {
new MergeFormatter().formatMerge(buf, result, new MergeFormatter().formatMerge(buf, result,
Arrays.asList(commitNames), CHARACTER_ENCODING); Arrays.asList(commitNames), CHARACTER_ENCODING);

12
org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyOneSided.java

@ -46,7 +46,9 @@ package org.eclipse.jgit.merge;
import java.io.IOException; import java.io.IOException;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
/** /**
@ -89,6 +91,11 @@ public class StrategyOneSided extends MergeStrategy {
return new OneSide(db, treeIndex); 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 { static class OneSide extends Merger {
private final int treeIndex; private final int treeIndex;
@ -97,6 +104,11 @@ public class StrategyOneSided extends MergeStrategy {
treeIndex = index; treeIndex = index;
} }
protected OneSide(final ObjectInserter inserter, final int index) {
super(inserter);
treeIndex = index;
}
@Override @Override
protected boolean mergeImpl() throws IOException { protected boolean mergeImpl() throws IOException {
return treeIndex < sourceTrees.length; return treeIndex < sourceTrees.length;

7
org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyRecursive.java

@ -43,6 +43,8 @@
package org.eclipse.jgit.merge; package org.eclipse.jgit.merge;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
/** /**
@ -62,6 +64,11 @@ public class StrategyRecursive extends StrategyResolve {
return new RecursiveMerger(db, inCore); return new RecursiveMerger(db, inCore);
} }
@Override
public ThreeWayMerger newMerger(ObjectInserter inserter, Config config) {
return new RecursiveMerger(inserter, config);
}
@Override @Override
public String getName() { public String getName() {
return "recursive"; //$NON-NLS-1$ return "recursive"; //$NON-NLS-1$

7
org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyResolve.java

@ -43,6 +43,8 @@
*/ */
package org.eclipse.jgit.merge; package org.eclipse.jgit.merge;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
/** /**
@ -60,6 +62,11 @@ public class StrategyResolve extends ThreeWayMergeStrategy {
return new ResolveMerger(db, inCore); return new ResolveMerger(db, inCore);
} }
@Override
public ThreeWayMerger newMerger(ObjectInserter inserter, Config config) {
return new ResolveMerger(inserter, config);
}
@Override @Override
public String getName() { public String getName() {
return "resolve"; //$NON-NLS-1$ return "resolve"; //$NON-NLS-1$

12
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.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheEntry; import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.errors.UnmergedPathException; import org.eclipse.jgit.errors.UnmergedPathException;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter; import org.eclipse.jgit.lib.ObjectInserter;
@ -89,6 +90,11 @@ public class StrategySimpleTwoWayInCore extends ThreeWayMergeStrategy {
return newMerger(db); return newMerger(db);
} }
@Override
public ThreeWayMerger newMerger(ObjectInserter inserter, Config config) {
return new InCoreMerger(inserter);
}
private static class InCoreMerger extends ThreeWayMerger { private static class InCoreMerger extends ThreeWayMerger {
private static final int T_BASE = 0; private static final int T_BASE = 0;
@ -110,6 +116,12 @@ public class StrategySimpleTwoWayInCore extends ThreeWayMergeStrategy {
cache = DirCache.newInCore(); cache = DirCache.newInCore();
} }
InCoreMerger(final ObjectInserter inserter) {
super(inserter);
tw = new NameConflictTreeWalk(null, reader);
cache = DirCache.newInCore();
}
@Override @Override
protected boolean mergeImpl() throws IOException { protected boolean mergeImpl() throws IOException {
tw.addTree(mergeBase()); tw.addTree(mergeBase());

12
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.errors.MissingObjectException;
import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.revwalk.RevTree;
@ -84,6 +85,17 @@ public abstract class ThreeWayMerger extends Merger {
this(local); this(local);
} }
/**
* 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. * Set the common ancestor tree.
* *

Loading…
Cancel
Save