summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@github.com>2016-06-15 02:00:35 -0500
committerEdward Thomson <ethomson@github.com>2016-06-25 18:05:44 -0400
commitd2b6a63fd243e1de8e6f8c12faf99ff7185ac2da (patch)
treea0adf3e891a6fbc8532abdbf4ea867ca455156d2
parentd53e99f584648884ce0e972e6422c3c3e4c1901f (diff)
downloadlibgit2-d2b6a63fd243e1de8e6f8c12faf99ff7185ac2da.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 b4e5e3d86..08a555d55 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -160,6 +160,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 is_workdir_modified(
checkout_data *data,
const git_diff_file *baseitem,
@@ -201,7 +206,8 @@ static bool 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);
}
@@ -211,6 +217,9 @@ static bool is_workdir_modified(
if (baseitem->size && wditem->file_size != baseitem->size)
return true;
+ 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;