diff --git a/pre_commit/git.py b/pre_commit/git.py
index d4277e7..2ed0299 100644
--- 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.

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
diff --git a/tests/commands/install_uninstall_test.py b/tests/commands/install_uninstall_test.py
index cd4c685..ad8d245 100644
--- 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
index c18dcd8..ffe1c1a 100644
--- 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(

pip install -e .[dev]
parse_log_pytest
requirements.txt
numpy>=1.16.0 pandas>=1.0.0 pytest
apt-get update apt-get install -y gcc
3.9
requirements-dev.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
aspy.yaml==1.3.0
cached-property==2.0.1
coverage==7.8.0
distlib==0.3.9
exceptiongroup==1.2.2
filelock==3.18.0
flake8==7.2.0
iniconfig==2.1.0
mccabe==0.7.0
mock==5.2.0
nodeenv==1.9.1
numpy==2.0.2
packaging==24.2
pandas==2.2.3
platformdirs==4.3.7
pluggy==1.5.0
-e git+https://github.com/pre-commit/pre-commit.git@e3b14c35f782ed464e3f96b44e8509048187689f#egg=pre_commit
pycodestyle==2.13.0
pyflakes==3.3.1
pytest==8.3.5
pytest-env==1.1.5
python-dateutil==2.9.0.post0
pytz==2025.2
PyYAML==6.0.2
six==1.17.0
tomli==2.2.1
tzdata==2025.2
virtualenv==20.29.3

name: pre-commit
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - aspy-yaml==1.3.0
      - cached-property==2.0.1
      - coverage==7.8.0
      - distlib==0.3.9
      - exceptiongroup==1.2.2
      - filelock==3.18.0
      - flake8==7.2.0
      - iniconfig==2.1.0
      - mccabe==0.7.0
      - mock==5.2.0
      - nodeenv==1.9.1
      - numpy==2.0.2
      - packaging==24.2
      - pandas==2.2.3
      - platformdirs==4.3.7
      - pluggy==1.5.0
      - pycodestyle==2.13.0
      - pyflakes==3.3.1
      - pytest==8.3.5
      - pytest-env==1.1.5
      - python-dateutil==2.9.0.post0
      - pytz==2025.2
      - pyyaml==6.0.2
      - setuptools==18.4
      - six==1.17.0
      - tomli==2.2.1
      - tzdata==2025.2
      - virtualenv==20.29.3
prefix: /opt/conda/envs/pre-commit

tests/git_test.py::test_parse_merge_msg_for_conflicts[Merge
tests/commands/install_uninstall_test.py::test_install_pre_commit_and_run tests/commands/install_uninstall_test.py::test_install_in_submodule_and_run tests/commands/install_uninstall_test.py::test_install_idempotent tests/commands/install_uninstall_test.py::test_failing_hooks_returns_nonzero tests/commands/install_uninstall_test.py::test_install_existing_hooks_no_overwrite tests/commands/install_uninstall_test.py::test_install_existing_hook_no_overwrite_idempotent tests/commands/install_uninstall_test.py::test_failing_existing_hook_returns_1 tests/commands/install_uninstall_test.py::test_install_overwrite_no_existing_hooks tests/commands/install_uninstall_test.py::test_install_overwrite tests/commands/install_uninstall_test.py::test_replace_old_commit_script tests/commands/install_uninstall_test.py::test_installs_hooks_with_hooks_True tests/commands/install_uninstall_test.py::test_install_hooks_command tests/commands/install_uninstall_test.py::test_installed_from_venv
tests/commands/install_uninstall_test.py::test_is_not_script tests/commands/install_uninstall_test.py::test_is_script tests/commands/install_uninstall_test.py::test_is_previous_pre_commit tests/commands/install_uninstall_test.py::test_install_pre_commit tests/commands/install_uninstall_test.py::test_install_hooks_directory_not_present tests/commands/install_uninstall_test.py::test_install_hooks_dead_symlink tests/commands/install_uninstall_test.py::test_uninstall_does_not_blow_up_when_not_there tests/commands/install_uninstall_test.py::test_uninstall tests/commands/install_uninstall_test.py::test_commit_am tests/commands/install_uninstall_test.py::test_unicode_merge_commit_message tests/commands/install_uninstall_test.py::test_environment_not_sourced tests/commands/install_uninstall_test.py::test_uninstall_restores_legacy_hooks tests/commands/install_uninstall_test.py::test_uninstall_doesnt_remove_not_our_hooks tests/commands/install_uninstall_test.py::test_pre_push_integration_failing tests/commands/install_uninstall_test.py::test_pre_push_integration_accepted tests/commands/install_uninstall_test.py::test_pre_push_integration_empty_push tests/commands/install_uninstall_test.py::test_install_disallow_mising_config tests/commands/install_uninstall_test.py::test_install_allow_mising_config tests/commands/install_uninstall_test.py::test_install_temporarily_allow_mising_config tests/git_test.py::test_get_root_at_root tests/git_test.py::test_get_root_deeper tests/git_test.py::test_get_root_not_git_dir tests/git_test.py::test_get_staged_files_deleted tests/git_test.py::test_is_not_in_merge_conflict tests/git_test.py::test_is_in_merge_conflict tests/git_test.py::test_cherry_pick_conflict tests/git_test.py::test_get_files_matching_base tests/git_test.py::test_get_files_matching_total_match tests/git_test.py::test_does_search_instead_of_match tests/git_test.py::test_does_not_include_deleted_fileS tests/git_test.py::test_exclude_removes_files tests/git_test.py::test_get_conflicted_files tests/git_test.py::test_get_conflicted_files_unstaged_files
pre_commit/git.py
pre_commit/git.py