aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Fink2010-09-21 12:37:01 (EDT)
committerDmitry Fink2010-09-24 14:01:20 (EDT)
commit906887a73586a7fa2ffdeaa8041e045cfbcfd7e2 (patch)
treed20a270719da9665b25d28fc4689007e2649d2fc
parenta67afbfee10ca2963f5f0f52f701376e382572e2 (diff)
downloadjgit-906887a73586a7fa2ffdeaa8041e045cfbcfd7e2.zip
jgit-906887a73586a7fa2ffdeaa8041e045cfbcfd7e2.tar.gz
jgit-906887a73586a7fa2ffdeaa8041e045cfbcfd7e2.tar.bz2
Extend merge support for bare repositoriesrefs/changes/29/1629/5
Optional inCore parameter to Resolver/Strategy will instruct it to perform all the operations in memory and avoid modifying working folder even if there is one. Change-Id: I5b873dead3682f79110f58d7806e43f50bcc5045
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeStrategy.java14
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java123
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyOneSided.java5
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyResolve.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategySimpleTwoWayInCore.java7
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMergeStrategy.java3
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java12
7 files changed, 133 insertions, 39 deletions
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 28347e8..507e148 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeStrategy.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeStrategy.java
@@ -143,4 +143,18 @@ public abstract class MergeStrategy {
* @return the new merge instance which implements this strategy.
*/
public abstract Merger newMerger(Repository db);
+
+ /**
+ * Create a new merge instance.
+ *
+ * @param db
+ * repository database the merger will read from, and eventually
+ * write results back to.
+ * @param inCore
+ * 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.
+ * @return the new merge instance which implements this strategy.
+ */
+ public abstract Merger newMerger(Repository db, boolean inCore);
}
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 42f9849..ecec033 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
@@ -128,6 +128,8 @@ public class ResolveMerger extends ThreeWayMerger {
private boolean enterSubtree;
+ private boolean inCore;
+
private DirCache dircache;
private WorkingTreeIterator workingTreeIt;
@@ -135,11 +137,24 @@ public class ResolveMerger extends ThreeWayMerger {
/**
* @param local
+ * @param inCore
*/
- protected ResolveMerger(Repository local) {
+ protected ResolveMerger(Repository local, boolean inCore) {
super(local);
commitNames = new String[] { "BASE", "OURS", "THEIRS" };
oi = getObjectInserter();
+ this.inCore = inCore;
+
+ if (inCore) {
+ dircache = DirCache.newInCore();
+ }
+ }
+
+ /**
+ * @param local
+ */
+ protected ResolveMerger(Repository local) {
+ this(local, false);
}
@Override
@@ -178,22 +193,26 @@ public class ResolveMerger extends ThreeWayMerger {
tw.enterSubtree();
}
- // All content-merges are successfully done. If we can now write the
- // new
- // index we are on quite safe ground. Even if the checkout of files
- // coming from "theirs" fails the user can work around such failures
- // by
- // checking out the index again.
- if (!builder.commit()) {
- cleanUp();
- throw new IndexWriteException();
+ if (!inCore) {
+ // All content-merges are successfully done. If we can now write the
+ // new index we are on quite safe ground. Even if the checkout of
+ // files coming from "theirs" fails the user can work around such
+ // failures by checking out the index again.
+ if (!builder.commit()) {
+ cleanUp();
+ throw new IndexWriteException();
+ }
+ builder = null;
+
+ // No problem found. The only thing left to be done is to checkout
+ // all files from "theirs" which have been selected to go into the
+ // new index.
+ checkout();
+ } else {
+ builder.finish();
+ builder = null;
}
- builder = null;
- // No problem found. The only thing left to be done is to checkout
- // all files from "theirs" which have been selected to go into the
- // new index.
- checkout();
if (getUnmergedPathes().isEmpty()) {
resultTree = dircache.writeTree(oi);
return true;
@@ -234,13 +253,19 @@ public class ResolveMerger extends ThreeWayMerger {
/**
* Reverts the worktree after an unsuccessful merge. We know that for all
* modified files the old content was in the old index and the index
- * contained only stage 0
+ * contained only stage 0. In case if inCore operation just clear
+ * the history of modified files.
*
* @throws IOException
* @throws CorruptObjectException
* @throws NoWorkTreeException
*/
private void cleanUp() throws NoWorkTreeException, CorruptObjectException, IOException {
+ if (inCore) {
+ modifiedFiles.clear();
+ return;
+ }
+
DirCache dc = db.readDirCache();
ObjectReader or = db.getObjectDatabase().newReader();
Iterator<String> mpathsIt=modifiedFiles.iterator();
@@ -391,14 +416,17 @@ public class ResolveMerger extends ThreeWayMerger {
}
if (nonTree(modeO) && nonTree(modeT)) {
- // We are going to update the worktree. Make sure the worktree is
- // not modified
- if (work != null
- && (!nonTree(work.getEntryRawMode()) || work.isModified(
- index.getDirCacheEntry(), true, true, db.getFS()))) {
- failingPathes.put(tw.getPathString(),
- MergeFailureReason.DIRTY_WORKTREE);
- return false;
+ if (!inCore) {
+ // We are going to update the worktree. Make sure the worktree
+ // is not modified
+ if (work != null
+ && (!nonTree(work.getEntryRawMode()) || work
+ .isModified(index.getDirCacheEntry(), true,
+ true, db.getFS()))) {
+ failingPathes.put(tw.getPathString(),
+ MergeFailureReason.DIRTY_WORKTREE);
+ return false;
+ }
}
if (!contentMerge(base, ours, theirs)) {
@@ -421,24 +449,41 @@ public class ResolveMerger extends ThreeWayMerger {
getRawText(ours.getEntryObjectId(), db),
getRawText(theirs.getEntryObjectId(), db));
- File workTree = db.getWorkTree();
- if (workTree == null)
- // TODO: This should be handled by WorkingTreeIterators which
- // support write operations
- throw new UnsupportedOperationException();
-
- File of = new File(workTree, tw.getPathString());
- FileOutputStream fos = new FileOutputStream(of);
- try {
- fmt.formatMerge(fos, result, Arrays.asList(commitNames),
- Constants.CHARACTER_ENCODING);
- } finally {
- fos.close();
+ File of = null;
+ FileOutputStream fos;
+ if (!inCore) {
+ File workTree = db.getWorkTree();
+ if (workTree == null)
+ // TODO: This should be handled by WorkingTreeIterators which
+ // support write operations
+ throw new UnsupportedOperationException();
+
+ of = new File(workTree, tw.getPathString());
+ 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 = File.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 occured, the file will contain conflict markers
// the index will be populated with the three stages and only the
- // workdir contains the halfways merged content
+ // workdir (if used) contains the halfways merged content
add(tw.getRawPath(), base, DirCacheEntry.STAGE_1);
add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2);
add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3);
@@ -457,6 +502,8 @@ public class ResolveMerger extends ThreeWayMerger {
is));
} finally {
is.close();
+ if (inCore)
+ of.delete();
}
builder.add(dce);
return true;
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 c941af9..34bc9f5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyOneSided.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyOneSided.java
@@ -84,6 +84,11 @@ public class StrategyOneSided extends MergeStrategy {
return new OneSide(db, treeIndex);
}
+ @Override
+ public Merger newMerger(final Repository db, boolean inCore) {
+ return new OneSide(db, treeIndex);
+ }
+
static class OneSide extends Merger {
private final int treeIndex;
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 2885625..e37635e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyResolve.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyResolve.java
@@ -49,9 +49,15 @@ import org.eclipse.jgit.lib.Repository;
* A three-way merge strategy performing a content-merge if necessary
*/
public class StrategyResolve extends ThreeWayMergeStrategy {
+
@Override
public ThreeWayMerger newMerger(Repository db) {
- return new ResolveMerger(db);
+ return new ResolveMerger(db, false);
+ }
+
+ @Override
+ public ThreeWayMerger newMerger(Repository db, boolean inCore) {
+ return new ResolveMerger(db, inCore);
}
@Override
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 29342a7..b8bd475 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategySimpleTwoWayInCore.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategySimpleTwoWayInCore.java
@@ -83,6 +83,12 @@ public class StrategySimpleTwoWayInCore extends ThreeWayMergeStrategy {
return new InCoreMerger(db);
}
+ @Override
+ public ThreeWayMerger newMerger(Repository db, boolean inCore) {
+ // This class is always inCore, so ignore the parameter
+ return newMerger(db);
+ }
+
private static class InCoreMerger extends ThreeWayMerger {
private static final int T_BASE = 0;
@@ -193,4 +199,5 @@ public class StrategySimpleTwoWayInCore extends ThreeWayMergeStrategy {
return resultTree;
}
}
+
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMergeStrategy.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMergeStrategy.java
index 343d897..c71590b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMergeStrategy.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMergeStrategy.java
@@ -49,4 +49,7 @@ import org.eclipse.jgit.lib.Repository;
public abstract class ThreeWayMergeStrategy extends MergeStrategy {
@Override
public abstract ThreeWayMerger newMerger(Repository db);
+
+ @Override
+ public abstract ThreeWayMerger newMerger(Repository db, boolean inCore);
}
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 bb23d0e..9350adf 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java
@@ -67,6 +67,18 @@ public abstract class ThreeWayMerger extends Merger {
}
/**
+ * Create a new merge instance for a repository.
+ *
+ * @param local
+ * the repository this merger will read and write data on.
+ * @param inCore
+ * perform the merge in core with no working folder involved
+ */
+ protected ThreeWayMerger(final Repository local, boolean inCore) {
+ this(local);
+ }
+
+ /**
* Set the common ancestor tree.
*
* @param id