summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/diff.c15
-rw-r--r--src/iterator.c2
-rw-r--r--tests/diff/workdir.c4
-rw-r--r--tests/status/worktree.c6
4 files changed, 19 insertions, 8 deletions
diff --git a/src/diff.c b/src/diff.c
index aa880650a..4c028ca4e 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -664,6 +664,7 @@ static int maybe_modified(
unsigned int omode = oitem->mode;
unsigned int nmode = nitem->mode;
bool new_is_workdir = (info->new_iter->type == GIT_ITERATOR_TYPE_WORKDIR);
+ bool modified_uncertain = false;
const char *matched_pathspec;
int error = 0;
@@ -731,15 +732,21 @@ static int maybe_modified(
/* if the stat data looks different, then mark modified - this just
* means that the OID will be recalculated below to confirm change
*/
- else if (omode != nmode ||
- oitem->file_size != nitem->file_size ||
- !diff_time_eq(&oitem->mtime, &nitem->mtime, use_nanos) ||
+ else if (omode != nmode || oitem->file_size != nitem->file_size) {
+ status = GIT_DELTA_MODIFIED;
+ modified_uncertain =
+ (oitem->file_size <= 0 && nitem->file_size > 0);
+ }
+ else if (!diff_time_eq(&oitem->mtime, &nitem->mtime, use_nanos) ||
(use_ctime &&
!diff_time_eq(&oitem->ctime, &nitem->ctime, use_nanos)) ||
oitem->ino != nitem->ino ||
oitem->uid != nitem->uid ||
oitem->gid != nitem->gid)
+ {
status = GIT_DELTA_MODIFIED;
+ modified_uncertain = true;
+ }
}
/* if mode is GITLINK and submodules are ignored, then skip */
@@ -750,7 +757,7 @@ static int maybe_modified(
/* if we got here and decided that the files are modified, but we
* haven't calculated the OID of the new item, then calculate it now
*/
- if (status == GIT_DELTA_MODIFIED && git_oid_iszero(&nitem->id)) {
+ if (modified_uncertain && git_oid_iszero(&nitem->id)) {
if (git_oid_iszero(&noid)) {
if ((error = git_diff__oid_for_file(&noid,
diff, nitem->path, nitem->mode, nitem->file_size)) < 0)
diff --git a/src/iterator.c b/src/iterator.c
index 5e668b50c..03058b956 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -1306,7 +1306,7 @@ static int workdir_iterator__enter_dir(fs_iterator *fi)
/* convert submodules to GITLINK and remove trailing slashes */
git_vector_foreach(&ff->entries, pos, entry) {
- if (!S_ISDIR(entry->st.st_mode))
+ if (!S_ISDIR(entry->st.st_mode) || !strcmp(GIT_DIR, entry->path))
continue;
GIT_PERF_INC(fi->base.submodule_lookups);
diff --git a/tests/diff/workdir.c b/tests/diff/workdir.c
index 03a3ff418..84c8866e0 100644
--- a/tests/diff/workdir.c
+++ b/tests/diff/workdir.c
@@ -67,8 +67,8 @@ void test_diff_workdir__to_index(void)
#ifdef GIT_PERF
cl_assert_equal_sz(
13 /* in root */ + 3 /* in subdir */, diff->stat_calls);
- cl_assert_equal_sz(9, diff->oid_calculations);
- cl_assert_equal_sz(2, diff->submodule_lookups);
+ cl_assert_equal_sz(5, diff->oid_calculations);
+ cl_assert_equal_sz(1, diff->submodule_lookups);
#endif
}
diff --git a/tests/status/worktree.c b/tests/status/worktree.c
index def3d60f0..f51c61864 100644
--- a/tests/status/worktree.c
+++ b/tests/status/worktree.c
@@ -578,7 +578,11 @@ void test_status_worktree__line_endings_dont_count_as_changes_with_autocrlf(void
cl_git_pass(git_status_file(&status, repo, "current_file"));
- cl_assert_equal_i(GIT_STATUS_CURRENT, status);
+ /* stat data on file should no longer match stat cache, even though
+ * file diff will be empty because of line-ending conversion - matches
+ * the Git command-line behavior here.
+ */
+ cl_assert_equal_i(GIT_STATUS_WT_MODIFIED, status);
}
void test_status_worktree__line_endings_dont_count_as_changes_with_autocrlf_issue_1397(void)