From 057686a6b97b9406876f3af60702aa5688bba8a0 Mon Sep 17 00:00:00 2001 From: Sven van Heugten Date: Fri, 6 Mar 2026 17:01:00 +0100 Subject: [PATCH] Fix changes sometimes disappearing entirely ```git-check-assertions run test/mechanicaldiff.bats assert_success git checkout HEAD~ bin run test/mechanicaldiff.bats assert_failure assert_output --partial "not ok 9 keeps matching change with an extra removed line" assert_output --partial "not ok 10 keeps matching change with an extra added line" ``` --- bin/mechanicaldiff | 10 ++++--- default.nix | 2 ++ flake.nix | 1 + test/mechanicaldiff.bats | 65 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 4 deletions(-) diff --git a/bin/mechanicaldiff b/bin/mechanicaldiff index 32d3b96..8ac824d 100755 --- a/bin/mechanicaldiff +++ b/bin/mechanicaldiff @@ -40,11 +40,13 @@ def filter_change_block( if trim_blank_ends(transformed_removed) == trim_blank_ends(added_lines): return change_lines - if len(removed_lines) != len(added_lines): - return [] - kept_lines = [] - for removed, added in zip(removed_lines, added_lines): + max_len = max(len(removed_lines), len(added_lines)) + for idx in range(max_len): + removed = removed_lines[idx] if idx < len(removed_lines) else None + added = added_lines[idx] if idx < len(added_lines) else None + if removed is None: + break if re.sub(search, replace, removed) == added: kept_lines.append(f"-{removed}") kept_lines.append(f"+{added}") diff --git a/default.nix b/default.nix index 6f0526a..54cf645 100644 --- a/default.nix +++ b/default.nix @@ -7,6 +7,7 @@ python3Packages, shellcheck-minimal, shfmt, + patchutils_0_4_2, }: let @@ -42,6 +43,7 @@ stdenv.mkDerivation { python3Packages.flake8 shellcheck-minimal shfmt + patchutils_0_4_2 ]; checkPhase = '' diff --git a/flake.nix b/flake.nix index 0593261..387b65c 100644 --- a/flake.nix +++ b/flake.nix @@ -26,6 +26,7 @@ pkgs.python3Packages.flake8 pkgs.shellcheck pkgs.shfmt + pkgs.patchutils_0_4_2 ]; }; } diff --git a/test/mechanicaldiff.bats b/test/mechanicaldiff.bats index ea2c5f9..0f6358c 100755 --- a/test/mechanicaldiff.bats +++ b/test/mechanicaldiff.bats @@ -162,6 +162,71 @@ setup() { assert_output "$(cat "$BATS_TEST_TMPDIR/diff")" } +@test "keeps matching change with an extra removed line" { + cat >"$BATS_TEST_TMPDIR/old" <<-'EOF' + foo + bar + baz + EOF + cat >"$BATS_TEST_TMPDIR/new" <<-'EOF' + foo_changed + baz + EOF + + git diff --no-index "$BATS_TEST_TMPDIR/old" "$BATS_TEST_TMPDIR/new" \ + >"$BATS_TEST_TMPDIR/diff" || true + + cat >"$BATS_TEST_TMPDIR/new_kept" <<-'EOF' + foo_changed + bar + baz + EOF + git diff --no-index "$BATS_TEST_TMPDIR/old" \ + "$BATS_TEST_TMPDIR/new_kept" \ + >"$BATS_TEST_TMPDIR/diff_expected" || true + + run mechanicaldiff foo foo_changed <"$BATS_TEST_TMPDIR/diff" + assert_failure + expected="$(sed \ + -e 's/new_kept/new/g' \ + -e '/^index /d' \ + "$BATS_TEST_TMPDIR/diff_expected")" + output_normalized="$(printf '%s\n' "$output" | recountdiff | sed -e '/^index /d')" + assert_equal "$expected" "$output_normalized" +} + +@test "keeps matching change with an extra added line" { + cat >"$BATS_TEST_TMPDIR/old" <<-'EOF' + foo + baz + EOF + cat >"$BATS_TEST_TMPDIR/new" <<-'EOF' + foo_changed + bar + baz + EOF + + git diff --no-index "$BATS_TEST_TMPDIR/old" "$BATS_TEST_TMPDIR/new" \ + >"$BATS_TEST_TMPDIR/diff" || true + + cat >"$BATS_TEST_TMPDIR/new_kept" <<-'EOF' + foo_changed + baz + EOF + git diff --no-index "$BATS_TEST_TMPDIR/old" \ + "$BATS_TEST_TMPDIR/new_kept" \ + >"$BATS_TEST_TMPDIR/diff_expected" || true + + run mechanicaldiff foo foo_changed <"$BATS_TEST_TMPDIR/diff" + assert_failure + expected="$(sed \ + -e 's/new_kept/new/g' \ + -e '/^index /d' \ + "$BATS_TEST_TMPDIR/diff_expected")" + output_normalized="$(printf '%s\n' "$output" | recountdiff | sed -e '/^index /d')" + assert_equal "$expected" "$output_normalized" +} + @test "ignores leading and trailing blank lines for comparison" { cat >"$BATS_TEST_TMPDIR/old" <<-'EOF'