diff options
| author | Patrick Steinhardt <ps@pks.im> | 2018-02-20 16:14:54 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-02-20 16:14:54 +0000 |
| commit | 894ccf4b162f87745ce890485f198374e9404152 (patch) | |
| tree | 1288dac33a8e54a36a5a7b49b8a66f8e27dc8fdf | |
| parent | afc5124bb6ce8ee9f3741276dd7427b0a499cef3 (diff) | |
| parent | 4e4771dcc77c6f26b4a0b296d68f7b310cad0076 (diff) | |
| download | libgit2-894ccf4b162f87745ce890485f198374e9404152.tar.gz | |
Merge pull request #4535 from libgit2/ethomson/checkout_typechange_with_index_and_wd
checkout: when examining index (instead of workdir), also examine mode
| -rw-r--r-- | src/checkout.c | 26 | ||||
| -rw-r--r-- | tests/checkout/head.c | 45 |
2 files changed, 61 insertions, 10 deletions
diff --git a/src/checkout.c b/src/checkout.c index 528fbdf92..2ad736afe 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -205,17 +205,23 @@ static bool checkout_is_workdir_modified( return rval; } - /* Look at the cache to decide if the workdir is modified. If not, - * we can simply compare the oid in the cache to the baseitem instead - * of hashing the file. If so, we allow the checkout to proceed if the - * oid is identical (ie, the staged item is what we're trying to check - * out.) + /* + * Look at the cache to decide if the workdir is modified: if the + * cache contents match the workdir contents, then we do not need + * to examine the working directory directly, instead we can + * examine the cache to see if _it_ has been modified. This allows + * us to avoid touching the disk. */ - if ((ie = git_index_get_bypath(data->index, wditem->path, 0)) != NULL) { - if (git_index_time_eq(&wditem->mtime, &ie->mtime) && - wditem->file_size == ie->file_size && - !is_file_mode_changed(wditem->mode, ie->mode)) - return !is_workdir_base_or_new(&ie->id, baseitem, newitem); + ie = git_index_get_bypath(data->index, wditem->path, 0); + + if (ie != NULL && + git_index_time_eq(&wditem->mtime, &ie->mtime) && + wditem->file_size == ie->file_size && + !is_file_mode_changed(wditem->mode, ie->mode)) { + + /* The workdir is modified iff the index entry is modified */ + return !is_workdir_base_or_new(&ie->id, baseitem, newitem) || + is_file_mode_changed(baseitem->mode, ie->mode); } /* depending on where base is coming from, we may or may not know diff --git a/tests/checkout/head.c b/tests/checkout/head.c index ded86df33..46b22570d 100644 --- a/tests/checkout/head.c +++ b/tests/checkout/head.c @@ -136,3 +136,48 @@ void test_checkout_head__do_remove_tracked_subdir(void) cl_assert(!git_path_isfile("testrepo/subdir/tracked-file")); cl_assert(git_path_isfile("testrepo/subdir/untracked-file")); } + +void test_checkout_head__typechange_workdir(void) +{ + git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; + git_object *target; + struct stat st; + + opts.checkout_strategy = GIT_CHECKOUT_FORCE; + + cl_git_pass(git_revparse_single(&target, g_repo, "HEAD")); + cl_git_pass(git_reset(g_repo, target, GIT_RESET_HARD, NULL)); + + cl_must_pass(p_chmod("testrepo/new.txt", 0755)); + cl_git_pass(git_checkout_head(g_repo, &opts)); + + cl_git_pass(p_stat("testrepo/new.txt", &st)); + cl_assert(!GIT_PERMS_IS_EXEC(st.st_mode)); + + git_object_free(target); +} + +void test_checkout_head__typechange_index_and_workdir(void) +{ + git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; + git_object *target; + git_index *index; + struct stat st; + + opts.checkout_strategy = GIT_CHECKOUT_FORCE; + + cl_git_pass(git_revparse_single(&target, g_repo, "HEAD")); + cl_git_pass(git_reset(g_repo, target, GIT_RESET_HARD, NULL)); + + cl_must_pass(p_chmod("testrepo/new.txt", 0755)); + cl_git_pass(git_repository_index(&index, g_repo)); + cl_git_pass(git_index_add_bypath(index, "new.txt")); + cl_git_pass(git_index_write(index)); + cl_git_pass(git_checkout_head(g_repo, &opts)); + + cl_git_pass(p_stat("testrepo/new.txt", &st)); + cl_assert(!GIT_PERMS_IS_EXEC(st.st_mode)); + + git_object_free(target); + git_index_free(index); +} |
