We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Warn when mismatching cygwin git/python
See #352 and #353 for how this can manifest itself


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pre_commit/git.py`
Content:
```
1 from __future__ import unicode_literals
2 
3 import functools
4 import logging
5 import os.path
6 import re
7 
8 from pre_commit.errors import FatalError
9 from pre_commit.util import CalledProcessError
10 from pre_commit.util import cmd_output
11 from pre_commit.util import memoize_by_cwd
12 
13 
14 logger = logging.getLogger('pre_commit')
15 
16 
17 def get_root():
18     try:
19         return cmd_output('git', 'rev-parse', '--show-toplevel')[1].strip()
20     except CalledProcessError:
21         raise FatalError(
22             'git failed. Is it installed, and are you in a Git repository '
23             'directory?'
24         )
25 
26 
27 def get_git_dir(git_root):
28     return os.path.normpath(os.path.join(
29         git_root,
30         cmd_output('git', 'rev-parse', '--git-dir', cwd=git_root)[1].strip(),
31     ))
32 
33 
34 def is_in_merge_conflict():
35     git_dir = get_git_dir('.')
36     return (
37         os.path.exists(os.path.join(git_dir, 'MERGE_MSG')) and
38         os.path.exists(os.path.join(git_dir, 'MERGE_HEAD'))
39     )
40 
41 
42 def parse_merge_msg_for_conflicts(merge_msg):
43     # Conflicted files start with tabs
44     return [
45         line.lstrip('#').strip()
46         for line in merge_msg.splitlines()
47         # '#\t' for git 2.4.1
48         if line.startswith(('\t', '#\t'))
49     ]
50 
51 
52 @memoize_by_cwd
53 def get_conflicted_files():
54     logger.info('Checking merge-conflict files only.')
55     # Need to get the conflicted files from the MERGE_MSG because they could
56     # have resolved the conflict by choosing one side or the other
57     merge_msg = open(os.path.join(get_git_dir('.'), 'MERGE_MSG')).read()
58     merge_conflict_filenames = parse_merge_msg_for_conflicts(merge_msg)
59 
60     # This will get the rest of the changes made after the merge.
61     # If they resolved the merge conflict by choosing a mesh of both sides
62     # this will also include the conflicted files
63     tree_hash = cmd_output('git', 'write-tree')[1].strip()
64     merge_diff_filenames = cmd_output(
65         'git', 'diff', '-m', tree_hash, 'HEAD', 'MERGE_HEAD', '--name-only',
66     )[1].splitlines()
67     return set(merge_conflict_filenames) | set(merge_diff_filenames)
68 
69 
70 @memoize_by_cwd
71 def get_staged_files():
72     return cmd_output(
73         'git', 'diff', '--staged', '--name-only',
74         # Everything except for D
75         '--diff-filter=ACMRTUXB'
76     )[1].splitlines()
77 
78 
79 @memoize_by_cwd
80 def get_all_files():
81     return cmd_output('git', 'ls-files')[1].splitlines()
82 
83 
84 def get_files_matching(all_file_list_strategy):
85     @functools.wraps(all_file_list_strategy)
86     @memoize_by_cwd
87     def wrapper(include_expr, exclude_expr):
88         include_regex = re.compile(include_expr)
89         exclude_regex = re.compile(exclude_expr)
90         return set(
91             filename
92             for filename in all_file_list_strategy()
93             if (
94                 include_regex.search(filename) and
95                 not exclude_regex.search(filename) and
96                 os.path.lexists(filename)
97             )
98         )
99     return wrapper
100 
101 
102 get_staged_files_matching = get_files_matching(get_staged_files)
103 get_all_files_matching = get_files_matching(get_all_files)
104 get_conflicted_files_matching = get_files_matching(get_conflicted_files)
105
```

Path: `pre_commit/main.py`
Content:
```
1 from __future__ import unicode_literals
2 
3 import argparse
4 import os
5 import sys
6 
7 import pkg_resources
8 
9 from pre_commit import color
10 from pre_commit import five
11 from pre_commit import git
12 from pre_commit.commands.autoupdate import autoupdate
13 from pre_commit.commands.clean import clean
14 from pre_commit.commands.install_uninstall import install
15 from pre_commit.commands.install_uninstall import uninstall
16 from pre_commit.commands.run import run
17 from pre_commit.error_handler import error_handler
18 from pre_commit.logging_handler import add_logging_handler
19 from pre_commit.runner import Runner
20 
21 
22 # https://github.com/pre-commit/pre-commit/issues/217
23 # On OSX, making a virtualenv using pyvenv at . causes `virtualenv` and `pip`
24 # to install packages to the wrong place.  We don't want anything to deal with
25 # pyvenv
26 os.environ.pop('__PYVENV_LAUNCHER__', None)
27 
28 
29 def _add_color_option(parser):
30     parser.add_argument(
31         '--color', default='auto', type=color.use_color,
32         metavar='{' + ','.join(color.COLOR_CHOICES) + '}',
33         help='Whether to use color in output.  Defaults to `%(default)s`.',
34     )
35 
36 
37 def main(argv=None):
38     argv = argv if argv is not None else sys.argv[1:]
39     argv = [five.to_text(arg) for arg in argv]
40     parser = argparse.ArgumentParser()
41 
42     # http://stackoverflow.com/a/8521644/812183
43     parser.add_argument(
44         '-V', '--version',
45         action='version',
46         version='%(prog)s {}'.format(
47             pkg_resources.get_distribution('pre-commit').version
48         )
49     )
50 
51     subparsers = parser.add_subparsers(dest='command')
52 
53     install_parser = subparsers.add_parser(
54         'install', help='Install the pre-commit script.',
55     )
56     _add_color_option(install_parser)
57     install_parser.add_argument(
58         '-f', '--overwrite', action='store_true',
59         help='Overwrite existing hooks / remove migration mode.',
60     )
61     install_parser.add_argument(
62         '--install-hooks', action='store_true',
63         help=(
64             'Whether to install hook environments for all environments '
65             'in the config file.'
66         ),
67     )
68     install_parser.add_argument(
69         '-t', '--hook-type', choices=('pre-commit', 'pre-push'),
70         default='pre-commit',
71     )
72 
73     uninstall_parser = subparsers.add_parser(
74         'uninstall', help='Uninstall the pre-commit script.',
75     )
76     _add_color_option(uninstall_parser)
77     uninstall_parser.add_argument(
78         '-t', '--hook-type', choices=('pre-commit', 'pre-push'),
79         default='pre-commit',
80     )
81 
82     clean_parser = subparsers.add_parser(
83         'clean', help='Clean out pre-commit files.',
84     )
85     _add_color_option(clean_parser)
86 
87     autoupdate_parser = subparsers.add_parser(
88         'autoupdate',
89         help="Auto-update pre-commit config to the latest repos' versions.",
90     )
91     _add_color_option(autoupdate_parser)
92 
93     run_parser = subparsers.add_parser('run', help='Run hooks.')
94     _add_color_option(run_parser)
95     run_parser.add_argument('hook', nargs='?', help='A single hook-id to run')
96     run_parser.add_argument(
97         '--no-stash', default=False, action='store_true',
98         help='Use this option to prevent auto stashing of unstaged files.',
99     )
100     run_parser.add_argument(
101         '--verbose', '-v', action='store_true', default=False,
102     )
103     run_parser.add_argument(
104         '--origin', '-o',
105         help="The origin branch's commit_id when using `git push`.",
106     )
107     run_parser.add_argument(
108         '--source', '-s',
109         help="The remote branch's commit_id when using `git push`.",
110     )
111     run_parser.add_argument(
112         '--allow-unstaged-config', default=False, action='store_true',
113         help=(
114             'Allow an unstaged config to be present.  Note that this will '
115             'be stashed before parsing unless --no-stash is specified.'
116         ),
117     )
118     run_parser.add_argument(
119         '--hook-stage', choices=('commit', 'push'), default='commit',
120         help='The stage during which the hook is fired e.g. commit or push.',
121     )
122     run_mutex_group = run_parser.add_mutually_exclusive_group(required=False)
123     run_mutex_group.add_argument(
124         '--all-files', '-a', action='store_true', default=False,
125         help='Run on all the files in the repo.  Implies --no-stash.',
126     )
127     run_mutex_group.add_argument(
128         '--files', nargs='*', default=[],
129         help='Specific filenames to run hooks on.',
130     )
131 
132     help = subparsers.add_parser(
133         'help', help='Show help for a specific command.',
134     )
135     help.add_argument('help_cmd', nargs='?', help='Command to show help for.')
136 
137     # Argparse doesn't really provide a way to use a `default` subparser
138     if len(argv) == 0:
139         argv = ['run']
140     args = parser.parse_args(argv)
141     if args.command == 'run':
142         args.files = [
143             os.path.relpath(os.path.abspath(filename), git.get_root())
144             for filename in args.files
145         ]
146 
147     if args.command == 'help':
148         if args.help_cmd:
149             parser.parse_args([args.help_cmd, '--help'])
150         else:
151             parser.parse_args(['--help'])
152 
153     with error_handler():
154         add_logging_handler(args.color)
155         runner = Runner.create()
156 
157         if args.command == 'install':
158             return install(
159                 runner, overwrite=args.overwrite, hooks=args.install_hooks,
160                 hook_type=args.hook_type,
161             )
162         elif args.command == 'uninstall':
163             return uninstall(runner, hook_type=args.hook_type)
164         elif args.command == 'clean':
165             return clean(runner)
166         elif args.command == 'autoupdate':
167             return autoupdate(runner)
168         elif args.command == 'run':
169             return run(runner, args)
170         else:
171             raise NotImplementedError(
172                 'Command {} not implemented.'.format(args.command)
173             )
174 
175         raise AssertionError(
176             'Command {} failed to exit with a returncode'.format(args.command)
177         )
178 
179 
180 if __name__ == '__main__':
181     exit(main())
182
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pre_commit/git.py b/pre_commit/git.py
--- a/pre_commit/git.py
+++ b/pre_commit/git.py
@@ -4,6 +4,7 @@
 import logging
 import os.path
 import re
