Commit 8639ea5f98ac53e532820e8a186f8a1d6d98f573

Edward Thomson 2015-01-17T22:47:03

checkout: introduce GIT_CHECKOUT_DONT_WRITE_INDEX

diff --git a/include/git2/checkout.h b/include/git2/checkout.h
index 8314c62..4fe1340 100644
--- a/include/git2/checkout.h
+++ b/include/git2/checkout.h
@@ -135,7 +135,10 @@ typedef enum {
 	/** Only update existing files, don't create new ones */
 	GIT_CHECKOUT_UPDATE_ONLY = (1u << 7),
 
-	/** Normally checkout updates index entries as it goes; this stops that */
+	/**
+	 * Normally checkout updates index entries as it goes; this stops that.
+	 * Implies `GIT_CHECKOUT_DONT_WRITE_INDEX`.
+	 */
 	GIT_CHECKOUT_DONT_UPDATE_INDEX = (1u << 8),
 
 	/** Don't refresh index/config/etc before doing checkout */
@@ -166,6 +169,9 @@ typedef enum {
 	/** Don't overwrite existing files or folders */
 	GIT_CHECKOUT_DONT_REMOVE_EXISTING = (1u << 22),
 
+	/** Normally checkout writes the index upon completion; this prevents that. */
+	GIT_CHECKOUT_DONT_WRITE_INDEX = (1u << 23),
+
 	/**
 	 * THE FOLLOWING OPTIONS ARE NOT YET IMPLEMENTED
 	 */
diff --git a/src/checkout.c b/src/checkout.c
index 3f65a9e..3953840 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -2375,6 +2375,9 @@ cleanup:
 	return error;
 }
 
+#define CHECKOUT_INDEX_DONT_WRITE_MASK \
+	(GIT_CHECKOUT_DONT_UPDATE_INDEX | GIT_CHECKOUT_DONT_WRITE_INDEX)
+
 int git_checkout_iterator(
 	git_iterator *target,
 	git_index *index,
@@ -2481,7 +2484,7 @@ int git_checkout_iterator(
 
 cleanup:
 	if (!error && data.index != NULL &&
-		(data.strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0)
+		(data.strategy & CHECKOUT_INDEX_DONT_WRITE_MASK) == 0)
 		error = git_index_write(data.index);
 
 	git_diff_free(data.diff);
diff --git a/tests/checkout/tree.c b/tests/checkout/tree.c
index 239ee55..0fabadc 100644
--- a/tests/checkout/tree.c
+++ b/tests/checkout/tree.c
@@ -1184,3 +1184,83 @@ void test_checkout_tree__caches_attributes_during_checkout(void)
 	git_buf_free(&ident2);
 	git_object_free(obj);
 }
+
+void test_checkout_tree__can_not_update_index(void)
+{
+	git_oid oid;
+	git_object *head;
+	unsigned int status;
+	git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+	git_index *index;
+
+	opts.checkout_strategy |=
+		GIT_CHECKOUT_FORCE | GIT_CHECKOUT_DONT_UPDATE_INDEX;
+
+	cl_git_pass(git_reference_name_to_id(&oid, g_repo, "HEAD"));
+	cl_git_pass(git_object_lookup(&head, g_repo, &oid, GIT_OBJ_ANY));
+
+	cl_git_pass(git_reset(g_repo, head, GIT_RESET_HARD, &g_opts, NULL, NULL));
+
+	cl_assert_equal_i(false, git_path_isdir("./testrepo/ab/"));
+
+	cl_git_pass(git_revparse_single(&g_object, g_repo, "subtrees"));
+
+	cl_git_pass(git_checkout_tree(g_repo, g_object, &opts));
+
+	cl_assert_equal_i(true, git_path_isfile("./testrepo/ab/de/2.txt"));
+	cl_git_pass(git_status_file(&status, g_repo, "ab/de/2.txt"));
+	cl_assert_equal_i(GIT_STATUS_WT_NEW, status);
+
+	cl_git_pass(git_repository_index(&index, g_repo));
+	cl_git_pass(git_index_write(index));
+
+	cl_git_pass(git_status_file(&status, g_repo, "ab/de/2.txt"));
+	cl_assert_equal_i(GIT_STATUS_WT_NEW, status);
+
+	git_object_free(head);
+	git_index_free(index);
+}
+
+void test_checkout_tree__can_update_but_not_write_index(void)
+{
+	git_oid oid;
+	git_object *head;
+	unsigned int status;
+	git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+	git_index *index;
+	git_repository *other;
+
+	opts.checkout_strategy |=
+		GIT_CHECKOUT_FORCE | GIT_CHECKOUT_DONT_WRITE_INDEX;
+
+	cl_git_pass(git_reference_name_to_id(&oid, g_repo, "HEAD"));
+	cl_git_pass(git_object_lookup(&head, g_repo, &oid, GIT_OBJ_ANY));
+
+	cl_git_pass(git_reset(g_repo, head, GIT_RESET_HARD, &g_opts, NULL, NULL));
+
+	cl_assert_equal_i(false, git_path_isdir("./testrepo/ab/"));
+
+	cl_git_pass(git_revparse_single(&g_object, g_repo, "subtrees"));
+
+	cl_git_pass(git_checkout_tree(g_repo, g_object, &opts));
+
+	cl_assert_equal_i(true, git_path_isfile("./testrepo/ab/de/2.txt"));
+	cl_git_pass(git_status_file(&status, g_repo, "ab/de/2.txt"));
+	cl_assert_equal_i(GIT_STATUS_INDEX_NEW, status);
+
+	cl_git_pass(git_repository_open(&other, "testrepo"));
+	cl_git_pass(git_status_file(&status, other, "ab/de/2.txt"));
+	cl_assert_equal_i(GIT_STATUS_WT_NEW, status);
+	git_repository_free(other);
+
+	cl_git_pass(git_repository_index(&index, g_repo));
+	cl_git_pass(git_index_write(index));
+
+	cl_git_pass(git_repository_open(&other, "testrepo"));
+	cl_git_pass(git_status_file(&status, other, "ab/de/2.txt"));
+	cl_assert_equal_i(GIT_STATUS_INDEX_NEW, status);
+	git_repository_free(other);
+
+	git_object_free(head);
+	git_index_free(index);
+}