Commit 958205a33d9e9d078f41a9a3ac04dc7c657840c7

Jochen Hunz 2021-04-14T22:05:47

implement GIT_CHECKOUT_DRY_RUN to allow notifications without touching the working directory

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);
+}