diff options
author | Carlos Martín Nieto <cmn@dwim.me> | 2015-09-16 17:46:24 +0200 |
---|---|---|
committer | Carlos Martín Nieto <cmn@dwim.me> | 2015-09-16 17:46:24 +0200 |
commit | add0378d8eb76cb7fde92bcbed3eb59ee5b8947c (patch) | |
tree | 4f693b9149765c90fdd77eb0bdbf959450dc87a0 | |
parent | b1f6c0b6fa8bbb0c9c11a4d09c731a7f7c311558 (diff) | |
parent | eea7c850248c04a6ac3aadbb13b2c72c2237013b (diff) | |
download | libgit2-add0378d8eb76cb7fde92bcbed3eb59ee5b8947c.tar.gz |
Merge pull request #3429 from ethomson/checkout_chmod
Checkout: handle mode changes
-rw-r--r-- | src/checkout.c | 15 | ||||
-rw-r--r-- | tests/checkout/tree.c | 84 |
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; |