diff --git a/src/checkout.c b/src/checkout.c index f71be26f9..6e1abce4a 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 0fabadc8d..1b4a33273 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); +} +