Look for all 3 git conflict markers in check_merge_conflict.

This commit is contained in:
Anton I. Sipos 2025-12-19 13:16:42 -08:00
parent 5dcc56558c
commit 19609da705
No known key found for this signature in database
GPG key ID: 327E0FD283F0D9AD
2 changed files with 42 additions and 18 deletions

View file

@ -10,10 +10,9 @@ from pre_commit_hooks.util import cmd_output
CONFLICT_PATTERNS = [ CONFLICT_PATTERNS = [
b'<<<<<<< ', b'<<<<<<< ',
b'=======', b'=======',
b'=======\r\n',
b'=======\n',
b'>>>>>>> ', b'>>>>>>> ',
] ]
N = len(CONFLICT_PATTERNS)
def is_in_merge() -> bool: def is_in_merge() -> bool:
@ -40,15 +39,21 @@ def main(argv: Sequence[str] | None = None) -> int:
retcode = 0 retcode = 0
for filename in args.filenames: for filename in args.filenames:
with open(filename, 'rb') as inputfile: with open(filename, 'rb') as inputfile:
expected_conflict_pattern_index = 0
for i, line in enumerate(inputfile, start=1): for i, line in enumerate(inputfile, start=1):
for pattern in CONFLICT_PATTERNS: # Look for conflict patterns in order
if line.startswith(pattern): if line.startswith(
CONFLICT_PATTERNS[expected_conflict_pattern_index]
):
expected_conflict_pattern_index += 1
if expected_conflict_pattern_index == N:
print( print(
f'{filename}:{i}: Merge conflict string ' f"{filename}:{i}: Merge conflict string "
f'{pattern.strip().decode()!r} found', f"{CONFLICT_PATTERNS[-1].strip().decode()!r} "
f"found",
) )
retcode = 1 retcode = 1
break
return retcode return retcode

View file

@ -105,18 +105,29 @@ def test_merge_conflicts_git(capsys):
assert main(['f1']) == 1 assert main(['f1']) == 1
out, _ = capsys.readouterr() out, _ = capsys.readouterr()
assert out == ( assert out == (
"f1:1: Merge conflict string '<<<<<<<' found\n"
"f1:3: Merge conflict string '=======' found\n"
"f1:5: Merge conflict string '>>>>>>>' found\n" "f1:5: Merge conflict string '>>>>>>>' found\n"
) )
@pytest.mark.parametrize( @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) def test_merge_conflicts_with_rst(
assert main(['f2']) == 1 contents, expected_retcode, repository_pending_merge
):
repository_pending_merge.join('f2.rst').write_binary(contents)
assert main(['f2.rst']) == expected_retcode
@pytest.mark.parametrize( @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') f.write_binary(b'problem\n=======\n')
assert main([str(f.realpath())]) == 0 assert main([str(f.realpath())]) == 0
@pytest.mark.parametrize(
def test_care_when_assumed_merge(tmpdir): '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 = tmpdir.join('README.md')
f.write_binary(b'problem\n=======\n') f.write_binary(contents)
assert main([str(f.realpath()), '--assume-in-merge']) == 1 assert main([str(f.realpath()), '--assume-in-merge']) == expected_retcode
def test_worktree_merge_conflicts(f1_is_a_conflict_file, tmpdir, capsys): def test_worktree_merge_conflicts(f1_is_a_conflict_file, tmpdir, capsys):