Skip to content

Commit d7fea1e

Browse files
committed
checkout: take mode into account when comparing index to baseline
When checking out a file, we determine whether the baseline (what we expect to be in the working directory) actually matches the contents of the working directory. This is safe behavior to prevent us from overwriting changes in the working directory. We look at the index to optimize this test: if we know that the index matches the working directory, then we can simply look at the index data compared to the baseline. We have historically compared the baseline to the index entry by oid. However, we must also compare the mode of the two items to ensure that they are identical. Otherwise, we will refuse to update the working directory for a mode change.
1 parent 952cf71 commit d7fea1e

File tree

1 file changed

+16
-10
lines changed

1 file changed

+16
-10
lines changed

src/checkout.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -205,17 +205,23 @@ static bool checkout_is_workdir_modified(
205205
return rval;
206206
}
207207

208-
/* Look at the cache to decide if the workdir is modified. If not,
209-
* we can simply compare the oid in the cache to the baseitem instead
210-
* of hashing the file. If so, we allow the checkout to proceed if the
211-
* oid is identical (ie, the staged item is what we're trying to check
212-
* out.)
208+
/*
209+
* Look at the cache to decide if the workdir is modified: if the
210+
* cache contents match the workdir contents, then we do not need
211+
* to examine the working directory directly, instead we can
212+
* examine the cache to see if _it_ has been modified. This allows
213+
* us to avoid touching the disk.
213214
*/
214-
if ((ie = git_index_get_bypath(data->index, wditem->path, 0)) != NULL) {
215-
if (git_index_time_eq(&wditem->mtime, &ie->mtime) &&
216-
wditem->file_size == ie->file_size &&
217-
!is_file_mode_changed(wditem->mode, ie->mode))
218-
return !is_workdir_base_or_new(&ie->id, baseitem, newitem);
215+
ie = git_index_get_bypath(data->index, wditem->path, 0);
216+
217+
if (ie != NULL &&
218+
git_index_time_eq(&wditem->mtime, &ie->mtime) &&
219+
wditem->file_size == ie->file_size &&
220+
!is_file_mode_changed(wditem->mode, ie->mode)) {
221+
222+
/* The workdir is modified iff the index entry is modified */
223+
return !is_workdir_base_or_new(&ie->id, baseitem, newitem) ||
224+
is_file_mode_changed(baseitem->mode, ie->mode);
219225
}
220226

221227
/* depending on where base is coming from, we may or may not know

0 commit comments

Comments
 (0)