Repository: pre-commit/pre-commit

Issue:
Unicode error: python 2 + merge conflict + non-ascii commit message
The important part of the stack:

```
  File "...python2.7/site-packages/pre_commit/commands/run.py", line 52, in get_filenames
    return getter(include_expr, exclude_expr)
  File "...python2.7/site-packages/pre_commit/util.py", line 46, in wrapper
    ret = wrapper._cache[key] = func(*args)
  File "...python2.7/site-packages/pre_commit/git.py", line 98, in wrapper
    for filename in all_file_list_strategy()
  File "...python2.7/site-packages/pre_commit/util.py", line 46, in wrapper
    ret = wrapper._cache[key] = func(*args)
  File "...python2.7/site-packages/pre_commit/git.py", line 64, in get_conflicted_files
    merge_conflict_filenames = parse_merge_msg_for_conflicts(merge_msg)
  File "...python2.7/site-packages/pre_commit/git.py", line 54, in parse_merge_msg_for_conflicts
    if line.startswith(('\t', '#\t'))
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 37: ordinal not in range(128)
```

An easy fix: https://github.com/pre-commit/pre-commit/blob/e3b14c35f782ed464e3f96b44e8509048187689f/pre_commit/git.py#L63


Discussion:

Resolving patch:
diff --git a/pre_commit/git.py b/pre_commit/git.py
--- a/pre_commit/git.py
+++ b/pre_commit/git.py
@@ -48,10 +48,10 @@ def is_in_merge_conflict():
 def parse_merge_msg_for_conflicts(merge_msg):
     # Conflicted files start with tabs
     return [
-        line.lstrip('#').strip()
+        line.lstrip(b'#').strip().decode('UTF-8')
         for line in merge_msg.splitlines()
         # '#\t' for git 2.4.1
-        if line.startswith(('\t', '#\t'))
+        if line.startswith((b'\t', b'#\t'))
     ]
 
 
@@ -60,7 +60,7 @@ def get_conflicted_files():
     logger.info('Checking merge-conflict files only.')
     # Need to get the conflicted files from the MERGE_MSG because they could
     # have resolved the conflict by choosing one side or the other
-    merge_msg = open(os.path.join(get_git_dir('.'), 'MERGE_MSG')).read()
+    merge_msg = open(os.path.join(get_git_dir('.'), 'MERGE_MSG'), 'rb').read()
     merge_conflict_filenames = parse_merge_msg_for_conflicts(merge_msg)
 
     # This will get the rest of the changes made after the merge.


Test patch:
diff --git a/tests/commands/install_uninstall_test.py b/tests/commands/install_uninstall_test.py
--- a/tests/commands/install_uninstall_test.py
+++ b/tests/commands/install_uninstall_test.py
@@ -1,3 +1,4 @@
+# -*- coding: UTF-8 -*-
 from __future__ import absolute_import
 from __future__ import unicode_literals
 
@@ -190,6 +191,18 @@ def test_commit_am(tempdir_factory):
         assert ret == 0
 
 
+def test_unicode_merge_commit_message(tempdir_factory):
+    path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
+    with cwd(path):
+        assert install(Runner(path, C.CONFIG_FILE)) == 0
+        cmd_output('git', 'checkout', 'master', '-b', 'foo')
+        cmd_output('git', 'commit', '--allow-empty', '-m', 'branch2')
+        cmd_output('git', 'checkout', 'master')
+        cmd_output('git', 'merge', 'foo', '--no-ff', '--no-commit', '-m', '☃')
+        # Used to crash
+        cmd_output('git', 'commit', '--no-edit')
+
+
 def test_install_idempotent(tempdir_factory):
     path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
     with cwd(path):
diff --git a/tests/git_test.py b/tests/git_test.py
--- a/tests/git_test.py
+++ b/tests/git_test.py
@@ -142,8 +142,8 @@ def test_get_conflicted_files_unstaged_files(in_merge_conflict):
     assert ret == {'conflict_file'}
 
 
-MERGE_MSG = "Merge branch 'foo' into bar\n\nConflicts:\n\tconflict_file\n"
-OTHER_MERGE_MSG = MERGE_MSG + '\tother_conflict_file\n'
+MERGE_MSG = b"Merge branch 'foo' into bar\n\nConflicts:\n\tconflict_file\n"
+OTHER_MERGE_MSG = MERGE_MSG + b'\tother_conflict_file\n'
 
 
 @pytest.mark.parametrize(