From 19609da70550244463cbed37cf7d02575f49fd45 Mon Sep 17 00:00:00 2001 From: "Anton I. Sipos" Date: Fri, 19 Dec 2025 13:16:42 -0800 Subject: [PATCH 1/2] Look for all 3 git conflict markers in check_merge_conflict. --- pre_commit_hooks/check_merge_conflict.py | 21 ++++++++----- tests/check_merge_conflict_test.py | 39 ++++++++++++++++++------ 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/pre_commit_hooks/check_merge_conflict.py b/pre_commit_hooks/check_merge_conflict.py index 54a083ee..e3763da3 100644 --- a/pre_commit_hooks/check_merge_conflict.py +++ b/pre_commit_hooks/check_merge_conflict.py @@ -9,11 +9,10 @@ CONFLICT_PATTERNS = [ b'<<<<<<< ', - b'======= ', - b'=======\r\n', - b'=======\n', + b'=======', b'>>>>>>> ', ] +N = len(CONFLICT_PATTERNS) def is_in_merge() -> bool: @@ -40,15 +39,21 @@ def main(argv: Sequence[str] | None = None) -> int: retcode = 0 for filename in args.filenames: with open(filename, 'rb') as inputfile: + expected_conflict_pattern_index = 0 for i, line in enumerate(inputfile, start=1): - for pattern in CONFLICT_PATTERNS: - if line.startswith(pattern): + # Look for conflict patterns in order + if line.startswith( + CONFLICT_PATTERNS[expected_conflict_pattern_index] + ): + expected_conflict_pattern_index += 1 + if expected_conflict_pattern_index == N: print( - f'{filename}:{i}: Merge conflict string ' - f'{pattern.strip().decode()!r} found', + f"{filename}:{i}: Merge conflict string " + f"{CONFLICT_PATTERNS[-1].strip().decode()!r} " + f"found", ) retcode = 1 - + break return retcode diff --git a/tests/check_merge_conflict_test.py b/tests/check_merge_conflict_test.py index 64112d79..2c9d2bab 100644 --- a/tests/check_merge_conflict_test.py +++ b/tests/check_merge_conflict_test.py @@ -105,18 +105,29 @@ def test_merge_conflicts_git(capsys): assert main(['f1']) == 1 out, _ = capsys.readouterr() assert out == ( - "f1:1: Merge conflict string '<<<<<<<' found\n" - "f1:3: Merge conflict string '=======' found\n" "f1:5: Merge conflict string '>>>>>>>' found\n" ) @pytest.mark.parametrize( - 'contents', (b'<<<<<<< HEAD\n', b'=======\n', b'>>>>>>> main\n'), + # Individual markers are not actually merge conflicts, need 3 markers + # to mark a real conflict + 'contents, expected_retcode', + ((b'<<<<<<< ', 0), + (b'=======', 0), + (b'>>>>>>> ',0), + # Real conflict marker + (b'<<<<<<< HEAD\n=======\n>>>>>>> branch\n', 1), + # Allow for the possibility of an .rst file with a ======= + # inside a conflict marker + (b'<<<<<<< HEAD\n=======\n=======\n>>>>>>> branch\n', 1), + ) ) -def test_merge_conflicts_failing(contents, repository_pending_merge): - repository_pending_merge.join('f2').write_binary(contents) - assert main(['f2']) == 1 +def test_merge_conflicts_with_rst( + contents, expected_retcode, repository_pending_merge +): + repository_pending_merge.join('f2.rst').write_binary(contents) + assert main(['f2.rst']) == expected_retcode @pytest.mark.parametrize( @@ -138,11 +149,19 @@ def test_does_not_care_when_not_in_a_merge(tmpdir): f.write_binary(b'problem\n=======\n') assert main([str(f.realpath())]) == 0 - -def test_care_when_assumed_merge(tmpdir): +@pytest.mark.parametrize( + 'contents, expected_retcode', + ( + # Not a complete conflict marker + (b'=======', 0), + # Complete conflict marker + (b'<<<<<<< HEAD\nproblem\n=======\n>>>>>>> branch\n', 1), + ) +) +def test_care_when_assumed_merge(contents, expected_retcode, tmpdir): f = tmpdir.join('README.md') - f.write_binary(b'problem\n=======\n') - assert main([str(f.realpath()), '--assume-in-merge']) == 1 + f.write_binary(contents) + assert main([str(f.realpath()), '--assume-in-merge']) == expected_retcode def test_worktree_merge_conflicts(f1_is_a_conflict_file, tmpdir, capsys): From 04bf47cb9b97a83475a47105102eb2da7f236bfb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 20 Dec 2025 05:33:34 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pre_commit_hooks/check_merge_conflict.py | 2 +- tests/check_merge_conflict_test.py | 24 +++++++++++++----------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/pre_commit_hooks/check_merge_conflict.py b/pre_commit_hooks/check_merge_conflict.py index e3763da3..287d1fb2 100644 --- a/pre_commit_hooks/check_merge_conflict.py +++ b/pre_commit_hooks/check_merge_conflict.py @@ -43,7 +43,7 @@ def main(argv: Sequence[str] | None = None) -> int: for i, line in enumerate(inputfile, start=1): # Look for conflict patterns in order if line.startswith( - CONFLICT_PATTERNS[expected_conflict_pattern_index] + CONFLICT_PATTERNS[expected_conflict_pattern_index], ): expected_conflict_pattern_index += 1 if expected_conflict_pattern_index == N: diff --git a/tests/check_merge_conflict_test.py b/tests/check_merge_conflict_test.py index 2c9d2bab..9b4141a9 100644 --- a/tests/check_merge_conflict_test.py +++ b/tests/check_merge_conflict_test.py @@ -113,18 +113,19 @@ def test_merge_conflicts_git(capsys): # Individual markers are not actually merge conflicts, need 3 markers # to mark a real conflict 'contents, expected_retcode', - ((b'<<<<<<< ', 0), - (b'=======', 0), - (b'>>>>>>> ',0), - # Real conflict marker - (b'<<<<<<< HEAD\n=======\n>>>>>>> branch\n', 1), - # Allow for the possibility of an .rst file with a ======= - # inside a conflict marker - (b'<<<<<<< HEAD\n=======\n=======\n>>>>>>> branch\n', 1), - ) + ( + (b'<<<<<<< ', 0), + (b'=======', 0), + (b'>>>>>>> ', 0), + # Real conflict marker + (b'<<<<<<< HEAD\n=======\n>>>>>>> branch\n', 1), + # Allow for the possibility of an .rst file with a ======= + # inside a conflict marker + (b'<<<<<<< HEAD\n=======\n=======\n>>>>>>> branch\n', 1), + ), ) def test_merge_conflicts_with_rst( - contents, expected_retcode, repository_pending_merge + contents, expected_retcode, repository_pending_merge, ): repository_pending_merge.join('f2.rst').write_binary(contents) assert main(['f2.rst']) == expected_retcode @@ -149,6 +150,7 @@ def test_does_not_care_when_not_in_a_merge(tmpdir): f.write_binary(b'problem\n=======\n') assert main([str(f.realpath())]) == 0 + @pytest.mark.parametrize( 'contents, expected_retcode', ( @@ -156,7 +158,7 @@ def test_does_not_care_when_not_in_a_merge(tmpdir): (b'=======', 0), # Complete conflict marker (b'<<<<<<< HEAD\nproblem\n=======\n>>>>>>> branch\n', 1), - ) + ), ) def test_care_when_assumed_merge(contents, expected_retcode, tmpdir): f = tmpdir.join('README.md')