We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Failure to check out revision pre-commit v1.15.1
```console
$ cat .pre-commit-config.yaml 
repos:
-   repo: https://github.com/asottile/pyupgrade
    rev: v1.13.0
    hooks:
    -   id: pyupgrade
$ pre-commit install-hooks
[INFO] Initializing environment for https://github.com/asottile/pyupgrade.
An unexpected error has occurred: CalledProcessError: Command: ('/usr/bin/git', 'checkout', 'v1.13.0')
Return code: 1
Expected return code: 0
Output: (none)
Errors: 
    error: pathspec 'v1.13.0' did not match any file(s) known to git.
    

Check the log at /code/.cache/pre-commit/pre-commit.log
lyftsvc@b780c05acb2e:/code/places$ cat ~/.cacp^C
lyftsvc@b780c05acb2e:/code/places$ cat /code/.cache/pre-commit/pre-commit.log 
An unexpected error has occurred: CalledProcessError: Command: ('/usr/bin/git', 'checkout', 'v1.13.0')
Return code: 1
Expected return code: 0
Output: (none)
Errors: 
    error: pathspec 'v1.13.0' did not match any file(s) known to git.
    

Traceback (most recent call last):
  File "/venv/lib/python3.6/site-packages/pre_commit/store.py", line 172, in clone_strategy
    self._shallow_clone(ref, _git_cmd)
  File "/venv/lib/python3.6/site-packages/pre_commit/store.py", line 149, in _shallow_clone
    git_cmd('-c', git_config, 'fetch', 'origin', ref, '--depth=1')
  File "/venv/lib/python3.6/site-packages/pre_commit/store.py", line 166, in _git_cmd
    cmd_output('git', *args, cwd=directory, env=env)
  File "/venv/lib/python3.6/site-packages/pre_commit/util.py", line 153, in cmd_output
    returncode, cmd, retcode, output=(stdout, stderr),
pre_commit.util.CalledProcessError: Command: ('/usr/bin/git', '-c', 'protocol.version=2', 'fetch', 'origin', 'v1.13.0', '--depth=1')
Return code: 128
Expected return code: 0
Output: (none)
Errors: 
    fatal: unknown value for config 'protocol.version': 2
    


During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/venv/lib/python3.6/site-packages/pre_commit/error_handler.py", line 46, in error_handler
    yield
  File "/venv/lib/python3.6/site-packages/pre_commit/main.py", line 274, in main
    return install_hooks(args.config, store)
  File "/venv/lib/python3.6/site-packages/pre_commit/commands/install_uninstall.py", line 129, in install_hooks
    install_hook_envs(all_hooks(load_config(config_file), store), store)
  File "/venv/lib/python3.6/site-packages/pre_commit/repository.py", line 221, in all_hooks
    for repo in root_config['repos']
  File "/venv/lib/python3.6/site-packages/pre_commit/repository.py", line 222, in <genexpr>
    for hook in _repository_hooks(repo, store, root_config)
  File "/venv/lib/python3.6/site-packages/pre_commit/repository.py", line 197, in _repository_hooks
    return _cloned_repository_hooks(repo_config, store, root_config)
  File "/venv/lib/python3.6/site-packages/pre_commit/repository.py", line 166, in _cloned_repository_hooks
    manifest_path = os.path.join(store.clone(repo, rev), C.MANIFEST_FILE)
  File "/venv/lib/python3.6/site-packages/pre_commit/store.py", line 176, in clone
    return self._new_repo(repo, ref, deps, clone_strategy)
  File "/venv/lib/python3.6/site-packages/pre_commit/store.py", line 128, in _new_repo
    make_strategy(directory)
  File "/venv/lib/python3.6/site-packages/pre_commit/store.py", line 174, in clone_strategy
    self._complete_clone(ref, _git_cmd)
  File "/venv/lib/python3.6/site-packages/pre_commit/store.py", line 142, in _complete_clone
    git_cmd('checkout', ref)
  File "/venv/lib/python3.6/site-packages/pre_commit/store.py", line 166, in _git_cmd
    cmd_output('git', *args, cwd=directory, env=env)
  File "/venv/lib/python3.6/site-packages/pre_commit/util.py", line 153, in cmd_output
    returncode, cmd, retcode, output=(stdout, stderr),
pre_commit.util.CalledProcessError: Command: ('/usr/bin/git', 'checkout', 'v1.13.0')
Return code: 1
Expected return code: 0
Output: (none)
Errors: 
    error: pathspec 'v1.13.0' did not match any file(s) known to git.
```

Perhaps related to the new clone strategy

