Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7497584

Browse files
committed
index: check racily clean entries more thoroughly
When an entry has a racy timestamp, we need to check whether the file itself has changed since we put its entry in the index. Only then do we smudge the size field to force a check the next time around.
1 parent ff47537 commit 7497584

File tree

1 file changed

+41
-2
lines changed

1 file changed

+41
-2
lines changed

src/index.c

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -688,20 +688,59 @@ int git_index__changed_relative_to(
688688
return !!git_oid_cmp(&index->checksum, checksum);
689689
}
690690

691+
static bool is_racy_timestamp(git_time_t stamp, git_index_entry *entry)
692+
{
693+
/* Git special-cases submodules in the check */
694+
if (S_ISGITLINK(entry->mode))
695+
return false;
696+
697+
/* If we never read the index, we can't have this race either */
698+
if (stamp == 0)
699+
return false;
700+
701+
/* If the timestamp is the same or newer than the index, it's racy */
702+
return ((int32_t) stamp) <= entry->mtime.seconds;
703+
}
704+
691705
/*
692706
* Force the next diff to take a look at those entries which have the
693707
* same timestamp as the current index.
694708
*/
695-
static void truncate_racily_clean(git_index *index)
709+
static int truncate_racily_clean(git_index *index)
696710
{
697711
size_t i;
712+
int error;
698713
git_index_entry *entry;
699714
git_time_t ts = index->stamp.mtime;
715+
git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
716+
git_diff *diff;
700717

718+
/* Nothing to do if there's no repo to talk about */
719+
if (!INDEX_OWNER(index))
720+
return 0;
721+
722+
/* If there's no workdir, we can't know where to even check */
723+
if (!git_repository_workdir(INDEX_OWNER(index)))
724+
return 0;
725+
726+
diff_opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE | GIT_DIFF_IGNORE_SUBMODULES | GIT_DIFF_DISABLE_PATHSPEC_MATCH;
701727
git_vector_foreach(&index->entries, i, entry) {
702-
if (entry->mtime.seconds == ts || ts == 0)
728+
if (!is_racy_timestamp(ts, entry))
729+
continue;
730+
731+
diff_opts.pathspec.count = 1;
732+
diff_opts.pathspec.strings = (char **) &entry->path;
733+
734+
if ((error = git_diff_index_to_workdir(&diff, INDEX_OWNER(index), index, &diff_opts)) < 0)
735+
return error;
736+
737+
if (git_diff_num_deltas(diff) > 0)
703738
entry->file_size = 0;
739+
740+
git_diff_free(diff);
704741
}
742+
743+
return 0;
705744
}
706745

707746
int git_index_write(git_index *index)

0 commit comments

Comments
 (0)