summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2017-10-09 09:00:29 +0200
committerGitHub <noreply@github.com>2017-10-09 09:00:29 +0200
commit38e769cb22bd1dda0ae96c14e375f524d4fc47c3 (patch)
tree14d7698b66647504c9fd0a8c118c19de0741a0a4
parent21e6a11a55fc2ca0f7385ef2f43cd75090a10d5f (diff)
parent19e8faba79b300a5ee355e606af5d1f62b4ac930 (diff)
downloadlibgit2-38e769cb22bd1dda0ae96c14e375f524d4fc47c3.tar.gz
Merge pull request #4369 from libgit2/ethomson/checkout_typechange
Checkout typechange-only deltas
-rw-r--r--src/checkout.c19
-rw-r--r--tests/checkout/tree.c45
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));