--- 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/store.py`
Content:
```
1 from __future__ import unicode_literals
2 
3 import contextlib
4 import io
5 import logging
6 import os.path
7 import sqlite3
8 import tempfile
9 
10 import pre_commit.constants as C
11 from pre_commit import file_lock
12 from pre_commit import git
13 from pre_commit.util import CalledProcessError
14 from pre_commit.util import clean_path_on_failure
15 from pre_commit.util import cmd_output
16 from pre_commit.util import resource_text
17 from pre_commit.util import rmtree
18 
19 
20 logger = logging.getLogger('pre_commit')
21 
22 
23 def _get_default_directory():
24     """Returns the default directory for the Store.  This is intentionally
25     underscored to indicate that `Store.get_default_directory` is the intended
26     way to get this information.  This is also done so
27     `Store.get_default_directory` can be mocked in tests and
28     `_get_default_directory` can be tested.
29     """
30     return os.environ.get('PRE_COMMIT_HOME') or os.path.join(
31         os.environ.get('XDG_CACHE_HOME') or os.path.expanduser('~/.cache'),
32         'pre-commit',
33     )
34 
35 
36 class Store(object):
37     get_default_directory = staticmethod(_get_default_directory)
38 
39     def __init__(self, directory=None):
40         self.directory = directory or Store.get_default_directory()
41         self.db_path = os.path.join(self.directory, 'db.db')
42 
43         if not os.path.exists(self.directory):
44             os.makedirs(self.directory)
45             with io.open(os.path.join(self.directory, 'README'), 'w') as f:
46                 f.write(
47                     'This directory is maintained by the pre-commit project.\n'
48                     'Learn more: https://github.com/pre-commit/pre-commit\n',
49                 )
50 
51         if os.path.exists(self.db_path):
52             return
53         with self.exclusive_lock():
54             # Another process may have already completed this work
55             if os.path.exists(self.db_path):  # pragma: no cover (race)
56                 return
57             # To avoid a race where someone ^Cs between db creation and
58             # execution of the CREATE TABLE statement
59             fd, tmpfile = tempfile.mkstemp(dir=self.directory)
60             # We'll be managing this file ourselves
61             os.close(fd)
62             with self.connect(db_path=tmpfile) as db:
63                 db.executescript(
64                     'CREATE TABLE repos ('
65                     '    repo TEXT NOT NULL,'
66                     '    ref TEXT NOT NULL,'
67                     '    path TEXT NOT NULL,'
68                     '    PRIMARY KEY (repo, ref)'
69                     ');',
70                 )
71                 self._create_config_table_if_not_exists(db)
72 
73             # Atomic file move
74             os.rename(tmpfile, self.db_path)
75 
76     @contextlib.contextmanager
77     def exclusive_lock(self):
78         def blocked_cb():  # pragma: no cover (tests are single-process)
79             logger.info('Locking pre-commit directory')
80 
81         with file_lock.lock(os.path.join(self.directory, '.lock'), blocked_cb):
82             yield
83 
84     @contextlib.contextmanager
85     def connect(self, db_path=None):
86         db_path = db_path or self.db_path
87         # sqlite doesn't close its fd with its contextmanager >.<
88         # contextlib.closing fixes this.
89         # See: https://stackoverflow.com/a/28032829/812183
90         with contextlib.closing(sqlite3.connect(db_path)) as db:
91             # this creates a transaction
92             with db:
93                 yield db
94 
95     @classmethod
96     def db_repo_name(cls, repo, deps):
97         if deps:
98             return '{}:{}'.format(repo, ','.join(sorted(deps)))
99         else:
100             return repo
101 
102     def _new_repo(self, repo, ref, deps, make_strategy):
103         repo = self.db_repo_name(repo, deps)
104 
105         def _get_result():
106             # Check if we already exist
107             with self.connect() as db:
108                 result = db.execute(
109                     'SELECT path FROM repos WHERE repo = ? AND ref = ?',
110                     (repo, ref),
111                 ).fetchone()
112                 if result:
113                     return result[0]
114 
115         result = _get_result()
116         if result:
117             return result
118         with self.exclusive_lock():
119             # Another process may have already completed this work
120             result = _get_result()
121             if result:  # pragma: no cover (race)
122                 return result
123 
124             logger.info('Initializing environment for {}.'.format(repo))
125 
126             directory = tempfile.mkdtemp(prefix='repo', dir=self.directory)
127             with clean_path_on_failure(directory):
128                 make_strategy(directory)
129 
130             # Update our db with the created repo
131             with self.connect() as db:
132                 db.execute(
133                     'INSERT INTO repos (repo, ref, path) VALUES (?, ?, ?)',
134                     [repo, ref, directory],
135                 )
136         return directory
137 
138     def _complete_clone(self, ref, git_cmd):
139         """Perform a complete clone of a repository and its submodules """
140 
141         git_cmd('fetch', 'origin')
142         git_cmd('checkout', ref)
143         git_cmd('submodule', 'update', '--init', '--recursive')
144 
145     def _shallow_clone(self, ref, git_cmd):  # pragma: windows no cover
146         """Perform a shallow clone of a repository and its submodules """
147 
148         git_config = 'protocol.version=2'
149         git_cmd('-c', git_config, 'fetch', 'origin', ref, '--depth=1')
150         git_cmd('checkout', ref)
151         git_cmd(
152             '-c', git_config, 'submodule', 'update', '--init',
153             '--recursive', '--depth=1',
154         )
155 
156     def clone(self, repo, ref, deps=()):
157         """Clone the given url and checkout the specific ref."""
158 
159         if os.path.isdir(repo):
160             repo = os.path.abspath(repo)
161 
162         def clone_strategy(directory):
163             env = git.no_git_env()
164 
165             def _git_cmd(*args):
166                 cmd_output('git', *args, cwd=directory, env=env)
167 
168             _git_cmd('init', '.')
169             _git_cmd('remote', 'add', 'origin', repo)
170 
171             try:
172                 self._shallow_clone(ref, _git_cmd)
173             except CalledProcessError:
174                 self._complete_clone(ref, _git_cmd)
175 
176         return self._new_repo(repo, ref, deps, clone_strategy)
177 
178     LOCAL_RESOURCES = (
179         'Cargo.toml', 'main.go', 'main.rs', '.npmignore', 'package.json',
180         'pre_commit_dummy_package.gemspec', 'setup.py',
181     )
182 
183     def make_local(self, deps):
184         def make_local_strategy(directory):
185             for resource in self.LOCAL_RESOURCES:
186                 contents = resource_text('empty_template_{}'.format(resource))
187                 with io.open(os.path.join(directory, resource), 'w') as f:
188                     f.write(contents)
189 
190             env = git.no_git_env()
191 
192             # initialize the git repository so it looks more like cloned repos
193             def _git_cmd(*args):
194                 cmd_output('git', *args, cwd=directory, env=env)
195 
196             _git_cmd('init', '.')
197             _git_cmd('config', 'remote.origin.url', '<<unknown>>')
198             _git_cmd('add', '.')
199             git.commit(repo=directory)
200 
201         return self._new_repo(
202             'local', C.LOCAL_REPO_VERSION, deps, make_local_strategy,
203         )
204 
205     def _create_config_table_if_not_exists(self, db):
206         db.executescript(
207             'CREATE TABLE IF NOT EXISTS configs ('
208             '   path TEXT NOT NULL,'
209             '   PRIMARY KEY (path)'
210             ');',
211         )
212 
213     def mark_config_used(self, path):
214         path = os.path.realpath(path)
215         # don't insert config files that do not exist
216         if not os.path.exists(path):
217             return
218         with self.connect() as db:
219             # TODO: eventually remove this and only create in _create
220             self._create_config_table_if_not_exists(db)
221             db.execute('INSERT OR IGNORE INTO configs VALUES (?)', (path,))
222 
223     def select_all_configs(self):
224         with self.connect() as db:
225             self._create_config_table_if_not_exists(db)
226             rows = db.execute('SELECT path FROM configs').fetchall()
227             return [path for path, in rows]
228 
229     def delete_configs(self, configs):
230         with self.connect() as db:
231             rows = [(path,) for path in configs]
232             db.executemany('DELETE FROM configs WHERE path = ?', rows)
233 
234     def select_all_repos(self):
235         with self.connect() as db:
236             return db.execute('SELECT repo, ref, path from repos').fetchall()
237 
238     def delete_repo(self, db_repo_name, ref, path):
239         with self.connect() as db:
240             db.execute(
241                 'DELETE FROM repos WHERE repo = ? and ref = ?',
242                 (db_repo_name, ref),
243             )
244         rmtree(path)
245
```
--- 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/store.py b/pre_commit/store.py
--- a/pre_commit/store.py
+++ b/pre_commit/store.py
@@ -138,7 +138,7 @@
     def _complete_clone(self, ref, git_cmd):
         """Perform a complete clone of a repository and its submodules """
 
-        git_cmd('fetch', 'origin')
+        git_cmd('fetch', 'origin', '--tags')
         git_cmd('checkout', ref)
         git_cmd('submodule', 'update', '--init', '--recursive')

{"golden_diff": "diff --git a/pre_commit/store.py b/pre_commit/store.py\n--- a/pre_commit/store.py\n+++ b/pre_commit/store.py\n@@ -138,7 +138,7 @@\n     def _complete_clone(self, ref, git_cmd):\n         \"\"\"Perform a complete clone of a repository and its submodules \"\"\"\n \n-        git_cmd('fetch', 'origin')\n+        git_cmd('fetch', 'origin', '--tags')\n         git_cmd('checkout', ref)\n         git_cmd('submodule', 'update', '--init', '--recursive')\n", "issue": "Failure to check out revision pre-commit v1.15.1\n```console\r\n$ cat .pre-commit-config.yaml \r\nrepos:\r\n-   repo: https://github.com/asottile/pyupgrade\r\n    rev: v1.13.0\r\n    hooks:\r\n    -   id: pyupgrade\r\n$ pre-commit install-hooks\r\n[INFO] Initializing environment for https://github.com/asottile/pyupgrade.\r\nAn unexpected error has occurred: CalledProcessError: Command: ('/usr/bin/git', 'checkout', 'v1.13.0')\r\nReturn code: 1\r\nExpected return code: 0\r\nOutput: (none)\r\nErrors: \r\n    error: pathspec 'v1.13.0' did not match any file(s) known to git.\r\n    \r\n\r\nCheck the log at /code/.cache/pre-commit/pre-commit.log\r\nlyftsvc@b780c05acb2e:/code/places$ cat ~/.cacp^C\r\nlyftsvc@b780c05acb2e:/code/places$ cat /code/.cache/pre-commit/pre-commit.log \r\nAn unexpected error has occurred: CalledProcessError: Command: ('/usr/bin/git', 'checkout', 'v1.13.0')\r\nReturn code: 1\r\nExpected return code: 0\r\nOutput: (none)\r\nErrors: \r\n    error: pathspec 'v1.13.0' did not match any file(s) known to git.\r\n    \r\n\r\nTraceback (most recent call last):\r\n  File \"/venv/lib/python3.6/site-packages/pre_commit/store.py\", line 172, in clone_strategy\r\n    self._shallow_clone(ref, _git_cmd)\r\n  File \"/venv/lib/python3.6/site-packages/pre_commit/store.py\", line 149, in _shallow_clone\r\n    git_cmd('-c', git_config, 'fetch', 'origin', ref, '--depth=1')\r\n  File \"/venv/lib/python3.6/site-packages/pre_commit/store.py\", line 166, in _git_cmd\r\n    cmd_output('git', *args, cwd=directory, env=env)\r\n  File \"/venv/lib/python3.6/site-packages/pre_commit/util.py\", line 153, in cmd_output\r\n    returncode, cmd, retcode, output=(stdout, stderr),\r\npre_commit.util.CalledProcessError: Command: ('/usr/bin/git', '-c', 'protocol.version=2', 'fetch', 'origin', 'v1.13.0', '--depth=1')\r\nReturn code: 128\r\nExpected return code: 0\r\nOutput: (none)\r\nErrors: \r\n    fatal: unknown value for config 'protocol.version': 2\r\n    \r\n\r\n\r\nDuring handling of the above exception, another exception occurred:\r\n\r\nTraceback (most recent call last):\r\n  File \"/venv/lib/python3.6/site-packages/pre_commit/error_handler.py\", line 46, in error_handler\r\n    yield\r\n  File \"/venv/lib/python3.6/site-packages/pre_commit/main.py\", line 274, in main\r\n    return install_hooks(args.config, store)\r\n  File \"/venv/lib/python3.6/site-packages/pre_commit/commands/install_uninstall.py\", line 129, in install_hooks\r\n    install_hook_envs(all_hooks(load_config(config_file), store), store)\r\n  File \"/venv/lib/python3.6/site-packages/pre_commit/repository.py\", line 221, in all_hooks\r\n    for repo in root_config['repos']\r\n  File \"/venv/lib/python3.6/site-packages/pre_commit/repository.py\", line 222, in <genexpr>\r\n    for hook in _repository_hooks(repo, store, root_config)\r\n  File \"/venv/lib/python3.6/site-packages/pre_commit/repository.py\", line 197, in _repository_hooks\r\n    return _cloned_repository_hooks(repo_config, store, root_config)\r\n  File \"/venv/lib/python3.6/site-packages/pre_commit/repository.py\", line 166, in _cloned_repository_hooks\r\n    manifest_path = os.path.join(store.clone(repo, rev), C.MANIFEST_FILE)\r\n  File \"/venv/lib/python3.6/site-packages/pre_commit/store.py\", line 176, in clone\r\n    return self._new_repo(repo, ref, deps, clone_strategy)\r\n  File \"/venv/lib/python3.6/site-packages/pre_commit/store.py\", line 128, in _new_repo\r\n    make_strategy(directory)\r\n  File \"/venv/lib/python3.6/site-packages/pre_commit/store.py\", line 174, in clone_strategy\r\n    self._complete_clone(ref, _git_cmd)\r\n  File \"/venv/lib/python3.6/site-packages/pre_commit/store.py\", line 142, in _complete_clone\r\n    git_cmd('checkout', ref)\r\n  File \"/venv/lib/python3.6/site-packages/pre_commit/store.py\", line 166, in _git_cmd\r\n    cmd_output('git', *args, cwd=directory, env=env)\r\n  File \"/venv/lib/python3.6/site-packages/pre_commit/util.py\", line 153, in cmd_output\r\n    returncode, cmd, retcode, output=(stdout, stderr),\r\npre_commit.util.CalledProcessError: Command: ('/usr/bin/git', 'checkout', 'v1.13.0')\r\nReturn code: 1\r\nExpected return code: 0\r\nOutput: (none)\r\nErrors: \r\n    error: pathspec 'v1.13.0' did not match any file(s) known to git.\r\n```\r\n\r\nPerhaps related to the new clone strategy\n", "before_files": [{"content": "from __future__ import unicode_literals\n\nimport contextlib\nimport io\nimport logging\nimport os.path\nimport sqlite3\nimport tempfile\n\nimport pre_commit.constants as C\nfrom pre_commit import file_lock\nfrom pre_commit import git\nfrom pre_commit.util import CalledProcessError\nfrom pre_commit.util import clean_path_on_failure\nfrom pre_commit.util import cmd_output\nfrom pre_commit.util import resource_text\nfrom pre_commit.util import rmtree\n\n\nlogger = logging.getLogger('pre_commit')\n\n\ndef _get_default_directory():\n    \"\"\"Returns the default directory for the Store.  This is intentionally\n    underscored to indicate that `Store.get_default_directory` is the intended\n    way to get this information.  This is also done so\n    `Store.get_default_directory` can be mocked in tests and\n    `_get_default_directory` can be tested.\n    \"\"\"\n    return os.environ.get('PRE_COMMIT_HOME') or os.path.join(\n        os.environ.get('XDG_CACHE_HOME') or os.path.expanduser('~/.cache'),\n        'pre-commit',\n    )\n\n\nclass Store(object):\n    get_default_directory = staticmethod(_get_default_directory)\n\n    def __init__(self, directory=None):\n        self.directory = directory or Store.get_default_directory()\n        self.db_path = os.path.join(self.directory, 'db.db')\n\n        if not os.path.exists(self.directory):\n            os.makedirs(self.directory)\n            with io.open(os.path.join(self.directory, 'README'), 'w') as f:\n                f.write(\n                    'This directory is maintained by the pre-commit project.\\n'\n                    'Learn more: https://github.com/pre-commit/pre-commit\\n',\n                )\n\n        if os.path.exists(self.db_path):\n            return\n        with self.exclusive_lock():\n            # Another process may have already completed this work\n            if os.path.exists(self.db_path):  # pragma: no cover (race)\n                return\n            # To avoid a race where someone ^Cs between db creation and\n            # execution of the CREATE TABLE statement\n            fd, tmpfile = tempfile.mkstemp(dir=self.directory)\n            # We'll be managing this file ourselves\n            os.close(fd)\n            with self.connect(db_path=tmpfile) as db:\n                db.executescript(\n                    'CREATE TABLE repos ('\n                    '    repo TEXT NOT NULL,'\n                    '    ref TEXT NOT NULL,'\n                    '    path TEXT NOT NULL,'\n                    '    PRIMARY KEY (repo, ref)'\n                    ');',\n                )\n                self._create_config_table_if_not_exists(db)\n\n            # Atomic file move\n            os.rename(tmpfile, self.db_path)\n\n    @contextlib.contextmanager\n    def exclusive_lock(self):\n        def blocked_cb():  # pragma: no cover (tests are single-process)\n            logger.info('Locking pre-commit directory')\n\n        with file_lock.lock(os.path.join(self.directory, '.lock'), blocked_cb):\n            yield\n\n    @contextlib.contextmanager\n    def connect(self, db_path=None):\n        db_path = db_path or self.db_path\n        # sqlite doesn't close its fd with its contextmanager >.<\n        # contextlib.closing fixes this.\n        # See: https://stackoverflow.com/a/28032829/812183\n        with contextlib.closing(sqlite3.connect(db_path)) as db:\n            # this creates a transaction\n            with db:\n                yield db\n\n    @classmethod\n    def db_repo_name(cls, repo, deps):\n        if deps:\n            return '{}:{}'.format(repo, ','.join(sorted(deps)))\n        else:\n            return repo\n\n    def _new_repo(self, repo, ref, deps, make_strategy):\n        repo = self.db_repo_name(repo, deps)\n\n        def _get_result():\n            # Check if we already exist\n            with self.connect() as db:\n                result = db.execute(\n                    'SELECT path FROM repos WHERE repo = ? AND ref = ?',\n                    (repo, ref),\n                ).fetchone()\n                if result:\n                    return result[0]\n\n        result = _get_result()\n        if result:\n            return result\n        with self.exclusive_lock():\n            # Another process may have already completed this work\n            result = _get_result()\n            if result:  # pragma: no cover (race)\n                return result\n\n            logger.info('Initializing environment for {}.'.format(repo))\n\n            directory = tempfile.mkdtemp(prefix='repo', dir=self.directory)\n            with clean_path_on_failure(directory):\n                make_strategy(directory)\n\n            # Update our db with the created repo\n            with self.connect() as db:\n                db.execute(\n                    'INSERT INTO repos (repo, ref, path) VALUES (?, ?, ?)',\n                    [repo, ref, directory],\n                )\n        return directory\n\n    def _complete_clone(self, ref, git_cmd):\n        \"\"\"Perform a complete clone of a repository and its submodules \"\"\"\n\n        git_cmd('fetch', 'origin')\n        git_cmd('checkout', ref)\n        git_cmd('submodule', 'update', '--init', '--recursive')\n\n    def _shallow_clone(self, ref, git_cmd):  # pragma: windows no cover\n        \"\"\"Perform a shallow clone of a repository and its submodules \"\"\"\n\n        git_config = 'protocol.version=2'\n        git_cmd('-c', git_config, 'fetch', 'origin', ref, '--depth=1')\n        git_cmd('checkout', ref)\n        git_cmd(\n            '-c', git_config, 'submodule', 'update', '--init',\n            '--recursive', '--depth=1',\n        )\n\n    def clone(self, repo, ref, deps=()):\n        \"\"\"Clone the given url and checkout the specific ref.\"\"\"\n\n        if os.path.isdir(repo):\n            repo = os.path.abspath(repo)\n\n        def clone_strategy(directory):\n            env = git.no_git_env()\n\n            def _git_cmd(*args):\n                cmd_output('git', *args, cwd=directory, env=env)\n\n            _git_cmd('init', '.')\n            _git_cmd('remote', 'add', 'origin', repo)\n\n            try:\n                self._shallow_clone(ref, _git_cmd)\n            except CalledProcessError:\n                self._complete_clone(ref, _git_cmd)\n\n        return self._new_repo(repo, ref, deps, clone_strategy)\n\n    LOCAL_RESOURCES = (\n        'Cargo.toml', 'main.go', 'main.rs', '.npmignore', 'package.json',\n        'pre_commit_dummy_package.gemspec', 'setup.py',\n    )\n\n    def make_local(self, deps):\n        def make_local_strategy(directory):\n            for resource in self.LOCAL_RESOURCES:\n                contents = resource_text('empty_template_{}'.format(resource))\n                with io.open(os.path.join(directory, resource), 'w') as f:\n                    f.write(contents)\n\n            env = git.no_git_env()\n\n            # initialize the git repository so it looks more like cloned repos\n            def _git_cmd(*args):\n                cmd_output('git', *args, cwd=directory, env=env)\n\n            _git_cmd('init', '.')\n            _git_cmd('config', 'remote.origin.url', '<<unknown>>')\n            _git_cmd('add', '.')\n            git.commit(repo=directory)\n\n        return self._new_repo(\n            'local', C.LOCAL_REPO_VERSION, deps, make_local_strategy,\n        )\n\n    def _create_config_table_if_not_exists(self, db):\n        db.executescript(\n            'CREATE TABLE IF NOT EXISTS configs ('\n            '   path TEXT NOT NULL,'\n            '   PRIMARY KEY (path)'\n            ');',\n        )\n\n    def mark_config_used(self, path):\n        path = os.path.realpath(path)\n        # don't insert config files that do not exist\n        if not os.path.exists(path):\n            return\n        with self.connect() as db:\n            # TODO: eventually remove this and only create in _create\n            self._create_config_table_if_not_exists(db)\n            db.execute('INSERT OR IGNORE INTO configs VALUES (?)', (path,))\n\n    def select_all_configs(self):\n        with self.connect() as db:\n            self._create_config_table_if_not_exists(db)\n            rows = db.execute('SELECT path FROM configs').fetchall()\n            return [path for path, in rows]\n\n    def delete_configs(self, configs):\n        with self.connect() as db:\n            rows = [(path,) for path in configs]\n            db.executemany('DELETE FROM configs WHERE path = ?', rows)\n\n    def select_all_repos(self):\n        with self.connect() as db:\n            return db.execute('SELECT repo, ref, path from repos').fetchall()\n\n    def delete_repo(self, db_repo_name, ref, path):\n        with self.connect() as db:\n            db.execute(\n                'DELETE FROM repos WHERE repo = ? and ref = ?',\n                (db_repo_name, ref),\n            )\n        rmtree(path)\n", "path": "pre_commit/store.py"}], "after_files": [{"content": "from __future__ import unicode_literals\n\nimport contextlib\nimport io\nimport logging\nimport os.path\nimport sqlite3\nimport tempfile\n\nimport pre_commit.constants as C\nfrom pre_commit import file_lock\nfrom pre_commit import git\nfrom pre_commit.util import CalledProcessError\nfrom pre_commit.util import clean_path_on_failure\nfrom pre_commit.util import cmd_output\nfrom pre_commit.util import resource_text\nfrom pre_commit.util import rmtree\n\n\nlogger = logging.getLogger('pre_commit')\n\n\ndef _get_default_directory():\n    \"\"\"Returns the default directory for the Store.  This is intentionally\n    underscored to indicate that `Store.get_default_directory` is the intended\n    way to get this information.  This is also done so\n    `Store.get_default_directory` can be mocked in tests and\n    `_get_default_directory` can be tested.\n    \"\"\"\n    return os.environ.get('PRE_COMMIT_HOME') or os.path.join(\n        os.environ.get('XDG_CACHE_HOME') or os.path.expanduser('~/.cache'),\n        'pre-commit',\n    )\n\n\nclass Store(object):\n    get_default_directory = staticmethod(_get_default_directory)\n\n    def __init__(self, directory=None):\n        self.directory = directory or Store.get_default_directory()\n        self.db_path = os.path.join(self.directory, 'db.db')\n\n        if not os.path.exists(self.directory):\n            os.makedirs(self.directory)\n            with io.open(os.path.join(self.directory, 'README'), 'w') as f:\n                f.write(\n                    'This directory is maintained by the pre-commit project.\\n'\n                    'Learn more: https://github.com/pre-commit/pre-commit\\n',\n                )\n\n        if os.path.exists(self.db_path):\n            return\n        with self.exclusive_lock():\n            # Another process may have already completed this work\n            if os.path.exists(self.db_path):  # pragma: no cover (race)\n                return\n            # To avoid a race where someone ^Cs between db creation and\n            # execution of the CREATE TABLE statement\n            fd, tmpfile = tempfile.mkstemp(dir=self.directory)\n            # We'll be managing this file ourselves\n            os.close(fd)\n            with self.connect(db_path=tmpfile) as db:\n                db.executescript(\n                    'CREATE TABLE repos ('\n                    '    repo TEXT NOT NULL,'\n                    '    ref TEXT NOT NULL,'\n                    '    path TEXT NOT NULL,'\n                    '    PRIMARY KEY (repo, ref)'\n                    ');',\n                )\n                self._create_config_table_if_not_exists(db)\n\n            # Atomic file move\n            os.rename(tmpfile, self.db_path)\n\n    @contextlib.contextmanager\n    def exclusive_lock(self):\n        def blocked_cb():  # pragma: no cover (tests are single-process)\n            logger.info('Locking pre-commit directory')\n\n        with file_lock.lock(os.path.join(self.directory, '.lock'), blocked_cb):\n            yield\n\n    @contextlib.contextmanager\n    def connect(self, db_path=None):\n        db_path = db_path or self.db_path\n        # sqlite doesn't close its fd with its contextmanager >.<\n        # contextlib.closing fixes this.\n        # See: https://stackoverflow.com/a/28032829/812183\n        with contextlib.closing(sqlite3.connect(db_path)) as db:\n            # this creates a transaction\n            with db:\n                yield db\n\n    @classmethod\n    def db_repo_name(cls, repo, deps):\n        if deps:\n            return '{}:{}'.format(repo, ','.join(sorted(deps)))\n        else:\n            return repo\n\n    def _new_repo(self, repo, ref, deps, make_strategy):\n        repo = self.db_repo_name(repo, deps)\n\n        def _get_result():\n            # Check if we already exist\n            with self.connect() as db:\n                result = db.execute(\n                    'SELECT path FROM repos WHERE repo = ? AND ref = ?',\n                    (repo, ref),\n                ).fetchone()\n                if result:\n                    return result[0]\n\n        result = _get_result()\n        if result:\n            return result\n        with self.exclusive_lock():\n            # Another process may have already completed this work\n            result = _get_result()\n            if result:  # pragma: no cover (race)\n                return result\n\n            logger.info('Initializing environment for {}.'.format(repo))\n\n            directory = tempfile.mkdtemp(prefix='repo', dir=self.directory)\n            with clean_path_on_failure(directory):\n                make_strategy(directory)\n\n            # Update our db with the created repo\n            with self.connect() as db:\n                db.execute(\n                    'INSERT INTO repos (repo, ref, path) VALUES (?, ?, ?)',\n                    [repo, ref, directory],\n                )\n        return directory\n\n    def _complete_clone(self, ref, git_cmd):\n        \"\"\"Perform a complete clone of a repository and its submodules \"\"\"\n\n        git_cmd('fetch', 'origin', '--tags')\n        git_cmd('checkout', ref)\n        git_cmd('submodule', 'update', '--init', '--recursive')\n\n    def _shallow_clone(self, ref, git_cmd):  # pragma: windows no cover\n        \"\"\"Perform a shallow clone of a repository and its submodules \"\"\"\n\n        git_config = 'protocol.version=2'\n        git_cmd('-c', git_config, 'fetch', 'origin', ref, '--depth=1')\n        git_cmd('checkout', ref)\n        git_cmd(\n            '-c', git_config, 'submodule', 'update', '--init',\n            '--recursive', '--depth=1',\n        )\n\n    def clone(self, repo, ref, deps=()):\n        \"\"\"Clone the given url and checkout the specific ref.\"\"\"\n\n        if os.path.isdir(repo):\n            repo = os.path.abspath(repo)\n\n        def clone_strategy(directory):\n            env = git.no_git_env()\n\n            def _git_cmd(*args):\n                cmd_output('git', *args, cwd=directory, env=env)\n\n            _git_cmd('init', '.')\n            _git_cmd('remote', 'add', 'origin', repo)\n\n            try:\n                self._shallow_clone(ref, _git_cmd)\n            except CalledProcessError:\n                self._complete_clone(ref, _git_cmd)\n\n        return self._new_repo(repo, ref, deps, clone_strategy)\n\n    LOCAL_RESOURCES = (\n        'Cargo.toml', 'main.go', 'main.rs', '.npmignore', 'package.json',\n        'pre_commit_dummy_package.gemspec', 'setup.py',\n    )\n\n    def make_local(self, deps):\n        def make_local_strategy(directory):\n            for resource in self.LOCAL_RESOURCES:\n                contents = resource_text('empty_template_{}'.format(resource))\n                with io.open(os.path.join(directory, resource), 'w') as f:\n                    f.write(contents)\n\n            env = git.no_git_env()\n\n            # initialize the git repository so it looks more like cloned repos\n            def _git_cmd(*args):\n                cmd_output('git', *args, cwd=directory, env=env)\n\n            _git_cmd('init', '.')\n            _git_cmd('config', 'remote.origin.url', '<<unknown>>')\n            _git_cmd('add', '.')\n            git.commit(repo=directory)\n\n        return self._new_repo(\n            'local', C.LOCAL_REPO_VERSION, deps, make_local_strategy,\n        )\n\n    def _create_config_table_if_not_exists(self, db):\n        db.executescript(\n            'CREATE TABLE IF NOT EXISTS configs ('\n            '   path TEXT NOT NULL,'\n            '   PRIMARY KEY (path)'\n            ');',\n        )\n\n    def mark_config_used(self, path):\n        path = os.path.realpath(path)\n        # don't insert config files that do not exist\n        if not os.path.exists(path):\n            return\n        with self.connect() as db:\n            # TODO: eventually remove this and only create in _create\n            self._create_config_table_if_not_exists(db)\n            db.execute('INSERT OR IGNORE INTO configs VALUES (?)', (path,))\n\n    def select_all_configs(self):\n        with self.connect() as db:\n            self._create_config_table_if_not_exists(db)\n            rows = db.execute('SELECT path FROM configs').fetchall()\n            return [path for path, in rows]\n\n    def delete_configs(self, configs):\n        with self.connect() as db:\n            rows = [(path,) for path in configs]\n            db.executemany('DELETE FROM configs WHERE path = ?', rows)\n\n    def select_all_repos(self):\n        with self.connect() as db:\n            return db.execute('SELECT repo, ref, path from repos').fetchall()\n\n    def delete_repo(self, db_repo_name, ref, path):\n        with self.connect() as db:\n            db.execute(\n                'DELETE FROM repos WHERE repo = ? and ref = ?',\n                (db_repo_name, ref),\n            )\n        rmtree(path)\n", "path": "pre_commit/store.py"}]}