Commit 752b7c792d7e2aad7be43a88114552233c230780

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 6c7a944..61c85ce 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;