summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@github.com>2016-06-15 02:00:35 -0500
committerEdward Thomson <ethomson@edwardthomson.com>2017-10-06 23:53:34 +0100
commit752b7c792d7e2aad7be43a88114552233c230780 (patch)
tree8977e6715f0fc4853892c32e8979c86e037fcdaa
parent62ac39314c11ec43e34e2930f990c3d4ad13153b (diff)
downloadlibgit2-752b7c792d7e2aad7be43a88114552233c230780.tar.gz
checkout: treat files as modified if mode differs
When performing a forced checkout, treat files as modified when the workdir or the index is identical except for the mode. This ensures that force checkout will update the mode to the target. (Apply this check for regular files only, if one of the items was a file and the other was another type of item then this would be a typechange and handled independently.)
-rw-r--r--src/checkout.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/src/checkout.c b/src/checkout.c
index 6c7a94441..61c85ceae 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -159,6 +159,11 @@ 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)
+{
+ return (S_ISREG(a) && S_ISREG(b) && a != b);
+}
+
static bool checkout_is_workdir_modified(
checkout_data *data,
const git_diff_file *baseitem,
@@ -200,7 +205,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 +220,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;