Added also tests and the associated option for the command line Merge command. Bug: 335091 Change-Id: Ie321c572284a6f64765a81674089fc408a10d059 Signed-off-by: Christian Halstrick <christian.halstrick@sap.com> Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>tags/v3.0.0.201305080800-m7
@@ -49,7 +49,6 @@ import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.eclipse.jgit.internal.storage.file.FileRepository; | |||
import org.eclipse.jgit.junit.JGitTestUtil; | |||
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; | |||
import org.eclipse.jgit.pgm.CLIGitCommand; | |||
@@ -57,7 +56,7 @@ import org.junit.Before; | |||
public class CLIRepositoryTestCase extends LocalDiskRepositoryTestCase { | |||
/** Test repository, initialized for this test case. */ | |||
protected FileRepository db; | |||
protected Repository db; | |||
/** Working directory of {@link #db}. */ | |||
protected File trash; | |||
@@ -165,7 +164,7 @@ public class CLIRepositoryTestCase extends LocalDiskRepositoryTestCase { | |||
assertEquals(toText(expected), toText(actual)); | |||
} | |||
private String toText(String[] lines) { | |||
private static String toText(String[] lines) { | |||
StringBuilder b = new StringBuilder(); | |||
for (String s : lines) { | |||
b.append(s); |
@@ -101,6 +101,40 @@ public class MergeTest extends CLIRepositoryTestCase { | |||
+ "' strategy.", execute("git merge master")[0]); | |||
} | |||
@Test | |||
public void testMergeNoCommit() throws Exception { | |||
git.branchCreate().setName("side").call(); | |||
writeTrashFile("master", "content"); | |||
git.add().addFilepattern("master").call(); | |||
git.commit().setMessage("master commit").call(); | |||
git.checkout().setName("side").call(); | |||
writeTrashFile("side", "content"); | |||
git.add().addFilepattern("side").call(); | |||
git.commit().setMessage("side commit").call(); | |||
assertEquals( | |||
"Automatic merge went well; stopped before committing as requested", | |||
execute("git merge --no-commit master")[0]); | |||
} | |||
@Test | |||
public void testMergeNoCommitSquash() throws Exception { | |||
git.branchCreate().setName("side").call(); | |||
writeTrashFile("master", "content"); | |||
git.add().addFilepattern("master").call(); | |||
git.commit().setMessage("master commit").call(); | |||
git.checkout().setName("side").call(); | |||
writeTrashFile("side", "content"); | |||
git.add().addFilepattern("side").call(); | |||
git.commit().setMessage("side commit").call(); | |||
assertArrayEquals( | |||
new String[] { | |||
"Squash commit -- not updating HEAD", | |||
"Automatic merge went well; stopped before committing as requested", | |||
"" }, execute("git merge --no-commit --squash master")); | |||
} | |||
@Test | |||
public void testSquash() throws Exception { | |||
git.branchCreate().setName("side").call(); |
@@ -1,6 +1,11 @@ | |||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
<component id="org.eclipse.jgit.pgm" version="2"> | |||
<resource path="src/org/eclipse/jgit/pgm/CLIText.java" type="org.eclipse.jgit.pgm.CLIText"> | |||
<filter id="1143996420"> | |||
<message_arguments> | |||
<message_argument value="mergeWentWellStoppedBeforeCommitting"/> | |||
</message_arguments> | |||
</filter> | |||
<filter id="1143996420"> | |||
<message_arguments> | |||
<message_argument value="noSuchRemoteRef"/> |
@@ -68,6 +68,7 @@ mergeConflict=CONFLICT(content): Merge conflict in {0} | |||
mergeFailed=Automatic merge failed; fix conflicts and then commit the result | |||
mergeMadeBy=Merge made by the ''{0}'' strategy. | |||
mergedSquashed=Squash commit -- not updating HEAD\nAutomatic merge went well; stopped before committing as requested | |||
mergeWentWellStoppedBeforeCommitting=Automatic merge went well; stopped before committing as requested | |||
metaVar_DAG=DAG | |||
metaVar_KEY=KEY | |||
metaVar_archiveFormat=format | |||
@@ -248,6 +249,7 @@ usage_manageReflogInformation=Manage reflog information | |||
usage_mergeStrategy=Use the given merge strategy. Can be supplied more than once to specify them in the order they should be tried. If there is no -s option, the resolve strategy is used. Currently the following strategies are supported: ours, theirs, simple-two-way-in-core, resolve | |||
usage_moveRenameABranch=move/rename a branch | |||
usage_nameStatus=show only name and status of files | |||
usage_noCommit=Don't commit after a successful merge | |||
usage_noPrefix=do not show any source or destination prefix | |||
usage_noRenames=disable rename detection | |||
usage_noShowStandardNotes=Disable showing notes from the standard /refs/notes/commits branch |
@@ -137,6 +137,7 @@ public class CLIText extends TranslationBundle { | |||
/***/ public String mergeFailed; | |||
/***/ public String mergeMadeBy; | |||
/***/ public String mergedSquashed; | |||
/***/ public String mergeWentWellStoppedBeforeCommitting; | |||
/***/ public String metaVar_KEY; | |||
/***/ public String metaVar_archiveFormat; | |||
/***/ public String metaVar_arg; |
@@ -71,6 +71,9 @@ class Merge extends TextBuiltin { | |||
@Option(name = "--squash", usage = "usage_squash") | |||
private boolean squash; | |||
@Option(name = "--no-commit", usage = "usage_noCommit") | |||
private boolean noCommit = false; | |||
private MergeStrategy mergeStrategy = MergeStrategy.RESOLVE; | |||
@Argument(required = true) | |||
@@ -111,7 +114,7 @@ class Merge extends TextBuiltin { | |||
Ref oldHead = db.getRef(Constants.HEAD); | |||
Git git = new Git(db); | |||
MergeCommand mergeCmd = git.merge().setStrategy(mergeStrategy) | |||
.setSquash(squash).setFastForward(ff); | |||
.setSquash(squash).setFastForward(ff).setCommit(!noCommit); | |||
if (srcRef != null) | |||
mergeCmd.include(srcRef); | |||
else | |||
@@ -160,8 +163,12 @@ class Merge extends TextBuiltin { | |||
name = "recursive"; //$NON-NLS-1$ | |||
outw.println(MessageFormat.format(CLIText.get().mergeMadeBy, name)); | |||
break; | |||
case MERGED_NOT_COMMITTED: | |||
outw.println(CLIText.get().mergeWentWellStoppedBeforeCommitting); | |||
break; | |||
case MERGED_SQUASHED: | |||
case FAST_FORWARD_SQUASHED: | |||
case MERGED_SQUASHED_NOT_COMMITTED: | |||
outw.println(CLIText.get().mergedSquashed); | |||
break; | |||
case ABORTED: |
@@ -141,6 +141,28 @@ public class MergeCommandTest extends RepositoryTestCase { | |||
db.getReflogReader(db.getBranch()).getLastEntry().getComment()); | |||
} | |||
@Test | |||
public void testFastForwardNoCommit() throws Exception { | |||
Git git = new Git(db); | |||
RevCommit first = git.commit().setMessage("initial commit").call(); | |||
createBranch(first, "refs/heads/branch1"); | |||
RevCommit second = git.commit().setMessage("second commit").call(); | |||
checkoutBranch("refs/heads/branch1"); | |||
MergeResult result = git.merge().include(db.getRef(Constants.MASTER)) | |||
.setCommit(false).call(); | |||
assertEquals(MergeResult.MergeStatus.FAST_FORWARD, | |||
result.getMergeStatus()); | |||
assertEquals(second, result.getNewHead()); | |||
assertEquals("merge refs/heads/master: Fast-forward", db | |||
.getReflogReader(Constants.HEAD).getLastEntry().getComment()); | |||
assertEquals("merge refs/heads/master: Fast-forward", db | |||
.getReflogReader(db.getBranch()).getLastEntry().getComment()); | |||
} | |||
@Test | |||
public void testFastForwardWithFiles() throws Exception { | |||
Git git = new Git(db); | |||
@@ -234,6 +256,31 @@ public class MergeCommandTest extends RepositoryTestCase { | |||
db.getReflogReader(db.getBranch()).getLastEntry().getComment()); | |||
} | |||
@Theory | |||
public void testMergeSuccessAllStrategiesNoCommit( | |||
MergeStrategy mergeStrategy) throws Exception { | |||
Git git = new Git(db); | |||
RevCommit first = git.commit().setMessage("first").call(); | |||
createBranch(first, "refs/heads/side"); | |||
writeTrashFile("a", "a"); | |||
git.add().addFilepattern("a").call(); | |||
git.commit().setMessage("second").call(); | |||
checkoutBranch("refs/heads/side"); | |||
writeTrashFile("b", "b"); | |||
git.add().addFilepattern("b").call(); | |||
RevCommit thirdCommit = git.commit().setMessage("third").call(); | |||
MergeResult result = git.merge().setStrategy(mergeStrategy) | |||
.setCommit(false) | |||
.include(db.getRef(Constants.MASTER)).call(); | |||
assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus()); | |||
assertEquals(db.getRef(Constants.HEAD).getTarget().getObjectId(), | |||
thirdCommit.getId()); | |||
} | |||
@Test | |||
public void testContentMerge() throws Exception { | |||
Git git = new Git(db); | |||
@@ -480,6 +527,56 @@ public class MergeCommandTest extends RepositoryTestCase { | |||
// test index state | |||
} | |||
@Test | |||
public void testSuccessfulContentMergeNoCommit() throws Exception { | |||
Git git = new Git(db); | |||
writeTrashFile("a", "1\na\n3\n"); | |||
writeTrashFile("b", "1\nb\n3\n"); | |||
writeTrashFile("c/c/c", "1\nc\n3\n"); | |||
git.add().addFilepattern("a").addFilepattern("b") | |||
.addFilepattern("c/c/c").call(); | |||
RevCommit initialCommit = git.commit().setMessage("initial").call(); | |||
createBranch(initialCommit, "refs/heads/side"); | |||
checkoutBranch("refs/heads/side"); | |||
writeTrashFile("a", "1(side)\na\n3\n"); | |||
writeTrashFile("b", "1\nb(side)\n3\n"); | |||
git.add().addFilepattern("a").addFilepattern("b").call(); | |||
RevCommit secondCommit = git.commit().setMessage("side").call(); | |||
assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); | |||
checkoutBranch("refs/heads/master"); | |||
assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); | |||
writeTrashFile("a", "1\na\n3(main)\n"); | |||
writeTrashFile("c/c/c", "1\nc(main)\n3\n"); | |||
git.add().addFilepattern("a").addFilepattern("c/c/c").call(); | |||
RevCommit thirdCommit = git.commit().setMessage("main").call(); | |||
MergeResult result = git.merge().include(secondCommit.getId()) | |||
.setCommit(false) | |||
.setStrategy(MergeStrategy.RESOLVE).call(); | |||
assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus()); | |||
assertEquals(db.getRef(Constants.HEAD).getTarget().getObjectId(), | |||
thirdCommit.getId()); | |||
assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(), | |||
"a"))); | |||
assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); | |||
assertEquals("1\nc(main)\n3\n", | |||
read(new File(db.getWorkTree(), "c/c/c"))); | |||
assertEquals(null, result.getConflicts()); | |||
assertEquals(2, result.getMergedCommits().length); | |||
assertEquals(thirdCommit, result.getMergedCommits()[0]); | |||
assertEquals(secondCommit, result.getMergedCommits()[1]); | |||
assertNull(result.getNewHead()); | |||
assertEquals(RepositoryState.MERGING_RESOLVED, db.getRepositoryState()); | |||
} | |||
@Test | |||
public void testSuccessfulContentMergeAndDirtyworkingTree() | |||
throws Exception { | |||
@@ -1345,6 +1442,7 @@ public class MergeCommandTest extends RepositoryTestCase { | |||
assertEquals(MergeStatus.FAST_FORWARD, result.getMergeStatus()); | |||
} | |||
@Test | |||
public void testNoFastForward() throws Exception { | |||
Git git = new Git(db); | |||
@@ -1362,6 +1460,33 @@ public class MergeCommandTest extends RepositoryTestCase { | |||
assertEquals(MergeStatus.MERGED, result.getMergeStatus()); | |||
} | |||
@Test | |||
public void testNoFastForwardNoCommit() throws Exception { | |||
// given | |||
Git git = new Git(db); | |||
RevCommit initialCommit = git.commit().setMessage("initial commit") | |||
.call(); | |||
createBranch(initialCommit, "refs/heads/branch1"); | |||
RevCommit secondCommit = git.commit().setMessage("second commit") | |||
.call(); | |||
checkoutBranch("refs/heads/branch1"); | |||
// when | |||
MergeCommand merge = git.merge(); | |||
merge.setFastForward(FastForwardMode.NO_FF); | |||
merge.include(db.getRef(Constants.MASTER)); | |||
merge.setCommit(false); | |||
MergeResult result = merge.call(); | |||
// then | |||
assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus()); | |||
assertEquals(2, result.getMergedCommits().length); | |||
assertEquals(initialCommit, result.getMergedCommits()[0]); | |||
assertEquals(secondCommit, result.getMergedCommits()[1]); | |||
assertNull(result.getNewHead()); | |||
assertEquals(RepositoryState.MERGING_RESOLVED, db.getRepositoryState()); | |||
} | |||
@Test | |||
public void testFastForwardOnlyNotPossible() throws Exception { | |||
Git git = new Git(db); |
@@ -195,6 +195,8 @@ public class MergeCommand extends GitCommand<MergeResult> { | |||
} | |||
} | |||
private boolean commit = true; | |||
/** | |||
* @param repo | |||
*/ | |||
@@ -327,7 +329,7 @@ public class MergeCommand extends GitCommand<MergeResult> { | |||
if (merger instanceof ResolveMerger) { | |||
ResolveMerger resolveMerger = (ResolveMerger) merger; | |||
resolveMerger.setCommitNames(new String[] { | |||
"BASE", "HEAD", ref.getName() }); //$NON-NLS-1$ | |||
"BASE", "HEAD", ref.getName() }); //$NON-NLS-1$ //$NON-NLS-2$ | |||
resolveMerger.setWorkingTreeIterator(new FileTreeIterator(repo)); | |||
noProblems = merger.merge(headCommit, srcCommit); | |||
lowLevelResults = resolveMerger | |||
@@ -350,18 +352,26 @@ public class MergeCommand extends GitCommand<MergeResult> { | |||
dco.checkout(); | |||
String msg = null; | |||
RevCommit newHead = null; | |||
ObjectId newHeadId = null; | |||
MergeStatus mergeStatus = null; | |||
if (!squash) { | |||
newHead = new Git(getRepository()).commit() | |||
.setReflogComment(refLogMessage.toString()).call(); | |||
if (!commit && squash) { | |||
mergeStatus = MergeStatus.MERGED_SQUASHED_NOT_COMMITTED; | |||
} | |||
if (!commit && !squash) { | |||
mergeStatus = MergeStatus.MERGED_NOT_COMMITTED; | |||
} | |||
if (commit && !squash) { | |||
newHeadId = new Git(getRepository()).commit() | |||
.setReflogComment(refLogMessage.toString()) | |||
.call().getId(); | |||
mergeStatus = MergeStatus.MERGED; | |||
} else { | |||
} | |||
if (commit && squash) { | |||
msg = JGitText.get().squashCommitNotUpdatingHEAD; | |||
newHead = headCommit; | |||
newHeadId = headCommit.getId(); | |||
mergeStatus = MergeStatus.MERGED_SQUASHED; | |||
} | |||
return new MergeResult(newHead.getId(), null, | |||
return new MergeResult(newHeadId, null, | |||
new ObjectId[] { headCommit.getId(), | |||
srcCommit.getId() }, mergeStatus, | |||
mergeStrategy, null, msg); | |||
@@ -521,4 +531,23 @@ public class MergeCommand extends GitCommand<MergeResult> { | |||
this.fastForwardMode = fastForwardMode; | |||
return this; | |||
} | |||
/** | |||
* Controls whether the merge command should automatically commit after a | |||
* successful merge | |||
* | |||
* @param commit | |||
* <code>true</code> if this command should commit (this is the | |||
* default behavior). <code>false</code> if this command should | |||
* not commit. In case the merge was successful but this flag was | |||
* set to <code>false</code> a {@link MergeResult} with type | |||
* {@link MergeResult} with status | |||
* {@link MergeStatus#MERGED_NOT_COMMITTED} is returned | |||
* @return {@code this} | |||
* @since 3.0 | |||
*/ | |||
public MergeCommand setCommit(boolean commit) { | |||
this.commit = commit; | |||
return this; | |||
} | |||
} |
@@ -141,6 +141,20 @@ public class MergeResult { | |||
return true; | |||
} | |||
}, | |||
/** | |||
* @since 3.0 | |||
*/ | |||
MERGED_SQUASHED_NOT_COMMITTED { | |||
@Override | |||
public String toString() { | |||
return "Merged-squashed-not-committed"; | |||
} | |||
@Override | |||
public boolean isSuccessful() { | |||
return true; | |||
} | |||
}, | |||
/** */ | |||
CONFLICTING { | |||
@Override | |||
@@ -167,6 +181,19 @@ public class MergeResult { | |||
return false; | |||
} | |||
}, | |||
/** | |||
* @since 3.0 | |||
**/ | |||
MERGED_NOT_COMMITTED { | |||
public String toString() { | |||
return "MergedNotCommited"; | |||
} | |||
@Override | |||
public boolean isSuccessful() { | |||
return true; | |||
} | |||
}, | |||
/** */ | |||
NOT_SUPPORTED { | |||
@Override |