Commit e6da3e4496188b36dbc83950f5e771a373c8ebcc

Edward Thomson 2015-02-14T10:33:06

checkout: upgrade to `SAFE_CREATE` when no index file When the repository does not contain an index, emulate git's behavior and upgrade to `SAFE_CREATE`. This allows us to check out repositories created with `git clone --no-checkout`.

diff --git a/src/checkout.c b/src/checkout.c
index f71be26..6e1abce 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -2346,6 +2346,13 @@ static int checkout_data_init(
 		}
 	}
 
+	/* if the repository does not actually have an index file, then this
+	 * is an initial checkout (perhaps from clone), so we allow safe updates
+	 */
+	if (!data->index->on_disk &&
+		(data->opts.checkout_strategy & GIT_CHECKOUT_SAFE) != 0)
+		data->opts.checkout_strategy |= GIT_CHECKOUT_SAFE_CREATE;
+
 	/* if you are forcing, definitely allow safe updates */
 	if ((data->opts.checkout_strategy & GIT_CHECKOUT_FORCE) != 0)
 		data->opts.checkout_strategy |= GIT_CHECKOUT_SAFE_CREATE;
diff --git a/tests/checkout/tree.c b/tests/checkout/tree.c
index 0fabadc..1b4a332 100644
--- a/tests/checkout/tree.c
+++ b/tests/checkout/tree.c
@@ -1264,3 +1264,39 @@ void test_checkout_tree__can_update_but_not_write_index(void)
 	git_object_free(head);
 	git_index_free(index);
 }
+
+/* Emulate checking out in a repo created by clone --no-checkout,
+ * which would not have written an index. */
+void test_checkout_tree__safe_proceeds_if_no_index(void)
+{
+	git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+	git_oid oid;
+	git_object *obj = NULL;
+
+	assert_on_branch(g_repo, "master");
+	cl_must_pass(p_unlink("testrepo/.git/index"));
+
+	/* do second checkout safe because we should be clean after first */
+	opts.checkout_strategy = GIT_CHECKOUT_SAFE;
+
+	cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/subtrees"));
+	cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY));
+
+	cl_git_pass(git_checkout_tree(g_repo, obj, &opts));
+	cl_git_pass(git_repository_set_head(g_repo, "refs/heads/subtrees", NULL, NULL));
+
+	cl_assert(git_path_isfile("testrepo/README"));
+	cl_assert(git_path_isfile("testrepo/branch_file.txt"));
+	cl_assert(git_path_isfile("testrepo/new.txt"));
+	cl_assert(git_path_isfile("testrepo/ab/4.txt"));
+	cl_assert(git_path_isfile("testrepo/ab/c/3.txt"));
+	cl_assert(git_path_isfile("testrepo/ab/de/2.txt"));
+	cl_assert(git_path_isfile("testrepo/ab/de/fgh/1.txt"));
+
+	cl_assert(!git_path_isdir("testrepo/a"));
+
+	assert_on_branch(g_repo, "subtrees");
+
+	git_object_free(obj);
+}
+