Merge "PackFile: Cache the packName string"
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
index 987e647..2761989 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
@@ -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);
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 a055131..5e99fc0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
@@ -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);