+import sys
 
 from pre_commit.errors import FatalError
 from pre_commit.util import CalledProcessError
@@ -102,3 +103,26 @@
 get_staged_files_matching = get_files_matching(get_staged_files)
 get_all_files_matching = get_files_matching(get_all_files)
 get_conflicted_files_matching = get_files_matching(get_conflicted_files)
+
+
+def check_for_cygwin_mismatch():
+    """See https://github.com/pre-commit/pre-commit/issues/354"""
+    if sys.platform in ('cygwin', 'win32'):  # pragma: no cover (windows)
+        is_cygwin_python = sys.platform == 'cygwin'
+        toplevel = cmd_output('git', 'rev-parse', '--show-toplevel')[1]
+        is_cygwin_git = toplevel.startswith('/')
+
+        if is_cygwin_python ^ is_cygwin_git:
+            exe_type = {True: '(cygwin)', False: '(windows)'}
+            logger.warn(
+                'pre-commit has detected a mix of cygwin python / git\n'
+                'This combination is not supported, it is likely you will '
+                'receive an error later in the program.\n'
+                'Make sure to use cygwin git+python while using cygwin\n'
+                'These can be installed through the cygwin installer.\n'
+                ' - python {}\n'
+                ' - git {}\n'.format(
+                    exe_type[is_cygwin_python],
+                    exe_type[is_cygwin_git],
+                )
+            )
diff --git a/pre_commit/main.py b/pre_commit/main.py
--- a/pre_commit/main.py
+++ b/pre_commit/main.py
@@ -152,6 +152,7 @@
 
     with error_handler():
         add_logging_handler(args.color)
