Commit c18a5ec58cd93be0c06e2d94b2f87efca8896969

Vicent Martí 2013-01-04T11:10:39

Merge pull request #1174 from nulltoken/topic/soft_reset_with_index_conflicts Prevent soft reset when index contains conflicts

diff --git a/.gitignore b/.gitignore
index b81a1b1..0289813 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
 /tests-clar/clar.suite
+/tests-clar/clar.suite.rule
 /tests-clar/.clarcache
 /apidocs
 /trash-*.exe
diff --git a/src/reset.c b/src/reset.c
index 784094a..04b0863 100644
--- a/src/reset.c
+++ b/src/reset.c
@@ -15,12 +15,6 @@
 
 #define ERROR_MSG "Cannot perform reset"
 
-static int reset_error_invalid(const char *msg)
-{
-	giterr_set(GITERR_INVALID, "%s - %s", ERROR_MSG, msg);
-	return -1;
-}
-
 static int update_head(git_repository *repo, git_object *commit)
 {
 	int error;
@@ -68,7 +62,7 @@ int git_reset(
 	git_object *commit = NULL;
 	git_index *index = NULL;
 	git_tree *tree = NULL;
-	int error = -1;
+	int error;
 	git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT;
 
 	assert(repo && target);
@@ -76,29 +70,33 @@ int git_reset(
 		|| reset_type == GIT_RESET_MIXED
 		|| reset_type == GIT_RESET_HARD);
 
-	if (git_object_owner(target) != repo)
-		return reset_error_invalid("The given target does not belong to this repository.");
+	if (git_object_owner(target) != repo) {
+		giterr_set(GITERR_OBJECT,
+			"%s - The given target does not belong to this repository.", ERROR_MSG);
+		return -1;
+	}
 
 	if (reset_type != GIT_RESET_SOFT
-		&& git_repository__ensure_not_bare(
+		&& (error = git_repository__ensure_not_bare(
 			repo,
-			reset_type == GIT_RESET_MIXED ? "reset mixed" : "reset hard") < 0)
-				return GIT_EBAREREPO;
+			reset_type == GIT_RESET_MIXED ? "reset mixed" : "reset hard")) < 0)
+				return error;
 
-	if (git_object_peel(&commit, target, GIT_OBJ_COMMIT) < 0) {
-		reset_error_invalid("The given target does not resolve to a commit");
+	if ((error = git_object_peel(&commit, target, GIT_OBJ_COMMIT)) < 0)
 		goto cleanup;
-	}
 
-	if (reset_type == GIT_RESET_SOFT && (git_repository_state(repo) == GIT_REPOSITORY_STATE_MERGE)) {
-		giterr_set(GITERR_OBJECT, "%s (soft) while in the middle of a merge.", ERROR_MSG);
-		error = GIT_EUNMERGED;
+	if ((error = git_repository_index(&index, repo)) < 0)
 		goto cleanup;
-	}
 
-	//TODO: Check for unmerged entries
+	if (reset_type == GIT_RESET_SOFT && 
+		(git_repository_state(repo) == GIT_REPOSITORY_STATE_MERGE ||
+		git_index_has_conflicts(index))) {
+			giterr_set(GITERR_OBJECT, "%s (soft) while in the middle of a merge.", ERROR_MSG);
+			error = GIT_EUNMERGED;
+			goto cleanup;
+	}
 
-	if (update_head(repo, commit) < 0)
+	if ((error = update_head(repo, commit)) < 0)
 		goto cleanup;
 
 	if (reset_type == GIT_RESET_SOFT) {
@@ -106,28 +104,17 @@ int git_reset(
 		goto cleanup;
 	}
 
-	if (git_commit_tree(&tree, (git_commit *)commit) < 0) {
-		giterr_set(GITERR_OBJECT, "%s - Failed to retrieve the commit tree.", ERROR_MSG);
+	if ((error = git_commit_tree(&tree, (git_commit *)commit)) < 0)
 		goto cleanup;
-	}
 
-	if (git_repository_index(&index, repo) < 0) {
-		giterr_set(GITERR_OBJECT, "%s - Failed to retrieve the index.", ERROR_MSG);
+	if ((error = git_index_read_tree(index, tree)) < 0)
 		goto cleanup;
-	}
 
-	if (git_index_read_tree(index, tree) < 0) {
-		giterr_set(GITERR_INDEX, "%s - Failed to update the index.", ERROR_MSG);
+	if ((error = git_index_write(index)) < 0)
 		goto cleanup;
-	}
-
-	if (git_index_write(index) < 0) {
-		giterr_set(GITERR_INDEX, "%s - Failed to write the index.", ERROR_MSG);
-		goto cleanup;
-	}
 
 	if ((error = git_repository_merge_cleanup(repo)) < 0) {
-		giterr_set(GITERR_INDEX, "%s - Failed to clean up merge data.", ERROR_MSG);
+		giterr_set(GITERR_REPOSITORY, "%s - Failed to clean up merge data.", ERROR_MSG);
 		goto cleanup;
 	}
 
@@ -138,12 +125,7 @@ int git_reset(
 
 	opts.checkout_strategy = GIT_CHECKOUT_FORCE;
 
-	if (git_checkout_index(repo, NULL, &opts) < 0) {
-		giterr_set(GITERR_INDEX, "%s - Failed to checkout the index.", ERROR_MSG);
-		goto cleanup;
-	}
-
-	error = 0;
+	error = git_checkout_index(repo, NULL, &opts);
 
 cleanup:
 	git_object_free(commit);
diff --git a/tests-clar/reset/soft.c b/tests-clar/reset/soft.c
index 9ebd637..884697c 100644
--- a/tests-clar/reset/soft.c
+++ b/tests-clar/reset/soft.c
@@ -130,3 +130,28 @@ void test_reset_soft__fails_when_merging(void)
 
 	git_buf_free(&merge_head_path);
 }
+
+void test_reset_soft__fails_when_index_contains_conflicts_independently_of_MERGE_HEAD_file_existence(void)
+{
+	git_index *index;
+	git_reference *head;
+	git_buf merge_head_path = GIT_BUF_INIT;
+
+	cl_git_sandbox_cleanup();
+
+	repo = cl_git_sandbox_init("mergedrepo");
+
+	cl_git_pass(git_buf_joinpath(&merge_head_path, git_repository_path(repo), "MERGE_HEAD"));
+	cl_git_pass(p_unlink(git_buf_cstr(&merge_head_path)));
+	git_buf_free(&merge_head_path);
+
+	cl_git_pass(git_repository_index(&index, repo));
+	cl_assert_equal_i(true, git_index_has_conflicts(index));
+	git_index_free(index);
+
+	cl_git_pass(git_repository_head(&head, repo));
+	cl_git_pass(git_reference_peel(&target, head, GIT_OBJ_COMMIT));
+	git_reference_free(head);
+
+	cl_assert_equal_i(GIT_EUNMERGED, git_reset(repo, target, GIT_RESET_SOFT));
+}