summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2015-09-16 17:46:24 +0200
committerCarlos Martín Nieto <cmn@dwim.me>2015-09-16 17:46:24 +0200
commitadd0378d8eb76cb7fde92bcbed3eb59ee5b8947c (patch)
tree4f693b9149765c90fdd77eb0bdbf959450dc87a0
parentb1f6c0b6fa8bbb0c9c11a4d09c731a7f7c311558 (diff)
parenteea7c850248c04a6ac3aadbb13b2c72c2237013b (diff)
downloadlibgit2-add0378d8eb76cb7fde92bcbed3eb59ee5b8947c.tar.gz
Merge pull request #3429 from ethomson/checkout_chmod
Checkout: handle mode changes
-rw-r--r--src/checkout.c15
-rw-r--r--tests/checkout/tree.c84
2 files changed, 87 insertions, 12 deletions
diff --git a/src/checkout.c b/src/checkout.c
index de48c9e01..8c06b3335 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -243,6 +243,12 @@ static int checkout_action_common(
if (delta->new_file.mode == GIT_FILEMODE_LINK && wd != NULL)
*action |= CHECKOUT_ACTION__REMOVE;
+ /* if the file is on disk and doesn't match our mode, force update */
+ if (wd &&
+ GIT_PERMS_IS_EXEC(wd->mode) !=
+ GIT_PERMS_IS_EXEC(delta->new_file.mode))
+ *action |= CHECKOUT_ACTION__REMOVE;
+
notify = GIT_CHECKOUT_NOTIFY_UPDATED;
}
@@ -1500,15 +1506,6 @@ static int blob_content_to_file(
if (error < 0)
return error;
- if (GIT_PERMS_IS_EXEC(mode)) {
- data->perfdata.chmod_calls++;
-
- if ((error = p_chmod(path, mode)) < 0) {
- giterr_set(GITERR_OS, "Failed to set permissions on '%s'", path);
- return error;
- }
- }
-
if (st) {
data->perfdata.stat_calls++;
diff --git a/tests/checkout/tree.c b/tests/checkout/tree.c
index be4019822..5680b86df 100644
--- a/tests/checkout/tree.c
+++ b/tests/checkout/tree.c
@@ -946,7 +946,7 @@ void test_checkout_tree__filemode_preserved_in_index(void)
cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts));
cl_assert(entry = git_index_get_bypath(index, "executable.txt", 0));
- cl_assert_equal_i(0100755, entry->mode);
+ cl_assert(GIT_PERMS_IS_EXEC(entry->mode));
git_commit_free(commit);
@@ -957,7 +957,7 @@ void test_checkout_tree__filemode_preserved_in_index(void)
cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts));
cl_assert(entry = git_index_get_bypath(index, "a/b.txt", 0));
- cl_assert_equal_i(0100644, entry->mode);
+ cl_assert(!GIT_PERMS_IS_EXEC(entry->mode));
git_commit_free(commit);
@@ -968,7 +968,18 @@ void test_checkout_tree__filemode_preserved_in_index(void)
cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts));
cl_assert(entry = git_index_get_bypath(index, "a/b.txt", 0));
- cl_assert_equal_i(0100755, entry->mode);
+ cl_assert(GIT_PERMS_IS_EXEC(entry->mode));
+
+ git_commit_free(commit);
+
+
+ /* Finally, check out the text file again and check that the exec bit is cleared */
+ cl_git_pass(git_oid_fromstr(&executable_oid, "cf80f8de9f1185bf3a05f993f6121880dd0cfbc9"));
+ cl_git_pass(git_commit_lookup(&commit, g_repo, &executable_oid));
+
+ cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts));
+ cl_assert(entry = git_index_get_bypath(index, "a/b.txt", 0));
+ cl_assert(!GIT_PERMS_IS_EXEC(entry->mode));
git_commit_free(commit);
@@ -976,6 +987,73 @@ void test_checkout_tree__filemode_preserved_in_index(void)
git_index_free(index);
}
+mode_t read_filemode(const char *path)
+{
+ git_buf fullpath = GIT_BUF_INIT;
+ struct stat st;
+ mode_t result;
+
+ git_buf_joinpath(&fullpath, "testrepo", path);
+ cl_must_pass(p_stat(fullpath.ptr, &st));
+
+ result = GIT_PERMS_IS_EXEC(st.st_mode) ?
+ GIT_FILEMODE_BLOB_EXECUTABLE : GIT_FILEMODE_BLOB;
+
+ git_buf_free(&fullpath);
+
+ return result;
+}
+
+void test_checkout_tree__filemode_preserved_in_workdir(void)
+{
+#ifndef GIT_WIN32
+ git_oid executable_oid;
+ git_commit *commit;
+ git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+
+ opts.checkout_strategy = GIT_CHECKOUT_FORCE;
+
+ /* test a freshly added executable */
+ cl_git_pass(git_oid_fromstr(&executable_oid, "afe4393b2b2a965f06acf2ca9658eaa01e0cd6b6"));
+ cl_git_pass(git_commit_lookup(&commit, g_repo, &executable_oid));
+
+ cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts));
+ cl_assert(GIT_PERMS_IS_EXEC(read_filemode("executable.txt")));
+
+ git_commit_free(commit);
+
+
+ /* Now start with a commit which has a text file */
+ cl_git_pass(git_oid_fromstr(&executable_oid, "cf80f8de9f1185bf3a05f993f6121880dd0cfbc9"));
+ cl_git_pass(git_commit_lookup(&commit, g_repo, &executable_oid));
+
+ cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts));
+ cl_assert(!GIT_PERMS_IS_EXEC(read_filemode("a/b.txt")));
+
+ git_commit_free(commit);
+
+
+ /* And then check out to a commit which converts the text file to an executable */
+ cl_git_pass(git_oid_fromstr(&executable_oid, "144344043ba4d4a405da03de3844aa829ae8be0e"));
+ cl_git_pass(git_commit_lookup(&commit, g_repo, &executable_oid));
+
+ cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts));
+ cl_assert(GIT_PERMS_IS_EXEC(read_filemode("a/b.txt")));
+
+ git_commit_free(commit);
+
+
+ /* Finally, check out the text file again and check that the exec bit is cleared */
+ cl_git_pass(git_oid_fromstr(&executable_oid, "cf80f8de9f1185bf3a05f993f6121880dd0cfbc9"));
+ cl_git_pass(git_commit_lookup(&commit, g_repo, &executable_oid));
+
+ cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts));
+ cl_assert(!GIT_PERMS_IS_EXEC(read_filemode("a/b.txt")));
+
+ git_commit_free(commit);
+#endif
+}
+
void test_checkout_tree__removes_conflicts(void)
{
git_oid commit_id;