From 87cf96094a6b5ccc4a9a1d92b9958ad0869a5c90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sun, 8 Sep 2024 09:05:44 +0200 Subject: [PATCH 1/2] diff: report copies and renames as changes in run_diff_cmd() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The diff machinery has two ways to detect changes to set the exit code: Just comparing hashes and comparing blob contents. The latter is needed if certain changes have to be ignored, e.g. with --ignore-space-change or --ignore-matching-lines. It's enabled by the diff_options flag diff_from_contents. The slower mode has never considered copies and renames to be changes, which is inconsistent with the quicker one. Fix it. Even if we ignore the file contents (because it's empty or contains only ignored lines), there's still the meta data change of adding or changing a filename, so we need to report it in the exit code. d7b97b7185 (diff: let external diffs report that changes are uninteresting, 2024-06-09) set diff_from_contents if external diff programs are allowed. This is the default e.g. for git diff, and so that change exposed the inconsistency much more widely. Reported-by: Jorge Luis Martinez Gomez Signed-off-by: René Scharfe Signed-off-by: Junio C Hamano --- diff.c | 3 +++ t/t4017-diff-retval.sh | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/diff.c b/diff.c index ebb7538e04..53e41a8d6c 100644 --- a/diff.c +++ b/diff.c @@ -4587,6 +4587,9 @@ static void run_diff_cmd(const struct external_diff *pgm, builtin_diff(name, other ? other : name, one, two, xfrm_msg, must_show_header, o, complete_rewrite); + if (p->status == DIFF_STATUS_COPIED || + p->status == DIFF_STATUS_RENAMED) + o->found_changes = 1; } else { fprintf(o->file, "* Unmerged path %s\n", name); o->found_changes = 1; diff --git a/t/t4017-diff-retval.sh b/t/t4017-diff-retval.sh index f439f469bd..9a4f578614 100755 --- a/t/t4017-diff-retval.sh +++ b/t/t4017-diff-retval.sh @@ -143,4 +143,20 @@ test_expect_success 'option errors are not confused by --exit-code' ' grep '^usage:' err ' +for option in --exit-code --quiet +do + test_expect_success "git diff $option returns 1 for copied file" " + git reset --hard && + cp a copy && + git add copy && + test_expect_code 1 git diff $option --cached --find-copies-harder + " + + test_expect_success "git diff $option returns 1 for renamed file" " + git reset --hard && + git mv a renamed && + test_expect_code 1 git diff $option --cached + " +done + test_done From 11591850ddd5e65d3d0aab22c0a7131b1eb1d6f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sun, 8 Sep 2024 09:08:35 +0200 Subject: [PATCH 2/2] diff: report dirty submodules as changes in builtin_diff() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The diff machinery has two ways to detect changes to set the exit code: Just comparing hashes and comparing blob contents. The latter is needed if certain changes have to be ignored, e.g. with --ignore-space-change or --ignore-matching-lines. It's enabled by the diff_options flag diff_from_contents. The slower mode as never considered submodules (and subrepos) as changes with --submodule=diff or --submodule=log, which is inconsistent with --submodule=short (the default). Fix it. d7b97b7185 (diff: let external diffs report that changes are uninteresting, 2024-06-09) set diff_from_contents if external diff programs are allowed. This is the default e.g. for git diff, and so that change exposed the inconsistency much more widely. Reported-by: David Hull Signed-off-by: René Scharfe Signed-off-by: Junio C Hamano --- diff.c | 2 ++ t/t4017-diff-retval.sh | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/diff.c b/diff.c index 53e41a8d6c..a83409944b 100644 --- a/diff.c +++ b/diff.c @@ -3565,6 +3565,7 @@ static void builtin_diff(const char *name_a, show_submodule_diff_summary(o, one->path ? one->path : two->path, &one->oid, &two->oid, two->dirty_submodule); + o->found_changes = 1; return; } else if (o->submodule_format == DIFF_SUBMODULE_INLINE_DIFF && (!one->mode || S_ISGITLINK(one->mode)) && @@ -3573,6 +3574,7 @@ static void builtin_diff(const char *name_a, show_submodule_inline_diff(o, one->path ? one->path : two->path, &one->oid, &two->oid, two->dirty_submodule); + o->found_changes = 1; return; } diff --git a/t/t4017-diff-retval.sh b/t/t4017-diff-retval.sh index 9a4f578614..d644310e22 100755 --- a/t/t4017-diff-retval.sh +++ b/t/t4017-diff-retval.sh @@ -159,4 +159,25 @@ do " done +test_expect_success 'setup dirty subrepo' ' + git reset --hard && + test_create_repo subrepo && + test_commit -C subrepo subrepo-file && + test_tick && + git add subrepo && + git commit -m subrepo && + test_commit -C subrepo another-subrepo-file +' + +for option in --exit-code --quiet +do + for submodule_format in diff log short + do + opts="$option --submodule=$submodule_format" && + test_expect_success "git diff $opts returns 1 for dirty subrepo" " + test_expect_code 1 git diff $opts + " + done +done + test_done