diff --git a/pre_commit/staged_files_only.py b/pre_commit/staged_files_only.py index 7db17b83..4d233924 100644 --- a/pre_commit/staged_files_only.py +++ b/pre_commit/staged_files_only.py @@ -11,6 +11,16 @@ from pre_commit.util import CalledProcessError logger = logging.getLogger('pre_commit') +def _git_apply(cmd_runner, patch): + args = ('apply', '--whitespace=nowarn', patch) + try: + cmd_runner.run(('git',) + args, encoding=None) + except CalledProcessError: + # Retry with autocrlf=false -- see #570 + cmd = ('git', '-c', 'core.autocrlf=false') + args + cmd_runner.run(cmd, encoding=None) + + @contextlib.contextmanager def staged_files_only(cmd_runner): """Clear any unstaged changes from the git working directory inside this @@ -46,10 +56,7 @@ def staged_files_only(cmd_runner): finally: # Try to apply the patch we saved try: - cmd_runner.run( - ('git', 'apply', '--whitespace=nowarn', patch_filename), - encoding=None, - ) + _git_apply(cmd_runner, patch_filename) except CalledProcessError: logger.warning( 'Stashed changes conflicted with hook auto-fixes... ' @@ -59,10 +66,7 @@ def staged_files_only(cmd_runner): # by hooks. # Roll back the changes made by hooks. cmd_runner.run(('git', 'checkout', '--', '.')) - cmd_runner.run( - ('git', 'apply', patch_filename, '--whitespace=nowarn'), - encoding=None, - ) + _git_apply(cmd_runner, patch_filename) logger.info('Restored changes from {}.'.format(patch_filename)) else: # There weren't any staged files so we don't need to do anything diff --git a/tests/staged_files_only_test.py b/tests/staged_files_only_test.py index ecaee814..78926d05 100644 --- a/tests/staged_files_only_test.py +++ b/tests/staged_files_only_test.py @@ -354,3 +354,17 @@ def test_crlf(in_git_dir, cmd_runner, crlf_before, crlf_after, autocrlf): def test_whitespace_errors(in_git_dir, cmd_runner): cmd_output('git', 'config', '--local', 'apply.whitespace', 'error') test_crlf(in_git_dir, cmd_runner, True, True, 'true') + + +def test_autocrlf_commited_crlf(in_git_dir, cmd_runner): + """Regression test for #570""" + cmd_output('git', 'config', '--local', 'core.autocrlf', 'false') + _write(b'1\r\n2\r\n') + cmd_output('git', 'add', 'foo') + cmd_output('git', 'commit', '-m', 'Check in crlf') + + cmd_output('git', 'config', '--local', 'core.autocrlf', 'true') + _write(b'1\r\n2\r\n\r\n\r\n\r\n') + + with staged_files_only(cmd_runner): + assert_no_diff()