Commit 2438817950f4c96a6194b5cceefbb94f1fe33246

Edward Thomson 2016-06-15T02:00:35

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.)

diff --git a/src/checkout.c b/src/checkout.c
index 25018d2..6375917 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;