Commit 3f201f75 by Patrick Steinhardt

checkout: fix file being treated as unmodified due to racy index

When trying to determine whether a file changed, we try to avoid heavy
operations by fist taking a look at the index, seeing whether the index
entry is modified already. This doesn't seem to cut it, though, as we
currently have the racy checkout::index::can_disable_pathspec_match test
case: sometimes the files get restored to their original contents,
sometimes they aren't.

The issue is caused by a racy index [1]: in case we modify a file, add
it to the index and then modify it again in-place without changing its
file, then we may end up with a modified file that has the same stat(3P)
info as we've currently got it in its corresponding index entry. The
mitigation for this is to treat files with the same mtime as the index
are treated as racily modified. We already have this logic in place for
the index, but not when doing a checkout.

Fix the issue by only consulting the index entry in case it has an older
mtime as the index. Previously, the following script reliably had at
least 20 failures, while now there is no failure to be observed anymore:

```bash
j=0
for i in $(seq 100)
do
	if ! ./libgit2_clar -scheckout::index::can_disable_pathspec_match >/dev/null
	then
		j=$(($j + 1))
	fi
done
echo "Failures: $j"
```

[1]: https://git-scm.com/docs/racy-git
parent 915f8860
......@@ -217,6 +217,7 @@ static bool checkout_is_workdir_modified(
ie = git_index_get_bypath(data->index, wditem->path, 0);
if (ie != NULL &&
!git_index_entry_newer_than_index(ie, data->index) &&
git_index_time_eq(&wditem->mtime, &ie->mtime) &&
wditem->file_size == ie->file_size &&
!is_filemode_changed(wditem->mode, ie->mode, data->respect_filemode)) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment