Abort merge when file to be checked out is dirty
In case a file needs to be checked out (from THEIRS) during a merge operation, it has to be checked if the worktree version of this file is dirty. If this is true, merge shall fail. Change-Id: I17c24845584700aad953c3d4f2bea77a0d665ec4 Signed-off-by: Philipp Thun <philipp.thun@sap.com>
This commit is contained in:
parent
28ffed2307
commit
bf05108d0b
|
@ -638,6 +638,164 @@ public void testMergeConflictFileFolder() throws Exception {
|
|||
assertEquals(RepositoryState.MERGING, db.getRepositoryState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccessfulMergeFailsDueToDirtyIndex() throws Exception {
|
||||
Git git = new Git(db);
|
||||
|
||||
File fileA = writeTrashFile("a", "a");
|
||||
RevCommit initialCommit = addAllAndCommit(git);
|
||||
|
||||
// switch branch
|
||||
createBranch(initialCommit, "refs/heads/side");
|
||||
checkoutBranch("refs/heads/side");
|
||||
// modify file a
|
||||
write(fileA, "a(side)");
|
||||
writeTrashFile("b", "b");
|
||||
RevCommit sideCommit = addAllAndCommit(git);
|
||||
|
||||
// switch branch
|
||||
checkoutBranch("refs/heads/master");
|
||||
writeTrashFile("c", "c");
|
||||
addAllAndCommit(git);
|
||||
|
||||
// modify and add file a
|
||||
write(fileA, "a(modified)");
|
||||
git.add().addFilepattern("a").call();
|
||||
// do not commit
|
||||
|
||||
// get current index state
|
||||
String indexState = indexState(CONTENT);
|
||||
|
||||
// merge
|
||||
MergeResult result = git.merge().include(sideCommit.getId())
|
||||
.setStrategy(MergeStrategy.RESOLVE).call();
|
||||
|
||||
checkMergeFailedResult(result, indexState, fileA);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConflictingMergeFailsDueToDirtyIndex() throws Exception {
|
||||
Git git = new Git(db);
|
||||
|
||||
File fileA = writeTrashFile("a", "a");
|
||||
RevCommit initialCommit = addAllAndCommit(git);
|
||||
|
||||
// switch branch
|
||||
createBranch(initialCommit, "refs/heads/side");
|
||||
checkoutBranch("refs/heads/side");
|
||||
// modify file a
|
||||
write(fileA, "a(side)");
|
||||
writeTrashFile("b", "b");
|
||||
RevCommit sideCommit = addAllAndCommit(git);
|
||||
|
||||
// switch branch
|
||||
checkoutBranch("refs/heads/master");
|
||||
// modify file a - this will cause a conflict during merge
|
||||
write(fileA, "a(master)");
|
||||
writeTrashFile("c", "c");
|
||||
addAllAndCommit(git);
|
||||
|
||||
// modify and add file a
|
||||
write(fileA, "a(modified)");
|
||||
git.add().addFilepattern("a").call();
|
||||
// do not commit
|
||||
|
||||
// get current index state
|
||||
String indexState = indexState(CONTENT);
|
||||
|
||||
// merge
|
||||
MergeResult result = git.merge().include(sideCommit.getId())
|
||||
.setStrategy(MergeStrategy.RESOLVE).call();
|
||||
|
||||
checkMergeFailedResult(result, indexState, fileA);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccessfulMergeFailsDueToDirtyWorktree() throws Exception {
|
||||
Git git = new Git(db);
|
||||
|
||||
File fileA = writeTrashFile("a", "a");
|
||||
RevCommit initialCommit = addAllAndCommit(git);
|
||||
|
||||
// switch branch
|
||||
createBranch(initialCommit, "refs/heads/side");
|
||||
checkoutBranch("refs/heads/side");
|
||||
// modify file a
|
||||
write(fileA, "a(side)");
|
||||
writeTrashFile("b", "b");
|
||||
RevCommit sideCommit = addAllAndCommit(git);
|
||||
|
||||
// switch branch
|
||||
checkoutBranch("refs/heads/master");
|
||||
writeTrashFile("c", "c");
|
||||
addAllAndCommit(git);
|
||||
|
||||
// modify file a
|
||||
write(fileA, "a(modified)");
|
||||
// do not add and commit
|
||||
|
||||
// get current index state
|
||||
String indexState = indexState(CONTENT);
|
||||
|
||||
// merge
|
||||
MergeResult result = git.merge().include(sideCommit.getId())
|
||||
.setStrategy(MergeStrategy.RESOLVE).call();
|
||||
|
||||
checkMergeFailedResult(result, indexState, fileA);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConflictingMergeFailsDueToDirtyWorktree() throws Exception {
|
||||
Git git = new Git(db);
|
||||
|
||||
File fileA = writeTrashFile("a", "a");
|
||||
RevCommit initialCommit = addAllAndCommit(git);
|
||||
|
||||
// switch branch
|
||||
createBranch(initialCommit, "refs/heads/side");
|
||||
checkoutBranch("refs/heads/side");
|
||||
// modify file a
|
||||
write(fileA, "a(side)");
|
||||
writeTrashFile("b", "b");
|
||||
RevCommit sideCommit = addAllAndCommit(git);
|
||||
|
||||
// switch branch
|
||||
checkoutBranch("refs/heads/master");
|
||||
// modify file a - this will cause a conflict during merge
|
||||
write(fileA, "a(master)");
|
||||
writeTrashFile("c", "c");
|
||||
addAllAndCommit(git);
|
||||
|
||||
// modify file a
|
||||
write(fileA, "a(modified)");
|
||||
// do not add and commit
|
||||
|
||||
// get current index state
|
||||
String indexState = indexState(CONTENT);
|
||||
|
||||
// merge
|
||||
MergeResult result = git.merge().include(sideCommit.getId())
|
||||
.setStrategy(MergeStrategy.RESOLVE).call();
|
||||
|
||||
checkMergeFailedResult(result, indexState, fileA);
|
||||
}
|
||||
|
||||
private RevCommit addAllAndCommit(final Git git) throws Exception {
|
||||
git.add().addFilepattern(".").call();
|
||||
return git.commit().setMessage("message").call();
|
||||
}
|
||||
|
||||
private void checkMergeFailedResult(final MergeResult result,
|
||||
final String indexState, final File fileA) throws Exception {
|
||||
assertEquals(MergeStatus.FAILED, result.getMergeStatus());
|
||||
assertEquals("a(modified)", read(fileA));
|
||||
assertFalse(new File(db.getWorkTree(), "b").exists());
|
||||
assertEquals("c", read(new File(db.getWorkTree(), "c")));
|
||||
assertEquals(indexState, indexState(CONTENT));
|
||||
assertEquals(null, result.getConflicts());
|
||||
assertEquals(RepositoryState.SAFE, db.getRepositoryState());
|
||||
}
|
||||
|
||||
private void createBranch(ObjectId objectId, String branchName) throws IOException {
|
||||
RefUpdate updateRef = db.updateRef(branchName);
|
||||
updateRef.setNewObjectId(objectId);
|
||||
|
|
|
@ -393,6 +393,10 @@ private boolean processEntry(CanonicalTreeParser base,
|
|||
if (modeB == modeO && tw.idEqual(T_BASE, T_OURS)) {
|
||||
// OURS was not changed compared to BASE. All changes must be in
|
||||
// THEIRS. THEIRS is chosen.
|
||||
|
||||
// Check worktree before checking out THEIRS
|
||||
if (isWorktreeDirty())
|
||||
return false;
|
||||
if (nonTree(modeT)) {
|
||||
DirCacheEntry e = add(tw.getRawPath(), theirs,
|
||||
DirCacheEntry.STAGE_0);
|
||||
|
|
Loading…
Reference in New Issue