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:
Philipp Thun 2011-03-17 10:48:44 +01:00 committed by Christian Halstrick
parent 28ffed2307
commit bf05108d0b
2 changed files with 162 additions and 0 deletions

View File

@ -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);

View File

@ -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);