diff --git a/pre_commit/commands/init_templatedir.py b/pre_commit/commands/init_templatedir.py
index 6e8df18..74a32f2 100644
--- a/pre_commit/commands/init_templatedir.py
+++ b/pre_commit/commands/init_templatedir.py
@@ -8,10 +8,10 @@ from pre_commit.util import cmd_output
 logger = logging.getLogger('pre_commit')
 
 
-def init_templatedir(config_file, store, directory, hook_type):
+def init_templatedir(config_file, store, directory, hook_types):
     install(
-        config_file, store, overwrite=True, hook_type=hook_type,
-        skip_on_missing_config=True, git_dir=directory,
+        config_file, store, hook_types=hook_types,
+        overwrite=True, skip_on_missing_config=True, git_dir=directory,
     )
     try:
         _, out, _ = cmd_output('git', 'config', 'init.templateDir')
diff --git a/pre_commit/commands/install_uninstall.py b/pre_commit/commands/install_uninstall.py
index 9b2c3b8..0fda627 100644
--- a/pre_commit/commands/install_uninstall.py
+++ b/pre_commit/commands/install_uninstall.py
@@ -67,19 +67,10 @@ def shebang():
     return '#!/usr/bin/env {}'.format(py)
 
 
-def install(
-        config_file, store,
-        overwrite=False, hooks=False, hook_type='pre-commit',
-        skip_on_missing_config=False, git_dir=None,
+def _install_hook_script(
+        config_file, hook_type,
+        overwrite=False, skip_on_missing_config=False, git_dir=None,
 ):
-    """Install the pre-commit hooks."""
-    if cmd_output('git', 'config', 'core.hooksPath', retcode=None)[1].strip():
-        logger.error(
-            'Cowardly refusing to install hooks with `core.hooksPath` set.\n'
-            'hint: `git config --unset-all core.hooksPath`',
-        )
-        return 1
-
     hook_path, legacy_path = _hook_paths(hook_type, git_dir=git_dir)
 
     mkdirp(os.path.dirname(hook_path))
@@ -120,7 +111,27 @@ def install(
 
     output.write_line('pre-commit installed at {}'.format(hook_path))
 
-    # If they requested we install all of the hooks, do so.
+
+def install(
+        config_file, store, hook_types,
+        overwrite=False, hooks=False,
+        skip_on_missing_config=False, git_dir=None,
+):
+    if cmd_output('git', 'config', 'core.hooksPath', retcode=None)[1].strip():
+        logger.error(
+            'Cowardly refusing to install hooks with `core.hooksPath` set.\n'
+            'hint: `git config --unset-all core.hooksPath`',
+        )
+        return 1
+
+    for hook_type in hook_types:
+        _install_hook_script(
+            config_file, hook_type,
+            overwrite=overwrite,
+            skip_on_missing_config=skip_on_missing_config,
+            git_dir=git_dir,
+        )
+
     if hooks:
         install_hooks(config_file, store)
 
@@ -131,13 +142,12 @@ def install_hooks(config_file, store):
     install_hook_envs(all_hooks(load_config(config_file), store), store)
 
 
-def uninstall(hook_type='pre-commit'):
-    """Uninstall the pre-commit hooks."""
+def _uninstall_hook_script(hook_type):  # type: (str) -> None
     hook_path, legacy_path = _hook_paths(hook_type)
 
     # If our file doesn't exist or it isn't ours, gtfo.
     if not os.path.exists(hook_path) or not is_our_script(hook_path):
-        return 0
+        return
 
     os.remove(hook_path)
     output.write_line('{} uninstalled'.format(hook_type))
@@ -146,4 +156,8 @@ def uninstall(hook_type='pre-commit'):
         os.rename(legacy_path, hook_path)
         output.write_line('Restored previous hooks to {}'.format(hook_path))
 
+
+def uninstall(hook_types):
+    for hook_type in hook_types:
+        _uninstall_hook_script(hook_type)
     return 0
diff --git a/pre_commit/main.py b/pre_commit/main.py
index dbfbecf..8d2d630 100644
--- a/pre_commit/main.py
+++ b/pre_commit/main.py
@@ -60,7 +60,8 @@ def _add_hook_type_option(parser):
         '-t', '--hook-type', choices=(
             'pre-commit', 'pre-push', 'prepare-commit-msg', 'commit-msg',
         ),
-        default='pre-commit',
+        action='append',
+        dest='hook_types',
     )
 
 
@@ -120,6 +121,11 @@ def _adjust_args_and_chdir(args):
         args.files = [os.path.relpath(filename) for filename in args.files]
     if args.command == 'try-repo' and os.path.exists(args.repo):
         args.repo = os.path.relpath(args.repo)
+    if (
+            args.command in {'install', 'uninstall', 'init-templatedir'} and
+            not args.hook_types
+    ):
+        args.hook_types = ['pre-commit']
 
 
 def main(argv=None):
@@ -299,14 +305,14 @@ def main(argv=None):
         elif args.command == 'install':
             return install(
                 args.config, store,
+                hook_types=args.hook_types,
                 overwrite=args.overwrite, hooks=args.install_hooks,
-                hook_type=args.hook_type,
                 skip_on_missing_config=args.allow_missing_config,
             )
         elif args.command == 'init-templatedir':
             return init_templatedir(
-                args.config, store,
-                args.directory, hook_type=args.hook_type,
+                args.config, store, args.directory,
+                hook_types=args.hook_types,
             )
         elif args.command == 'install-hooks':
             return install_hooks(args.config, store)
@@ -319,7 +325,7 @@ def main(argv=None):
         elif args.command == 'try-repo':
             return try_repo(args)
         elif args.command == 'uninstall':
-            return uninstall(hook_type=args.hook_type)
+            return uninstall(hook_types=args.hook_types)
         else:
             raise NotImplementedError(
                 'Command {} not implemented.'.format(args.command),

Install many hooks types by one command
Now I should run next in every new repo:
```console
$ pre-commit install-hooks
$ pre-commit install --install-hooks --hook-type commit-msg
```

Maybe can be more pretty have something like 
```console
$ pre-commit install --install-hooks --all
# OR
$ pre-commit install --install-hooks --hook-type pre-commit,commit-msg
```
diff --git a/tests/commands/init_templatedir_test.py b/tests/commands/init_templatedir_test.py
index b94de99..1bb9695 100644
--- a/tests/commands/init_templatedir_test.py
+++ b/tests/commands/init_templatedir_test.py
@@ -16,7 +16,7 @@ from testing.util import git_commit
 
 def test_init_templatedir(tmpdir, tempdir_factory, store, cap_out):
     target = str(tmpdir.join('tmpl'))
-    init_templatedir(C.CONFIG_FILE, store, target, hook_type='pre-commit')
+    init_templatedir(C.CONFIG_FILE, store, target, hook_types=['pre-commit'])
     lines = cap_out.get().splitlines()
     assert lines[0].startswith('pre-commit installed at ')
     assert lines[1] == (
@@ -45,7 +45,9 @@ def test_init_templatedir_already_set(tmpdir, tempdir_factory, store, cap_out):
     tmp_git_dir = git_dir(tempdir_factory)
     with cwd(tmp_git_dir):
         cmd_output('git', 'config', 'init.templateDir', target)
-        init_templatedir(C.CONFIG_FILE, store, target, hook_type='pre-commit')
+        init_templatedir(
+            C.CONFIG_FILE, store, target, hook_types=['pre-commit'],
+        )
 
     lines = cap_out.get().splitlines()
     assert len(lines) == 1
@@ -57,7 +59,9 @@ def test_init_templatedir_not_set(tmpdir, store, cap_out):
     with envcontext([('HOME', str(tmpdir))]):
         with tmpdir.join('tmpl').ensure_dir().as_cwd():
             # we have not set init.templateDir so this should produce a warning
-            init_templatedir(C.CONFIG_FILE, store, '.', hook_type='pre-commit')
+            init_templatedir(
+                C.CONFIG_FILE, store, '.', hook_types=['pre-commit'],
+            )
 
     lines = cap_out.get().splitlines()
     assert len(lines) == 3
@@ -73,7 +77,7 @@ def test_init_templatedir_expanduser(tmpdir, tempdir_factory, store, cap_out):
         cmd_output('git', 'config', 'init.templateDir', '~/templatedir')
         with mock.patch.object(os.path, 'expanduser', return_value=target):
             init_templatedir(
-                C.CONFIG_FILE, store, target, hook_type='pre-commit',
+                C.CONFIG_FILE, store, target, hook_types=['pre-commit'],
             )
 
     lines = cap_out.get().splitlines()
diff --git a/tests/commands/install_uninstall_test.py b/tests/commands/install_uninstall_test.py
index 913bf74..52f6e4e 100644
--- a/tests/commands/install_uninstall_test.py
+++ b/tests/commands/install_uninstall_test.py
@@ -67,10 +67,10 @@ def test_shebang_posix_on_path(tmpdir):
 
 
 def test_install_pre_commit(in_git_dir, store):
-    assert not install(C.CONFIG_FILE, store)
+    assert not install(C.CONFIG_FILE, store, hook_types=['pre-commit'])
     assert os.access(in_git_dir.join('.git/hooks/pre-commit').strpath, os.X_OK)
 
-    assert not install(C.CONFIG_FILE, store, hook_type='pre-push')
+    assert not install(C.CONFIG_FILE, store, hook_types=['pre-push'])
     assert os.access(in_git_dir.join('.git/hooks/pre-push').strpath, os.X_OK)
 
 
@@ -78,32 +78,41 @@ def test_install_hooks_directory_not_present(in_git_dir, store):
     # Simulate some git clients which don't make .git/hooks #234
     if in_git_dir.join('.git/hooks').exists():  # pragma: no cover (odd git)
         in_git_dir.join('.git/hooks').remove()
-    install(C.CONFIG_FILE, store)
+    install(C.CONFIG_FILE, store, hook_types=['pre-commit'])
     assert in_git_dir.join('.git/hooks/pre-commit').exists()
 
 
+def test_install_multiple_hooks_at_once(in_git_dir, store):
+    install(C.CONFIG_FILE, store, hook_types=['pre-commit', 'pre-push'])
+    assert in_git_dir.join('.git/hooks/pre-commit').exists()
+    assert in_git_dir.join('.git/hooks/pre-push').exists()
+    uninstall(hook_types=['pre-commit', 'pre-push'])
+    assert not in_git_dir.join('.git/hooks/pre-commit').exists()
+    assert not in_git_dir.join('.git/hooks/pre-push').exists()
+
+
 def test_install_refuses_core_hookspath(in_git_dir, store):
     cmd_output('git', 'config', '--local', 'core.hooksPath', 'hooks')
-    assert install(C.CONFIG_FILE, store)
+    assert install(C.CONFIG_FILE, store, hook_types=['pre-commit'])
 
 
 @xfailif_no_symlink  # pragma: windows no cover
 def test_install_hooks_dead_symlink(in_git_dir, store):
     hook = in_git_dir.join('.git/hooks').ensure_dir().join('pre-commit')
     os.symlink('/fake/baz', hook.strpath)
-    install(C.CONFIG_FILE, store)
+    install(C.CONFIG_FILE, store, hook_types=['pre-commit'])
     assert hook.exists()
 
 
 def test_uninstall_does_not_blow_up_when_not_there(in_git_dir):
-    assert uninstall() == 0
+    assert uninstall(hook_types=['pre-commit']) == 0
 
 
 def test_uninstall(in_git_dir, store):
     assert not in_git_dir.join('.git/hooks/pre-commit').exists()
-    install(C.CONFIG_FILE, store)
+    install(C.CONFIG_FILE, store, hook_types=['pre-commit'])
     assert in_git_dir.join('.git/hooks/pre-commit').exists()
-    uninstall()
+    uninstall(hook_types=['pre-commit'])
     assert not in_git_dir.join('.git/hooks/pre-commit').exists()
 
 
@@ -142,7 +151,7 @@ NORMAL_PRE_COMMIT_RUN = re.compile(
 def test_install_pre_commit_and_run(tempdir_factory, store):
     path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
     with cwd(path):
-        assert install(C.CONFIG_FILE, store) == 0
+        assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0
 
         ret, output = _get_commit_output(tempdir_factory)
         assert ret == 0
@@ -152,9 +161,9 @@ def test_install_pre_commit_and_run(tempdir_factory, store):
 def test_install_pre_commit_and_run_custom_path(tempdir_factory, store):
     path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
     with cwd(path):
-        cmd_output('git', 'mv', C.CONFIG_FILE, 'custom-config.yaml')
+        cmd_output('git', 'mv', C.CONFIG_FILE, 'custom.yaml')
         git_commit(cwd=path)
-        assert install('custom-config.yaml', store) == 0
+        assert install('custom.yaml', store, hook_types=['pre-commit']) == 0
 
         ret, output = _get_commit_output(tempdir_factory)
         assert ret == 0
@@ -169,7 +178,7 @@ def test_install_in_submodule_and_run(tempdir_factory, store):
 
     sub_pth = os.path.join(parent_path, 'sub')
     with cwd(sub_pth):
-        assert install(C.CONFIG_FILE, store) == 0
+        assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0
         ret, output = _get_commit_output(tempdir_factory)
         assert ret == 0
         assert NORMAL_PRE_COMMIT_RUN.match(output)
@@ -182,7 +191,7 @@ def test_install_in_worktree_and_run(tempdir_factory, store):
     cmd_output('git', '-C', src_path, 'worktree', 'add', path, '-b', 'master')
 
     with cwd(path):
-        assert install(C.CONFIG_FILE, store) == 0
+        assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0
         ret, output = _get_commit_output(tempdir_factory)
         assert ret == 0
         assert NORMAL_PRE_COMMIT_RUN.match(output)
@@ -199,7 +208,7 @@ def test_commit_am(tempdir_factory, store):
         with io.open('unstaged', 'w') as foo_file:
             foo_file.write('Oh hai')
 
-        assert install(C.CONFIG_FILE, store) == 0
+        assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0
 
         ret, output = _get_commit_output(tempdir_factory)
         assert ret == 0
@@ -208,7 +217,7 @@ def test_commit_am(tempdir_factory, store):
 def test_unicode_merge_commit_message(tempdir_factory, store):
     path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
     with cwd(path):
-        assert install(C.CONFIG_FILE, store) == 0
+        assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0
         cmd_output('git', 'checkout', 'master', '-b', 'foo')
         git_commit('-n', cwd=path)
         cmd_output('git', 'checkout', 'master')
@@ -225,8 +234,8 @@ def test_unicode_merge_commit_message(tempdir_factory, store):
 def test_install_idempotent(tempdir_factory, store):
     path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
     with cwd(path):
-        assert install(C.CONFIG_FILE, store) == 0
-        assert install(C.CONFIG_FILE, store) == 0
+        assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0
+        assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0
 
         ret, output = _get_commit_output(tempdir_factory)
         assert ret == 0
@@ -252,7 +261,7 @@ def test_environment_not_sourced(tempdir_factory, store):
     with cwd(path):
         # Patch the executable to simulate rming virtualenv
         with mock.patch.object(sys, 'executable', '/does-not-exist'):
-            assert install(C.CONFIG_FILE, store) == 0
+            assert not install(C.CONFIG_FILE, store, hook_types=['pre-commit'])
 
         # Use a specific homedir to ignore --user installs
         homedir = tempdir_factory.get()
@@ -290,7 +299,7 @@ FAILING_PRE_COMMIT_RUN = re.compile(
 def test_failing_hooks_returns_nonzero(tempdir_factory, store):
     path = make_consuming_repo(tempdir_factory, 'failing_hook_repo')
     with cwd(path):
-        assert install(C.CONFIG_FILE, store) == 0
+        assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0
 
         ret, output = _get_commit_output(tempdir_factory)
         assert ret == 1
@@ -323,7 +332,7 @@ def test_install_existing_hooks_no_overwrite(tempdir_factory, store):
         assert EXISTING_COMMIT_RUN.match(output)
 
         # Now install pre-commit (no-overwrite)
-        assert install(C.CONFIG_FILE, store) == 0
+        assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0
 
         # We should run both the legacy and pre-commit hooks
         ret, output = _get_commit_output(tempdir_factory)
@@ -336,10 +345,10 @@ def test_legacy_overwriting_legacy_hook(tempdir_factory, store):
     path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
     with cwd(path):
         _write_legacy_hook(path)
-        assert install(C.CONFIG_FILE, store) == 0
+        assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0
         _write_legacy_hook(path)
         # this previously crashed on windows.  See #1010
-        assert install(C.CONFIG_FILE, store) == 0
+        assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0
 
 
 def test_install_existing_hook_no_overwrite_idempotent(tempdir_factory, store):
@@ -348,8 +357,8 @@ def test_install_existing_hook_no_overwrite_idempotent(tempdir_factory, store):
         _write_legacy_hook(path)
 
         # Install twice
-        assert install(C.CONFIG_FILE, store) == 0
-        assert install(C.CONFIG_FILE, store) == 0
+        assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0
+        assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0
 
         # We should run both the legacy and pre-commit hooks
         ret, output = _get_commit_output(tempdir_factory)
@@ -374,7 +383,7 @@ def test_failing_existing_hook_returns_1(tempdir_factory, store):
             f.write('#!/usr/bin/env bash\necho "fail!"\nexit 1\n')
         make_executable(f.name)
 
-        assert install(C.CONFIG_FILE, store) == 0
+        assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0
 
         # We should get a failure from the legacy hook
         ret, output = _get_commit_output(tempdir_factory)
@@ -385,7 +394,9 @@ def test_failing_existing_hook_returns_1(tempdir_factory, store):
 def test_install_overwrite_no_existing_hooks(tempdir_factory, store):
     path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
     with cwd(path):
-        assert install(C.CONFIG_FILE, store, overwrite=True) == 0
+        assert not install(
+            C.CONFIG_FILE, store, hook_types=['pre-commit'], overwrite=True,
+        )
 
         ret, output = _get_commit_output(tempdir_factory)
         assert ret == 0
@@ -396,7 +407,9 @@ def test_install_overwrite(tempdir_factory, store):
     path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
     with cwd(path):
         _write_legacy_hook(path)
-        assert install(C.CONFIG_FILE, store, overwrite=True) == 0
+        assert not install(
+            C.CONFIG_FILE, store, hook_types=['pre-commit'], overwrite=True,
+        )
 
         ret, output = _get_commit_output(tempdir_factory)
         assert ret == 0
@@ -409,8 +422,8 @@ def test_uninstall_restores_legacy_hooks(tempdir_factory, store):
         _write_legacy_hook(path)
 
         # Now install and uninstall pre-commit
-        assert install(C.CONFIG_FILE, store) == 0
-        assert uninstall() == 0
+        assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0
+        assert uninstall(hook_types=['pre-commit']) == 0
 
         # Make sure we installed the "old" hook correctly
         ret, output = _get_commit_output(tempdir_factory, touch_file='baz')
@@ -433,7 +446,7 @@ def test_replace_old_commit_script(tempdir_factory, store):
         make_executable(f.name)
 
         # Install normally
-        assert install(C.CONFIG_FILE, store) == 0
+        assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0
 
         ret, output = _get_commit_output(tempdir_factory)
         assert ret == 0
@@ -445,7 +458,7 @@ def test_uninstall_doesnt_remove_not_our_hooks(in_git_dir):
     pre_commit.write('#!/usr/bin/env bash\necho 1\n')
     make_executable(pre_commit.strpath)
 
-    assert uninstall() == 0
+    assert uninstall(hook_types=['pre-commit']) == 0
 
     assert pre_commit.exists()
 
@@ -461,7 +474,7 @@ PRE_INSTALLED = re.compile(
 def test_installs_hooks_with_hooks_True(tempdir_factory, store):
     path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
     with cwd(path):
-        install(C.CONFIG_FILE, store, hooks=True)
+        install(C.CONFIG_FILE, store, hook_types=['pre-commit'], hooks=True)
         ret, output = _get_commit_output(
             tempdir_factory, pre_commit_home=store.directory,
         )
@@ -473,7 +486,7 @@ def test_installs_hooks_with_hooks_True(tempdir_factory, store):
 def test_install_hooks_command(tempdir_factory, store):
     path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
     with cwd(path):
-        install(C.CONFIG_FILE, store)
+        install(C.CONFIG_FILE, store, hook_types=['pre-commit'])
         install_hooks(C.CONFIG_FILE, store)
         ret, output = _get_commit_output(
             tempdir_factory, pre_commit_home=store.directory,
@@ -486,7 +499,7 @@ def test_install_hooks_command(tempdir_factory, store):
 def test_installed_from_venv(tempdir_factory, store):
     path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
     with cwd(path):
-        install(C.CONFIG_FILE, store)
+        install(C.CONFIG_FILE, store, hook_types=['pre-commit'])
         # No environment so pre-commit is not on the path when running!
         # Should still pick up the python from when we installed
         ret, output = _get_commit_output(
@@ -525,7 +538,7 @@ def test_pre_push_integration_failing(tempdir_factory, store):
     path = tempdir_factory.get()
     cmd_output('git', 'clone', upstream, path)
     with cwd(path):
-        install(C.CONFIG_FILE, store, hook_type='pre-push')
+        install(C.CONFIG_FILE, store, hook_types=['pre-push'])
         # commit succeeds because pre-commit is only installed for pre-push
         assert _get_commit_output(tempdir_factory)[0] == 0
         assert _get_commit_output(tempdir_factory, touch_file='zzz')[0] == 0
@@ -543,7 +556,7 @@ def test_pre_push_integration_accepted(tempdir_factory, store):
     path = tempdir_factory.get()
     cmd_output('git', 'clone', upstream, path)
     with cwd(path):
-        install(C.CONFIG_FILE, store, hook_type='pre-push')
+        install(C.CONFIG_FILE, store, hook_types=['pre-push'])
         assert _get_commit_output(tempdir_factory)[0] == 0
 
         retc, output = _get_push_output(tempdir_factory)
@@ -563,7 +576,7 @@ def test_pre_push_force_push_without_fetch(tempdir_factory, store):
         assert _get_push_output(tempdir_factory)[0] == 0
 
     with cwd(path2):
-        install(C.CONFIG_FILE, store, hook_type='pre-push')
+        install(C.CONFIG_FILE, store, hook_types=['pre-push'])
         assert _get_commit_output(tempdir_factory, msg='force!')[0] == 0
 
         retc, output = _get_push_output(tempdir_factory, opts=('--force',))
@@ -578,7 +591,7 @@ def test_pre_push_new_upstream(tempdir_factory, store):
     path = tempdir_factory.get()
     cmd_output('git', 'clone', upstream, path)
     with cwd(path):
-        install(C.CONFIG_FILE, store, hook_type='pre-push')
+        install(C.CONFIG_FILE, store, hook_types=['pre-push'])
         assert _get_commit_output(tempdir_factory)[0] == 0
 
         cmd_output('git', 'remote', 'rename', 'origin', 'upstream')
@@ -594,7 +607,7 @@ def test_pre_push_integration_empty_push(tempdir_factory, store):
     path = tempdir_factory.get()
     cmd_output('git', 'clone', upstream, path)
     with cwd(path):
-        install(C.CONFIG_FILE, store, hook_type='pre-push')
+        install(C.CONFIG_FILE, store, hook_types=['pre-push'])
         _get_push_output(tempdir_factory)
         retc, output = _get_push_output(tempdir_factory)
         assert output == 'Everything up-to-date\n'
@@ -617,7 +630,7 @@ def test_pre_push_legacy(tempdir_factory, store):
             )
         make_executable(f.name)
 
-        install(C.CONFIG_FILE, store, hook_type='pre-push')
+        install(C.CONFIG_FILE, store, hook_types=['pre-push'])
         assert _get_commit_output(tempdir_factory)[0] == 0
 
         retc, output = _get_push_output(tempdir_factory)
@@ -631,7 +644,7 @@ def test_pre_push_legacy(tempdir_factory, store):
 def test_commit_msg_integration_failing(
         commit_msg_repo, tempdir_factory, store,
 ):
-    install(C.CONFIG_FILE, store, hook_type='commit-msg')
+    install(C.CONFIG_FILE, store, hook_types=['commit-msg'])
     retc, out = _get_commit_output(tempdir_factory)
     assert retc == 1
     assert out.startswith('Must have "Signed off by:"...')
@@ -641,7 +654,7 @@ def test_commit_msg_integration_failing(
 def test_commit_msg_integration_passing(
         commit_msg_repo, tempdir_factory, store,
 ):
-    install(C.CONFIG_FILE, store, hook_type='commit-msg')
+    install(C.CONFIG_FILE, store, hook_types=['commit-msg'])
     msg = 'Hi\nSigned off by: me, lol'
     retc, out = _get_commit_output(tempdir_factory, msg=msg)
     assert retc == 0
@@ -662,7 +675,7 @@ def test_commit_msg_legacy(commit_msg_repo, tempdir_factory, store):
         )
     make_executable(hook_path)
 
-    install(C.CONFIG_FILE, store, hook_type='commit-msg')
+    install(C.CONFIG_FILE, store, hook_types=['commit-msg'])
 
     msg = 'Hi\nSigned off by: asottile'
     retc, out = _get_commit_output(tempdir_factory, msg=msg)
@@ -675,7 +688,7 @@ def test_commit_msg_legacy(commit_msg_repo, tempdir_factory, store):
 def test_prepare_commit_msg_integration_failing(
         failing_prepare_commit_msg_repo, tempdir_factory, store,
 ):
-    install(C.CONFIG_FILE, store, hook_type='prepare-commit-msg')
+    install(C.CONFIG_FILE, store, hook_types=['prepare-commit-msg'])
     retc, out = _get_commit_output(tempdir_factory)
     assert retc == 1
     assert out.startswith('Add "Signed off by:"...')
@@ -685,7 +698,7 @@ def test_prepare_commit_msg_integration_failing(
 def test_prepare_commit_msg_integration_passing(
         prepare_commit_msg_repo, tempdir_factory, store,
 ):
-    install(C.CONFIG_FILE, store, hook_type='prepare-commit-msg')
+    install(C.CONFIG_FILE, store, hook_types=['prepare-commit-msg'])
     msg = 'Hi'
     retc, out = _get_commit_output(tempdir_factory, msg=msg)
     assert retc == 0
@@ -715,7 +728,7 @@ def test_prepare_commit_msg_legacy(
         )
     make_executable(hook_path)
 
-    install(C.CONFIG_FILE, store, hook_type='prepare-commit-msg')
+    install(C.CONFIG_FILE, store, hook_types=['prepare-commit-msg'])
 
     msg = 'Hi'
     retc, out = _get_commit_output(tempdir_factory, msg=msg)
@@ -735,7 +748,8 @@ def test_install_disallow_missing_config(tempdir_factory, store):
     with cwd(path):
         remove_config_from_repo(path)
         ret = install(
-            C.CONFIG_FILE, store, overwrite=True, skip_on_missing_config=False,
+            C.CONFIG_FILE, store, hook_types=['pre-commit'],
+            overwrite=True, skip_on_missing_config=False,
         )
         assert ret == 0
 
@@ -748,7 +762,8 @@ def test_install_allow_missing_config(tempdir_factory, store):
     with cwd(path):
         remove_config_from_repo(path)
         ret = install(
-            C.CONFIG_FILE, store, overwrite=True, skip_on_missing_config=True,
+            C.CONFIG_FILE, store, hook_types=['pre-commit'],
+            overwrite=True, skip_on_missing_config=True,
         )
         assert ret == 0
 
@@ -766,7 +781,8 @@ def test_install_temporarily_allow_mising_config(tempdir_factory, store):
     with cwd(path):
         remove_config_from_repo(path)
         ret = install(
-            C.CONFIG_FILE, store, overwrite=True, skip_on_missing_config=False,
+            C.CONFIG_FILE, store, hook_types=['pre-commit'],
+            overwrite=True, skip_on_missing_config=False,
         )
         assert ret == 0
 
diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py
index 49ce008..f6d5c93 100644
--- a/tests/commands/run_test.py
+++ b/tests/commands/run_test.py
@@ -525,7 +525,7 @@ def test_stdout_write_bug_py26(repo_with_failing_hook, store, tempdir_factory):
             config['repos'][0]['hooks'][0]['args'] = ['☃']
         stage_a_file()
 
-        install(C.CONFIG_FILE, store)
+        install(C.CONFIG_FILE, store, hook_types=['pre-commit'])
 
         # Have to use subprocess because pytest monkeypatches sys.stdout
         _, stdout, _ = git_commit(
@@ -555,7 +555,7 @@ def test_lots_of_files(store, tempdir_factory):
             open(filename, 'w').close()
 
         cmd_output('git', 'add', '.')
-        install(C.CONFIG_FILE, store)
+        install(C.CONFIG_FILE, store, hook_types=['pre-commit'])
 
         git_commit(
             fn=cmd_output_mocked_pre_commit_home,

pip install -e .[dev]
parse_log_pytest
requirements.txt
3.9
requirements-dev.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
aspy.yaml==1.3.0
cfgv==3.4.0
coverage==7.8.0
distlib==0.3.9
exceptiongroup==1.2.2
filelock==3.18.0
identify==2.6.9
importlib_metadata==8.6.1
iniconfig==2.1.0
mock==5.2.0
nodeenv==1.9.1
packaging==24.2
platformdirs==4.3.7
pluggy==1.5.0
-e git+https://github.com/pre-commit/pre-commit.git@96c35185f07925ff10a04e3d161c96baf39eaa28#egg=pre_commit
pytest==8.3.5
pytest-env==1.1.5
PyYAML==6.0.2
six==1.17.0
toml==0.10.2
tomli==2.2.1
virtualenv==20.29.3
zipp==3.21.0

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
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_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
      - cfgv==3.4.0
      - coverage==7.8.0
      - distlib==0.3.9
      - exceptiongroup==1.2.2
      - filelock==3.18.0
      - identify==2.6.9
      - importlib-metadata==8.6.1
      - iniconfig==2.1.0
      - mock==5.2.0
      - nodeenv==1.9.1
      - packaging==24.2
      - platformdirs==4.3.7
      - pluggy==1.5.0
      - pytest==8.3.5
      - pytest-env==1.1.5
      - pyyaml==6.0.2
      - six==1.17.0
      - toml==0.10.2
      - tomli==2.2.1
      - virtualenv==20.29.3
      - zipp==3.21.0
prefix: /opt/conda/envs/pre-commit

tests/commands/init_templatedir_test.py::test_init_templatedir tests/commands/init_templatedir_test.py::test_init_templatedir_already_set tests/commands/init_templatedir_test.py::test_init_templatedir_not_set tests/commands/init_templatedir_test.py::test_init_templatedir_expanduser 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_multiple_hooks_at_once tests/commands/install_uninstall_test.py::test_install_refuses_core_hookspath 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_install_pre_commit_and_run tests/commands/install_uninstall_test.py::test_install_pre_commit_and_run_custom_path tests/commands/install_uninstall_test.py::test_install_in_worktree_and_run 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_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_legacy_overwriting_legacy_hook 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_uninstall_restores_legacy_hooks tests/commands/install_uninstall_test.py::test_replace_old_commit_script tests/commands/install_uninstall_test.py::test_uninstall_doesnt_remove_not_our_hooks 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_pre_push_integration_failing tests/commands/install_uninstall_test.py::test_pre_push_integration_accepted tests/commands/install_uninstall_test.py::test_pre_push_force_push_without_fetch tests/commands/install_uninstall_test.py::test_pre_push_new_upstream tests/commands/install_uninstall_test.py::test_pre_push_integration_empty_push tests/commands/install_uninstall_test.py::test_pre_push_legacy tests/commands/install_uninstall_test.py::test_commit_msg_integration_failing tests/commands/install_uninstall_test.py::test_commit_msg_integration_passing tests/commands/install_uninstall_test.py::test_commit_msg_legacy tests/commands/install_uninstall_test.py::test_prepare_commit_msg_integration_failing tests/commands/install_uninstall_test.py::test_prepare_commit_msg_integration_passing tests/commands/install_uninstall_test.py::test_prepare_commit_msg_legacy tests/commands/install_uninstall_test.py::test_install_disallow_missing_config tests/commands/install_uninstall_test.py::test_install_allow_missing_config tests/commands/install_uninstall_test.py::test_install_temporarily_allow_mising_config tests/commands/run_test.py::test_stdout_write_bug_py26 tests/commands/run_test.py::test_lots_of_files
tests/commands/install_uninstall_test.py::test_install_in_submodule_and_run tests/commands/install_uninstall_test.py::test_environment_not_sourced
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_shebang_windows tests/commands/install_uninstall_test.py::test_shebang_posix_not_on_path tests/commands/install_uninstall_test.py::test_shebang_posix_on_path tests/commands/run_test.py::test_run[options3-outputs3-1-True] tests/commands/run_test.py::test_run[options4-outputs4-1-True] tests/commands/run_test.py::test_run[options7-outputs7-0-False] tests/commands/run_test.py::test_origin_source_error_msg_error[master-] tests/commands/run_test.py::test_origin_source_error_msg_error[-master] tests/commands/run_test.py::test_origin_source_both_ok tests/commands/run_test.py::test_has_unmerged_paths tests/commands/run_test.py::test_merge_conflict tests/commands/run_test.py::test_merge_conflict_modified tests/commands/run_test.py::test_compute_cols[hooks0-True-80] tests/commands/run_test.py::test_compute_cols[hooks1-False-81] tests/commands/run_test.py::test_compute_cols[hooks2-True-85] tests/commands/run_test.py::test_compute_cols[hooks3-False-82] tests/commands/run_test.py::test_get_skips[environ0-expected_output0] tests/commands/run_test.py::test_get_skips[environ1-expected_output1] tests/commands/run_test.py::test_get_skips[environ2-expected_output2] tests/commands/run_test.py::test_get_skips[environ3-expected_output3] tests/commands/run_test.py::test_get_skips[environ4-expected_output4] tests/commands/run_test.py::test_get_skips[environ5-expected_output5] tests/commands/run_test.py::test_get_skips[environ6-expected_output6] tests/commands/run_test.py::test_skip_hook tests/commands/run_test.py::test_skip_aliased_hook tests/commands/run_test.py::test_hook_id_not_in_non_verbose_output tests/commands/run_test.py::test_hook_id_in_verbose_output tests/commands/run_test.py::test_non_ascii_hook_id tests/commands/run_test.py::test_stages tests/commands/run_test.py::test_pcre_deprecation_warning tests/commands/run_test.py::test_meta_hook_passes tests/commands/run_test.py::test_error_with_unstaged_config tests/commands/run_test.py::test_files_running_subdir tests/commands/run_test.py::test_classifier_removes_dne tests/commands/run_test.py::test_include_exclude_base_case tests/commands/run_test.py::test_matches_broken_symlink tests/commands/run_test.py::test_include_exclude_total_match tests/commands/run_test.py::test_include_exclude_does_search_instead_of_match tests/commands/run_test.py::test_include_exclude_exclude_removes_files tests/commands/run_test.py::test_args_hook_only
pre_commit/commands/install_uninstall.py pre_commit/main.py pre_commit/commands/init_templatedir.py
pre_commit/commands/install_uninstall.py pre_commit/main.py pre_commit/commands/init_templatedir.py