+        git.check_for_cygwin_mismatch()
         runner = Runner.create()
 
         if args.command == 'install':

{"golden_diff": "diff --git a/pre_commit/git.py b/pre_commit/git.py\n--- a/pre_commit/git.py\n+++ b/pre_commit/git.py\n@@ -4,6 +4,7 @@\n import logging\n import os.path\n import re\n+import sys\n \n from pre_commit.errors import FatalError\n from pre_commit.util import CalledProcessError\n@@ -102,3 +103,26 @@\n get_staged_files_matching = get_files_matching(get_staged_files)\n get_all_files_matching = get_files_matching(get_all_files)\n get_conflicted_files_matching = get_files_matching(get_conflicted_files)\n+\n+\n+def check_for_cygwin_mismatch():\n+    \"\"\"See https://github.com/pre-commit/pre-commit/issues/354\"\"\"\n+    if sys.platform in ('cygwin', 'win32'):  # pragma: no cover (windows)\n+        is_cygwin_python = sys.platform == 'cygwin'\n+        toplevel = cmd_output('git', 'rev-parse', '--show-toplevel')[1]\n+        is_cygwin_git = toplevel.startswith('/')\n+\n+        if is_cygwin_python ^ is_cygwin_git:\n+            exe_type = {True: '(cygwin)', False: '(windows)'}\n+            logger.warn(\n+                'pre-commit has detected a mix of cygwin python / git\\n'\n+                'This combination is not supported, it is likely you will '\n+                'receive an error later in the program.\\n'\n+                'Make sure to use cygwin git+python while using cygwin\\n'\n+                'These can be installed through the cygwin installer.\\n'\n+                ' - python {}\\n'\n+                ' - git {}\\n'.format(\n+                    exe_type[is_cygwin_python],\n+                    exe_type[is_cygwin_git],\n+                )\n+            )\ndiff --git a/pre_commit/main.py b/pre_commit/main.py\n--- a/pre_commit/main.py\n+++ b/pre_commit/main.py\n@@ -152,6 +152,7 @@\n \n     with error_handler():\n         add_logging_handler(args.color)\n+        git.check_for_cygwin_mismatch()\n         runner = Runner.create()\n \n         if args.command == 'install':\n", "issue": "Warn when mismatching cygwin git/python\nSee #352 and #353 for how this can manifest itself\n\n", "before_files": [{"content": "from __future__ import unicode_literals\n\nimport functools\nimport logging\nimport os.path\nimport re\n\nfrom pre_commit.errors import FatalError\nfrom pre_commit.util import CalledProcessError\nfrom pre_commit.util import cmd_output\nfrom pre_commit.util import memoize_by_cwd\n\n\nlogger = logging.getLogger('pre_commit')\n\n\ndef get_root():\n    try:\n        return cmd_output('git', 'rev-parse', '--show-toplevel')[1].strip()\n    except CalledProcessError:\n        raise FatalError(\n            'git failed. Is it installed, and are you in a Git repository '\n            'directory?'\n        )\n\n\ndef get_git_dir(git_root):\n    return os.path.normpath(os.path.join(\n        git_root,\n        cmd_output('git', 'rev-parse', '--git-dir', cwd=git_root)[1].strip(),\n    ))\n\n\ndef is_in_merge_conflict():\n    git_dir = get_git_dir('.')\n    return (\n        os.path.exists(os.path.join(git_dir, 'MERGE_MSG')) and\n        os.path.exists(os.path.join(git_dir, 'MERGE_HEAD'))\n    )\n\n\ndef parse_merge_msg_for_conflicts(merge_msg):\n    # Conflicted files start with tabs\n    return [\n        line.lstrip('#').strip()\n        for line in merge_msg.splitlines()\n        # '#\\t' for git 2.4.1\n        if line.startswith(('\\t', '#\\t'))\n    ]\n\n\n@memoize_by_cwd\ndef get_conflicted_files():\n    logger.info('Checking merge-conflict files only.')\n    # Need to get the conflicted files from the MERGE_MSG because they could\n    # have resolved the conflict by choosing one side or the other\n    merge_msg = open(os.path.join(get_git_dir('.'), 'MERGE_MSG')).read()\n    merge_conflict_filenames = parse_merge_msg_for_conflicts(merge_msg)\n\n    # This will get the rest of the changes made after the merge.\n    # If they resolved the merge conflict by choosing a mesh of both sides\n    # this will also include the conflicted files\n    tree_hash = cmd_output('git', 'write-tree')[1].strip()\n    merge_diff_filenames = cmd_output(\n        'git', 'diff', '-m', tree_hash, 'HEAD', 'MERGE_HEAD', '--name-only',\n    )[1].splitlines()\n    return set(merge_conflict_filenames) | set(merge_diff_filenames)\n\n\n@memoize_by_cwd\ndef get_staged_files():\n    return cmd_output(\n        'git', 'diff', '--staged', '--name-only',\n        # Everything except for D\n        '--diff-filter=ACMRTUXB'\n    )[1].splitlines()\n\n\n@memoize_by_cwd\ndef get_all_files():\n    return cmd_output('git', 'ls-files')[1].splitlines()\n\n\ndef get_files_matching(all_file_list_strategy):\n    @functools.wraps(all_file_list_strategy)\n    @memoize_by_cwd\n    def wrapper(include_expr, exclude_expr):\n        include_regex = re.compile(include_expr)\n        exclude_regex = re.compile(exclude_expr)\n        return set(\n            filename\n            for filename in all_file_list_strategy()\n            if (\n                include_regex.search(filename) and\n                not exclude_regex.search(filename) and\n                os.path.lexists(filename)\n            )\n        )\n    return wrapper\n\n\nget_staged_files_matching = get_files_matching(get_staged_files)\nget_all_files_matching = get_files_matching(get_all_files)\nget_conflicted_files_matching = get_files_matching(get_conflicted_files)\n", "path": "pre_commit/git.py"}, {"content": "from __future__ import unicode_literals\n\nimport argparse\nimport os\nimport sys\n\nimport pkg_resources\n\nfrom pre_commit import color\nfrom pre_commit import five\nfrom pre_commit import git\nfrom pre_commit.commands.autoupdate import autoupdate\nfrom pre_commit.commands.clean import clean\nfrom pre_commit.commands.install_uninstall import install\nfrom pre_commit.commands.install_uninstall import uninstall\nfrom pre_commit.commands.run import run\nfrom pre_commit.error_handler import error_handler\nfrom pre_commit.logging_handler import add_logging_handler\nfrom pre_commit.runner import Runner\n\n\n# https://github.com/pre-commit/pre-commit/issues/217\n# On OSX, making a virtualenv using pyvenv at . causes `virtualenv` and `pip`\n# to install packages to the wrong place.  We don't want anything to deal with\n# pyvenv\nos.environ.pop('__PYVENV_LAUNCHER__', None)\n\n\ndef _add_color_option(parser):\n    parser.add_argument(\n        '--color', default='auto', type=color.use_color,\n        metavar='{' + ','.join(color.COLOR_CHOICES) + '}',\n        help='Whether to use color in output.  Defaults to `%(default)s`.',\n    )\n\n\ndef main(argv=None):\n    argv = argv if argv is not None else sys.argv[1:]\n    argv = [five.to_text(arg) for arg in argv]\n    parser = argparse.ArgumentParser()\n\n    # http://stackoverflow.com/a/8521644/812183\n    parser.add_argument(\n        '-V', '--version',\n        action='version',\n        version='%(prog)s {}'.format(\n            pkg_resources.get_distribution('pre-commit').version\n        )\n    )\n\n    subparsers = parser.add_subparsers(dest='command')\n\n    install_parser = subparsers.add_parser(\n        'install', help='Install the pre-commit script.',\n    )\n    _add_color_option(install_parser)\n    install_parser.add_argument(\n        '-f', '--overwrite', action='store_true',\n        help='Overwrite existing hooks / remove migration mode.',\n    )\n    install_parser.add_argument(\n        '--install-hooks', action='store_true',\n        help=(\n            'Whether to install hook environments for all environments '\n            'in the config file.'\n        ),\n    )\n    install_parser.add_argument(\n        '-t', '--hook-type', choices=('pre-commit', 'pre-push'),\n        default='pre-commit',\n    )\n\n    uninstall_parser = subparsers.add_parser(\n        'uninstall', help='Uninstall the pre-commit script.',\n    )\n    _add_color_option(uninstall_parser)\n    uninstall_parser.add_argument(\n        '-t', '--hook-type', choices=('pre-commit', 'pre-push'),\n        default='pre-commit',\n    )\n\n    clean_parser = subparsers.add_parser(\n        'clean', help='Clean out pre-commit files.',\n    )\n    _add_color_option(clean_parser)\n\n    autoupdate_parser = subparsers.add_parser(\n        'autoupdate',\n        help=\"Auto-update pre-commit config to the latest repos' versions.\",\n    )\n    _add_color_option(autoupdate_parser)\n\n    run_parser = subparsers.add_parser('run', help='Run hooks.')\n    _add_color_option(run_parser)\n    run_parser.add_argument('hook', nargs='?', help='A single hook-id to run')\n    run_parser.add_argument(\n        '--no-stash', default=False, action='store_true',\n        help='Use this option to prevent auto stashing of unstaged files.',\n    )\n    run_parser.add_argument(\n        '--verbose', '-v', action='store_true', default=False,\n    )\n    run_parser.add_argument(\n        '--origin', '-o',\n        help=\"The origin branch's commit_id when using `git push`.\",\n    )\n    run_parser.add_argument(\n        '--source', '-s',\n        help=\"The remote branch's commit_id when using `git push`.\",\n    )\n    run_parser.add_argument(\n        '--allow-unstaged-config', default=False, action='store_true',\n        help=(\n            'Allow an unstaged config to be present.  Note that this will '\n            'be stashed before parsing unless --no-stash is specified.'\n        ),\n    )\n    run_parser.add_argument(\n        '--hook-stage', choices=('commit', 'push'), default='commit',\n        help='The stage during which the hook is fired e.g. commit or push.',\n    )\n    run_mutex_group = run_parser.add_mutually_exclusive_group(required=False)\n    run_mutex_group.add_argument(\n        '--all-files', '-a', action='store_true', default=False,\n        help='Run on all the files in the repo.  Implies --no-stash.',\n    )\n    run_mutex_group.add_argument(\n        '--files', nargs='*', default=[],\n        help='Specific filenames to run hooks on.',\n    )\n\n    help = subparsers.add_parser(\n        'help', help='Show help for a specific command.',\n    )\n    help.add_argument('help_cmd', nargs='?', help='Command to show help for.')\n\n    # Argparse doesn't really provide a way to use a `default` subparser\n    if len(argv) == 0:\n        argv = ['run']\n    args = parser.parse_args(argv)\n    if args.command == 'run':\n        args.files = [\n            os.path.relpath(os.path.abspath(filename), git.get_root())\n            for filename in args.files\n        ]\n\n    if args.command == 'help':\n        if args.help_cmd:\n            parser.parse_args([args.help_cmd, '--help'])\n        else:\n            parser.parse_args(['--help'])\n\n    with error_handler():\n        add_logging_handler(args.color)\n        runner = Runner.create()\n\n        if args.command == 'install':\n            return install(\n                runner, overwrite=args.overwrite, hooks=args.install_hooks,\n                hook_type=args.hook_type,\n            )\n        elif args.command == 'uninstall':\n            return uninstall(runner, hook_type=args.hook_type)\n        elif args.command == 'clean':\n            return clean(runner)\n        elif args.command == 'autoupdate':\n            return autoupdate(runner)\n        elif args.command == 'run':\n            return run(runner, args)\n        else:\n            raise NotImplementedError(\n                'Command {} not implemented.'.format(args.command)\n            )\n\n        raise AssertionError(\n            'Command {} failed to exit with a returncode'.format(args.command)\n        )\n\n\nif __name__ == '__main__':\n    exit(main())\n", "path": "pre_commit/main.py"}], "after_files": [{"content": "from __future__ import unicode_literals\n\nimport functools\nimport logging\nimport os.path\nimport re\nimport sys\n\nfrom pre_commit.errors import FatalError\nfrom pre_commit.util import CalledProcessError\nfrom pre_commit.util import cmd_output\nfrom pre_commit.util import memoize_by_cwd\n\n\nlogger = logging.getLogger('pre_commit')\n\n\ndef get_root():\n    try:\n        return cmd_output('git', 'rev-parse', '--show-toplevel')[1].strip()\n    except CalledProcessError:\n        raise FatalError(\n            'git failed. Is it installed, and are you in a Git repository '\n            'directory?'\n        )\n\n\ndef get_git_dir(git_root):\n    return os.path.normpath(os.path.join(\n        git_root,\n        cmd_output('git', 'rev-parse', '--git-dir', cwd=git_root)[1].strip(),\n    ))\n\n\ndef is_in_merge_conflict():\n    git_dir = get_git_dir('.')\n    return (\n        os.path.exists(os.path.join(git_dir, 'MERGE_MSG')) and\n        os.path.exists(os.path.join(git_dir, 'MERGE_HEAD'))\n    )\n\n\ndef parse_merge_msg_for_conflicts(merge_msg):\n    # Conflicted files start with tabs\n    return [\n        line.lstrip('#').strip()\n        for line in merge_msg.splitlines()\n        # '#\\t' for git 2.4.1\n        if line.startswith(('\\t', '#\\t'))\n    ]\n\n\n@memoize_by_cwd\ndef get_conflicted_files():\n    logger.info('Checking merge-conflict files only.')\n    # Need to get the conflicted files from the MERGE_MSG because they could\n    # have resolved the conflict by choosing one side or the other\n    merge_msg = open(os.path.join(get_git_dir('.'), 'MERGE_MSG')).read()\n    merge_conflict_filenames = parse_merge_msg_for_conflicts(merge_msg)\n\n    # This will get the rest of the changes made after the merge.\n    # If they resolved the merge conflict by choosing a mesh of both sides\n    # this will also include the conflicted files\n    tree_hash = cmd_output('git', 'write-tree')[1].strip()\n    merge_diff_filenames = cmd_output(\n        'git', 'diff', '-m', tree_hash, 'HEAD', 'MERGE_HEAD', '--name-only',\n    )[1].splitlines()\n    return set(merge_conflict_filenames) | set(merge_diff_filenames)\n\n\n@memoize_by_cwd\ndef get_staged_files():\n    return cmd_output(\n        'git', 'diff', '--staged', '--name-only',\n        # Everything except for D\n        '--diff-filter=ACMRTUXB'\n    )[1].splitlines()\n\n\n@memoize_by_cwd\ndef get_all_files():\n    return cmd_output('git', 'ls-files')[1].splitlines()\n\n\ndef get_files_matching(all_file_list_strategy):\n    @functools.wraps(all_file_list_strategy)\n    @memoize_by_cwd\n    def wrapper(include_expr, exclude_expr):\n        include_regex = re.compile(include_expr)\n        exclude_regex = re.compile(exclude_expr)\n        return set(\n            filename\n            for filename in all_file_list_strategy()\n            if (\n                include_regex.search(filename) and\n                not exclude_regex.search(filename) and\n                os.path.lexists(filename)\n            )\n        )\n    return wrapper\n\n\nget_staged_files_matching = get_files_matching(get_staged_files)\nget_all_files_matching = get_files_matching(get_all_files)\nget_conflicted_files_matching = get_files_matching(get_conflicted_files)\n\n\ndef check_for_cygwin_mismatch():\n    \"\"\"See https://github.com/pre-commit/pre-commit/issues/354\"\"\"\n    if sys.platform in ('cygwin', 'win32'):  # pragma: no cover (windows)\n        is_cygwin_python = sys.platform == 'cygwin'\n        toplevel = cmd_output('git', 'rev-parse', '--show-toplevel')[1]\n        is_cygwin_git = toplevel.startswith('/')\n\n        if is_cygwin_python ^ is_cygwin_git:\n            exe_type = {True: '(cygwin)', False: '(windows)'}\n            logger.warn(\n                'pre-commit has detected a mix of cygwin python / git\\n'\n                'This combination is not supported, it is likely you will '\n                'receive an error later in the program.\\n'\n                'Make sure to use cygwin git+python while using cygwin\\n'\n                'These can be installed through the cygwin installer.\\n'\n                ' - python {}\\n'\n                ' - git {}\\n'.format(\n                    exe_type[is_cygwin_python],\n                    exe_type[is_cygwin_git],\n                )\n            )\n", "path": "pre_commit/git.py"}, {"content": "from __future__ import unicode_literals\n\nimport argparse\nimport os\nimport sys\n\nimport pkg_resources\n\nfrom pre_commit import color\nfrom pre_commit import five\nfrom pre_commit import git\nfrom pre_commit.commands.autoupdate import autoupdate\nfrom pre_commit.commands.clean import clean\nfrom pre_commit.commands.install_uninstall import install\nfrom pre_commit.commands.install_uninstall import uninstall\nfrom pre_commit.commands.run import run\nfrom pre_commit.error_handler import error_handler\nfrom pre_commit.logging_handler import add_logging_handler\nfrom pre_commit.runner import Runner\n\n\n# https://github.com/pre-commit/pre-commit/issues/217\n# On OSX, making a virtualenv using pyvenv at . causes `virtualenv` and `pip`\n# to install packages to the wrong place.  We don't want anything to deal with\n# pyvenv\nos.environ.pop('__PYVENV_LAUNCHER__', None)\n\n\ndef _add_color_option(parser):\n    parser.add_argument(\n        '--color', default='auto', type=color.use_color,\n        metavar='{' + ','.join(color.COLOR_CHOICES) + '}',\n        help='Whether to use color in output.  Defaults to `%(default)s`.',\n    )\n\n\ndef main(argv=None):\n    argv = argv if argv is not None else sys.argv[1:]\n    argv = [five.to_text(arg) for arg in argv]\n    parser = argparse.ArgumentParser()\n\n    # http://stackoverflow.com/a/8521644/812183\n    parser.add_argument(\n        '-V', '--version',\n        action='version',\n        version='%(prog)s {}'.format(\n            pkg_resources.get_distribution('pre-commit').version\n        )\n    )\n\n    subparsers = parser.add_subparsers(dest='command')\n\n    install_parser = subparsers.add_parser(\n        'install', help='Install the pre-commit script.',\n    )\n    _add_color_option(install_parser)\n    install_parser.add_argument(\n        '-f', '--overwrite', action='store_true',\n        help='Overwrite existing hooks / remove migration mode.',\n    )\n    install_parser.add_argument(\n        '--install-hooks', action='store_true',\n        help=(\n            'Whether to install hook environments for all environments '\n            'in the config file.'\n        ),\n    )\n    install_parser.add_argument(\n        '-t', '--hook-type', choices=('pre-commit', 'pre-push'),\n        default='pre-commit',\n    )\n\n    uninstall_parser = subparsers.add_parser(\n        'uninstall', help='Uninstall the pre-commit script.',\n    )\n    _add_color_option(uninstall_parser)\n    uninstall_parser.add_argument(\n        '-t', '--hook-type', choices=('pre-commit', 'pre-push'),\n        default='pre-commit',\n    )\n\n    clean_parser = subparsers.add_parser(\n        'clean', help='Clean out pre-commit files.',\n    )\n    _add_color_option(clean_parser)\n\n    autoupdate_parser = subparsers.add_parser(\n        'autoupdate',\n        help=\"Auto-update pre-commit config to the latest repos' versions.\",\n    )\n    _add_color_option(autoupdate_parser)\n\n    run_parser = subparsers.add_parser('run', help='Run hooks.')\n    _add_color_option(run_parser)\n    run_parser.add_argument('hook', nargs='?', help='A single hook-id to run')\n    run_parser.add_argument(\n        '--no-stash', default=False, action='store_true',\n        help='Use this option to prevent auto stashing of unstaged files.',\n    )\n    run_parser.add_argument(\n        '--verbose', '-v', action='store_true', default=False,\n    )\n    run_parser.add_argument(\n        '--origin', '-o',\n        help=\"The origin branch's commit_id when using `git push`.\",\n    )\n    run_parser.add_argument(\n        '--source', '-s',\n        help=\"The remote branch's commit_id when using `git push`.\",\n    )\n    run_parser.add_argument(\n        '--allow-unstaged-config', default=False, action='store_true',\n        help=(\n            'Allow an unstaged config to be present.  Note that this will '\n            'be stashed before parsing unless --no-stash is specified.'\n        ),\n    )\n    run_parser.add_argument(\n        '--hook-stage', choices=('commit', 'push'), default='commit',\n        help='The stage during which the hook is fired e.g. commit or push.',\n    )\n    run_mutex_group = run_parser.add_mutually_exclusive_group(required=False)\n    run_mutex_group.add_argument(\n        '--all-files', '-a', action='store_true', default=False,\n        help='Run on all the files in the repo.  Implies --no-stash.',\n    )\n    run_mutex_group.add_argument(\n        '--files', nargs='*', default=[],\n        help='Specific filenames to run hooks on.',\n    )\n\n    help = subparsers.add_parser(\n        'help', help='Show help for a specific command.',\n    )\n    help.add_argument('help_cmd', nargs='?', help='Command to show help for.')\n\n    # Argparse doesn't really provide a way to use a `default` subparser\n    if len(argv) == 0:\n        argv = ['run']\n    args = parser.parse_args(argv)\n    if args.command == 'run':\n        args.files = [\n            os.path.relpath(os.path.abspath(filename), git.get_root())\n            for filename in args.files\n        ]\n\n    if args.command == 'help':\n        if args.help_cmd:\n            parser.parse_args([args.help_cmd, '--help'])\n        else:\n            parser.parse_args(['--help'])\n\n    with error_handler():\n        add_logging_handler(args.color)\n        git.check_for_cygwin_mismatch()\n        runner = Runner.create()\n\n        if args.command == 'install':\n            return install(\n                runner, overwrite=args.overwrite, hooks=args.install_hooks,\n                hook_type=args.hook_type,\n            )\n        elif args.command == 'uninstall':\n            return uninstall(runner, hook_type=args.hook_type)\n        elif args.command == 'clean':\n            return clean(runner)\n        elif args.command == 'autoupdate':\n            return autoupdate(runner)\n        elif args.command == 'run':\n            return run(runner, args)\n        else:\n            raise NotImplementedError(\n                'Command {} not implemented.'.format(args.command)\n            )\n\n        raise AssertionError(\n            'Command {} failed to exit with a returncode'.format(args.command)\n        )\n\n\nif __name__ == '__main__':\n    exit(main())\n", "path": "pre_commit/main.py"}]}