diff options
author | Patrick Steinhardt <ps@pks.im> | 2017-10-09 09:00:29 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-10-09 09:00:29 +0200 |
commit | 38e769cb22bd1dda0ae96c14e375f524d4fc47c3 (patch) | |
tree | 14d7698b66647504c9fd0a8c118c19de0741a0a4 | |
parent | 21e6a11a55fc2ca0f7385ef2f43cd75090a10d5f (diff) | |
parent | 19e8faba79b300a5ee355e606af5d1f62b4ac930 (diff) | |
download | libgit2-38e769cb22bd1dda0ae96c14e375f524d4fc47c3.tar.gz |
Merge pull request #4369 from libgit2/ethomson/checkout_typechange
Checkout typechange-only deltas
-rw-r--r-- | src/checkout.c | 19 | ||||
-rw-r--r-- | tests/checkout/tree.c | 45 |
2 files changed, 63 insertions, 1 deletions
diff --git a/src/checkout.c b/src/checkout.c index 6c7a94441..caed6cdf1 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -159,6 +159,19 @@ GIT_INLINE(bool) is_workdir_base_or_new( git_oid__cmp(&newitem->id, workdir_id) == 0); } +GIT_INLINE(bool) is_file_mode_changed(git_filemode_t a, git_filemode_t b) +{ +#ifdef GIT_WIN32 + /* + * On Win32 we do not support the executable bit; the file will + * always be 0100644 on disk, don't bother doing a test. + */ + return false; +#else + return (S_ISREG(a) && S_ISREG(b) && a != b); +#endif +} + static bool checkout_is_workdir_modified( checkout_data *data, const git_diff_file *baseitem, @@ -200,7 +213,8 @@ static bool checkout_is_workdir_modified( */ 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) + wditem->file_size == ie->file_size && + !is_file_mode_changed(wditem->mode, ie->mode)) return !is_workdir_base_or_new(&ie->id, baseitem, newitem); } @@ -214,6 +228,9 @@ static bool checkout_is_workdir_modified( if (S_ISDIR(wditem->mode)) return false; + if (is_file_mode_changed(baseitem->mode, wditem->mode)) + return true; + if (git_diff__oid_for_entry(&oid, data->diff, wditem, wditem->mode, NULL) < 0) return false; diff --git a/tests/checkout/tree.c b/tests/checkout/tree.c index b3b860c63..c3475f411 100644 --- a/tests/checkout/tree.c +++ b/tests/checkout/tree.c @@ -1514,6 +1514,51 @@ void test_checkout_tree__baseline_is_empty_when_no_index(void) git_reference_free(head); } +void test_checkout_tree__mode_change_is_force_updated(void) +{ + git_index *index; + git_reference *head; + git_object *obj; + git_status_list *status; + + if (!cl_is_chmod_supported()) + clar__skip(); + + assert_on_branch(g_repo, "master"); + cl_git_pass(git_repository_index(&index, g_repo)); + cl_git_pass(git_repository_head(&head, g_repo)); + cl_git_pass(git_reference_peel(&obj, head, GIT_OBJ_COMMIT)); + + cl_git_pass(git_reset(g_repo, obj, GIT_RESET_HARD, NULL)); + + cl_git_pass(git_status_list_new(&status, g_repo, NULL)); + cl_assert_equal_i(0, git_status_list_entrycount(status)); + git_status_list_free(status); + + /* update the mode on-disk */ + cl_must_pass(p_chmod("testrepo/README", 0755)); + + cl_git_pass(git_checkout_tree(g_repo, obj, &g_opts)); + + cl_git_pass(git_status_list_new(&status, g_repo, NULL)); + cl_assert_equal_i(0, git_status_list_entrycount(status)); + git_status_list_free(status); + + /* update the mode on-disk and in the index */ + cl_must_pass(p_chmod("testrepo/README", 0755)); + cl_must_pass(git_index_add_bypath(index, "README")); + + cl_git_pass(git_checkout_tree(g_repo, obj, &g_opts)); + + cl_git_pass(git_status_list_new(&status, g_repo, NULL)); + cl_assert_equal_i(0, git_status_list_entrycount(status)); + git_status_list_free(status); + + git_object_free(obj); + git_reference_free(head); + git_index_free(index); +} + void test_checkout_tree__nullopts(void) { cl_git_pass(git_checkout_tree(g_repo, NULL, NULL)); |