implement GIT_CHECKOUT_DRY_RUN to allow notifications without touching the working directory
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
diff --git a/include/git2/checkout.h b/include/git2/checkout.h
index 3c87001..d4c1cfa 100644
--- a/include/git2/checkout.h
+++ b/include/git2/checkout.h
@@ -177,6 +177,9 @@ typedef enum {
/** Normally checkout writes the index upon completion; this prevents that. */
GIT_CHECKOUT_DONT_WRITE_INDEX = (1u << 23),
+ /** Stop checkout after the notifications happend but before the working directory is touched. */
+ GIT_CHECKOUT_DRY_RUN = (1u << 24),
+
/**
* THE FOLLOWING OPTIONS ARE NOT YET IMPLEMENTED
*/
diff --git a/src/checkout.c b/src/checkout.c
index 6548799..7d3b035 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -2606,6 +2606,9 @@ int git_checkout_iterator(
if ((error = checkout_get_actions(&actions, &counts, &data, workdir)) != 0)
goto cleanup;
+ if (data.strategy & GIT_CHECKOUT_DRY_RUN)
+ goto cleanup;
+
data.total_steps = counts[CHECKOUT_ACTION__REMOVE] +
counts[CHECKOUT_ACTION__REMOVE_CONFLICT] +
counts[CHECKOUT_ACTION__UPDATE_BLOB] +
diff --git a/tests/checkout/tree.c b/tests/checkout/tree.c
index f8d9abe..3241a3e 100644
--- a/tests/checkout/tree.c
+++ b/tests/checkout/tree.c
@@ -1636,3 +1636,49 @@ void test_checkout_tree__no_index_refresh(void)
modify_index_and_checkout_tree(&opts);
assert_status_entrycount(g_repo, 0);
}
+
+void test_checkout_tree__dry_run(void)
+{
+ git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+ git_oid oid;
+ git_object *obj = NULL;
+ checkout_counts ct;
+
+ /* first let's get things into a known state - by checkout out the HEAD */
+
+ assert_on_branch(g_repo, "master");
+
+ opts.checkout_strategy = GIT_CHECKOUT_FORCE;
+ cl_git_pass(git_checkout_head(g_repo, &opts));
+
+ cl_assert(!git_path_isdir("testrepo/a"));
+
+ check_file_contents_nocr("testrepo/branch_file.txt", "hi\nbye!\n");
+
+ /* now checkout branch but with dry run enabled */
+
+ memset(&ct, 0, sizeof(ct));
+ opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_DRY_RUN;
+ opts.notify_flags = GIT_CHECKOUT_NOTIFY_ALL;
+ opts.notify_cb = checkout_count_callback;
+ opts.notify_payload = &ct;
+
+ cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/dir"));
+ cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJECT_ANY));
+
+ cl_git_pass(git_checkout_tree(g_repo, obj, &opts));
+ cl_git_pass(git_repository_set_head(g_repo, "refs/heads/dir"));
+
+ assert_on_branch(g_repo, "dir");
+
+ /* these normally would have been created and updated, but with
+ * DRY_RUN they will be unchanged.
+ */
+ cl_assert(!git_path_isdir("testrepo/a"));
+ check_file_contents_nocr("testrepo/branch_file.txt", "hi\nbye!\n");
+
+ /* check that notify callback was invoked */
+ cl_assert_equal_i(ct.n_updates, 2);
+
+ git_object_free(obj);
+}