Browse Source

Extend merge support for bare repositories

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
stable-0.10
Dmitry Fink 14 years ago
parent
commit
906887a735
  1. 14
      org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeStrategy.java
  2. 123
      org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
  3. 5
      org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyOneSided.java
  4. 8
      org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyResolve.java
  5. 7
      org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategySimpleTwoWayInCore.java
  6. 3
      org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMergeStrategy.java
  7. 12
      org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java

14
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. * @return the new merge instance which implements this strategy.
*/ */
public abstract Merger newMerger(Repository db); 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);
} }

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

@ -128,6 +128,8 @@ public class ResolveMerger extends ThreeWayMerger {
private boolean enterSubtree; private boolean enterSubtree;
private boolean inCore;
private DirCache dircache; private DirCache dircache;
private WorkingTreeIterator workingTreeIt; private WorkingTreeIterator workingTreeIt;
@ -135,11 +137,24 @@ public class ResolveMerger extends ThreeWayMerger {
/** /**
* @param local * @param local
* @param inCore
*/ */
protected ResolveMerger(Repository local) { protected ResolveMerger(Repository local, boolean inCore) {
super(local); super(local);
commitNames = new String[] { "BASE", "OURS", "THEIRS" }; commitNames = new String[] { "BASE", "OURS", "THEIRS" };
oi = getObjectInserter(); oi = getObjectInserter();
this.inCore = inCore;
if (inCore) {
dircache = DirCache.newInCore();
}
}
/**
* @param local
*/
protected ResolveMerger(Repository local) {
this(local, false);
} }
@Override @Override
@ -178,22 +193,26 @@ public class ResolveMerger extends ThreeWayMerger {
tw.enterSubtree(); tw.enterSubtree();
} }
// All content-merges are successfully done. If we can now write the if (!inCore) {
// new // All content-merges are successfully done. If we can now write the
// index we are on quite safe ground. Even if the checkout of files // new index we are on quite safe ground. Even if the checkout of
// coming from "theirs" fails the user can work around such failures // files coming from "theirs" fails the user can work around such
// by // failures by checking out the index again.
// checking out the index again. if (!builder.commit()) {
if (!builder.commit()) { cleanUp();
cleanUp(); throw new IndexWriteException();
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()) { if (getUnmergedPathes().isEmpty()) {
resultTree = dircache.writeTree(oi); resultTree = dircache.writeTree(oi);
return true; return true;
@ -234,13 +253,19 @@ public class ResolveMerger extends ThreeWayMerger {
/** /**
* Reverts the worktree after an unsuccessful merge. We know that for all * 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 * 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 IOException
* @throws CorruptObjectException * @throws CorruptObjectException
* @throws NoWorkTreeException * @throws NoWorkTreeException
*/ */
private void cleanUp() throws NoWorkTreeException, CorruptObjectException, IOException { private void cleanUp() throws NoWorkTreeException, CorruptObjectException, IOException {
if (inCore) {
modifiedFiles.clear();
return;
}
DirCache dc = db.readDirCache(); DirCache dc = db.readDirCache();
ObjectReader or = db.getObjectDatabase().newReader(); ObjectReader or = db.getObjectDatabase().newReader();
Iterator<String> mpathsIt=modifiedFiles.iterator(); Iterator<String> mpathsIt=modifiedFiles.iterator();
@ -391,14 +416,17 @@ public class ResolveMerger extends ThreeWayMerger {
} }
if (nonTree(modeO) && nonTree(modeT)) { if (nonTree(modeO) && nonTree(modeT)) {
// We are going to update the worktree. Make sure the worktree is if (!inCore) {
// not modified // We are going to update the worktree. Make sure the worktree
if (work != null // is not modified
&& (!nonTree(work.getEntryRawMode()) || work.isModified( if (work != null
index.getDirCacheEntry(), true, true, db.getFS()))) { && (!nonTree(work.getEntryRawMode()) || work
failingPathes.put(tw.getPathString(), .isModified(index.getDirCacheEntry(), true,
MergeFailureReason.DIRTY_WORKTREE); true, db.getFS()))) {
return false; failingPathes.put(tw.getPathString(),
MergeFailureReason.DIRTY_WORKTREE);
return false;
}
} }
if (!contentMerge(base, ours, theirs)) { if (!contentMerge(base, ours, theirs)) {
@ -421,24 +449,41 @@ public class ResolveMerger extends ThreeWayMerger {
getRawText(ours.getEntryObjectId(), db), getRawText(ours.getEntryObjectId(), db),
getRawText(theirs.getEntryObjectId(), db)); getRawText(theirs.getEntryObjectId(), db));
File workTree = db.getWorkTree(); File of = null;
if (workTree == null) FileOutputStream fos;
// TODO: This should be handled by WorkingTreeIterators which if (!inCore) {
// support write operations File workTree = db.getWorkTree();
throw new UnsupportedOperationException(); if (workTree == null)
// TODO: This should be handled by WorkingTreeIterators which
File of = new File(workTree, tw.getPathString()); // support write operations
FileOutputStream fos = new FileOutputStream(of); throw new UnsupportedOperationException();
try {
fmt.formatMerge(fos, result, Arrays.asList(commitNames), of = new File(workTree, tw.getPathString());
Constants.CHARACTER_ENCODING); fos = new FileOutputStream(of);
} finally { try {
fos.close(); 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()) { if (result.containsConflicts()) {
// a conflict occured, the file will contain conflict markers // a conflict occured, the file will contain conflict markers
// the index will be populated with the three stages and only the // 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(), base, DirCacheEntry.STAGE_1);
add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2); add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2);
add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3); add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3);
@ -457,6 +502,8 @@ public class ResolveMerger extends ThreeWayMerger {
is)); is));
} finally { } finally {
is.close(); is.close();
if (inCore)
of.delete();
} }
builder.add(dce); builder.add(dce);
return true; return true;

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

@ -84,6 +84,11 @@ public class StrategyOneSided extends MergeStrategy {
return new OneSide(db, treeIndex); return new OneSide(db, treeIndex);
} }
@Override
public Merger newMerger(final Repository db, boolean inCore) {
return new OneSide(db, treeIndex);
}
static class OneSide extends Merger { static class OneSide extends Merger {
private final int treeIndex; private final int treeIndex;

8
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 * A three-way merge strategy performing a content-merge if necessary
*/ */
public class StrategyResolve extends ThreeWayMergeStrategy { public class StrategyResolve extends ThreeWayMergeStrategy {
@Override @Override
public ThreeWayMerger newMerger(Repository db) { 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 @Override

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

@ -83,6 +83,12 @@ public class StrategySimpleTwoWayInCore extends ThreeWayMergeStrategy {
return new InCoreMerger(db); 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 class InCoreMerger extends ThreeWayMerger {
private static final int T_BASE = 0; private static final int T_BASE = 0;
@ -193,4 +199,5 @@ public class StrategySimpleTwoWayInCore extends ThreeWayMergeStrategy {
return resultTree; return resultTree;
} }
} }
} }

3
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 { public abstract class ThreeWayMergeStrategy extends MergeStrategy {
@Override @Override
public abstract ThreeWayMerger newMerger(Repository db); public abstract ThreeWayMerger newMerger(Repository db);
@Override
public abstract ThreeWayMerger newMerger(Repository db, boolean inCore);
} }

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

@ -66,6 +66,18 @@ public abstract class ThreeWayMerger extends Merger {
super(local); super(local);
} }
/**
* 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. * Set the common ancestor tree.
* *

Loading…
Cancel
Save