checkout: introduce GIT_CHECKOUT_DONT_WRITE_INDEX
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
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);
+}