We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Broken edit links
Two issues which may or may not be related:
- Module sources: the "Edit on github" links for pages like http://www.tornadoweb.org/en/stable/_modules/tornado/stack_context.html are broken; they point to a non-existent .rst file. Is it possible to suppress the edit link for these pages (or ideally point it to the real source)? (migrated from https://github.com/snide/sphinx_rtd_theme/issues/237)
- Non-latest branches: on a page like http://www.tornadoweb.org/en/stable/, the "edit on github" link in the upper right is broken because it points to https://github.com/tornadoweb/tornado/blob/origin/stable/docs/index.rst (the 'origin' directory needs to be removed from the path). On the lower left, clicking "v: stable" for the menu and then "Edit" works (linking to https://github.com/tornadoweb/tornado/edit/stable/docs/index.rst).

The "latest" branch works fine (linking to "master"); this is only a problem for pages based on other branches (migrated from https://github.com/snide/sphinx_rtd_theme/issues/236)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `readthedocs/vcs_support/backends/git.py`
Content:
```
1 """Git-related utilities."""
2 
3 from __future__ import absolute_import
4 
5 import csv
6 import logging
7 import os
8 import re
9 
10 from builtins import str
11 from six import StringIO
12 
13 from readthedocs.projects.exceptions import ProjectImportError
14 from readthedocs.vcs_support.base import BaseVCS, VCSVersion
15 
16 
17 log = logging.getLogger(__name__)
18 
19 
20 class Backend(BaseVCS):
21 
22     """Git VCS backend."""
23 
24     supports_tags = True
25     supports_branches = True
26     fallback_branch = 'master'  # default branch
27 
28     def __init__(self, *args, **kwargs):
29         super(Backend, self).__init__(*args, **kwargs)
30         self.token = kwargs.get('token', None)
31         self.repo_url = self._get_clone_url()
32 
33     def _get_clone_url(self):
34         if '://' in self.repo_url:
35             hacked_url = self.repo_url.split('://')[1]
36             hacked_url = re.sub('.git$', '', hacked_url)
37             clone_url = 'https://%s' % hacked_url
38             if self.token:
39                 clone_url = 'https://%s@%s' % (self.token, hacked_url)
40                 return clone_url
41             # Don't edit URL because all hosts aren't the same
42 
43             # else:
44                 # clone_url = 'git://%s' % (hacked_url)
45         return self.repo_url
46 
47     def set_remote_url(self, url):
48         return self.run('git', 'remote', 'set-url', 'origin', url)
49 
50     def update(self):
51         # Use checkout() to update repo
52         self.checkout()
53 
54     def repo_exists(self):
55         code, _, _ = self.run('git', 'status')
56         return code == 0
57 
58     def fetch(self):
59         code, _, err = self.run('git', 'fetch', '--tags', '--prune')
60         if code != 0:
61             raise ProjectImportError(
62                 "Failed to get code from '%s' (git fetch): %s\n\nStderr:\n\n%s\n\n" % (
63                     self.repo_url, code, err)
64             )
65 
66     def checkout_revision(self, revision=None):
67         if not revision:
68             branch = self.default_branch or self.fallback_branch
69             revision = 'origin/%s' % branch
70 
71         code, out, err = self.run('git', 'checkout',
72                                   '--force', '--quiet', revision)
73         if code != 0:
74             log.warning("Failed to checkout revision '%s': %s",
75                         revision, code)
76         return [code, out, err]
77 
78     def clone(self):
79         code, _, err = self.run('git', 'clone', '--recursive', '--quiet',
80                                 self.repo_url, '.')
81         if code != 0:
82             raise ProjectImportError(
83                 (
84                     "Failed to get code from '{url}' (git clone): {exit}\n\n"
85                     "git clone error output: {sterr}"
86                 ).format(
87                     url=self.repo_url,
88                     exit=code,
89                     sterr=err
90                 )
91             )
92 
93     @property
94     def tags(self):
95         retcode, stdout, _ = self.run('git', 'show-ref', '--tags')
96         # error (or no tags found)
97         if retcode != 0:
98             return []
99         return self.parse_tags(stdout)
100 
101     def parse_tags(self, data):
102         """
103         Parses output of show-ref --tags, eg:
104 
105             3b32886c8d3cb815df3793b3937b2e91d0fb00f1 refs/tags/2.0.0
106             bd533a768ff661991a689d3758fcfe72f455435d refs/tags/2.0.1
107             c0288a17899b2c6818f74e3a90b77e2a1779f96a refs/tags/2.0.2
108             a63a2de628a3ce89034b7d1a5ca5e8159534eef0 refs/tags/2.1.0.beta2
109             c7fc3d16ed9dc0b19f0d27583ca661a64562d21e refs/tags/2.1.0.rc1
110             edc0a2d02a0cc8eae8b67a3a275f65cd126c05b1 refs/tags/2.1.0.rc2
111 
112         Into VCSTag objects with the tag name as verbose_name and the commit
113         hash as identifier.
114         """
115         # parse the lines into a list of tuples (commit-hash, tag ref name)
116         # StringIO below is expecting Unicode data, so ensure that it gets it.
117         if not isinstance(data, str):
118             data = str(data)
119         raw_tags = csv.reader(StringIO(data), delimiter=' ')
120         vcs_tags = []
121         for row in raw_tags:
122             row = [f for f in row if f != '']
123             if row == []:
124                 continue
125             commit_hash, name = row
126             clean_name = name.split('/')[-1]
127             vcs_tags.append(VCSVersion(self, commit_hash, clean_name))
128         return vcs_tags
129 
130     @property
131     def branches(self):
132         # Only show remote branches
133         retcode, stdout, _ = self.run('git', 'branch', '-r')
134         # error (or no tags found)
135         if retcode != 0:
136             return []
137         return self.parse_branches(stdout)
138 
139     def parse_branches(self, data):
140         """
141         Parse output of git branch -r
142 
143         e.g.:
144 
145               origin/2.0.X
146               origin/HEAD -> origin/master
147               origin/develop
148               origin/master
149               origin/release/2.0.0
150               origin/release/2.1.0
151         """
152         clean_branches = []
153         # StringIO below is expecting Unicode data, so ensure that it gets it.
154         if not isinstance(data, str):
155             data = str(data)
156         raw_branches = csv.reader(StringIO(data), delimiter=' ')
157         for branch in raw_branches:
158             branch = [f for f in branch if f != '' and f != '*']
159             # Handle empty branches
160             if branch:
161                 branch = branch[0]
162                 if branch.startswith('origin/'):
163                     cut_len = len('origin/')
164                     slug = branch[cut_len:].replace('/', '-')
165                     if slug in ['HEAD']:
166                         continue
167                     clean_branches.append(VCSVersion(self, branch, slug))
168                 else:
169                     # Believe this is dead code.
170                     slug = branch.replace('/', '-')
171                     clean_branches.append(VCSVersion(self, branch, slug))
172         return clean_branches
173 
174     @property
175     def commit(self):
176         _, stdout, _ = self.run('git', 'rev-parse', 'HEAD')
177         return stdout.strip()
178 
179     def checkout(self, identifier=None):
180         self.check_working_dir()
181 
182         # Clone or update repository
183         if self.repo_exists():
184             self.set_remote_url(self.repo_url)
185             self.fetch()
186         else:
187             self.make_clean_working_dir()
188             self.clone()
189 
190         # Find proper identifier
191         if not identifier:
192             identifier = self.default_branch or self.fallback_branch
193 
194         identifier = self.find_ref(identifier)
195 
196         # Checkout the correct identifier for this branch.
197         code, out, err = self.checkout_revision(identifier)
198         if code != 0:
199             return code, out, err
200 
201         # Clean any remains of previous checkouts
202         self.run('git', 'clean', '-d', '-f', '-f')
203 
204         # Update submodules
205         self.run('git', 'submodule', 'sync')
206         self.run('git', 'submodule', 'update',
207                  '--init', '--recursive', '--force')
208 
209         return code, out, err
210 
211     def find_ref(self, ref):
212         # Check if ref starts with 'origin/'
213         if ref.startswith('origin/'):
214             return ref
215 
216         # Check if ref is a branch of the origin remote
217         if self.ref_exists('remotes/origin/' + ref):
218             return 'origin/' + ref
219 
220         return ref
221 
222     def ref_exists(self, ref):
223         code, _, _ = self.run('git', 'show-ref', ref)
224         return code == 0
225 
226     @property
227     def env(self):
228         env = super(Backend, self).env
229         env['GIT_DIR'] = os.path.join(self.working_dir, '.git')
230         return env
231
```
--- 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/readthedocs/vcs_support/backends/git.py b/readthedocs/vcs_support/backends/git.py
--- a/readthedocs/vcs_support/backends/git.py
+++ b/readthedocs/vcs_support/backends/git.py
@@ -92,7 +92,15 @@
 
     @property
     def tags(self):
-        retcode, stdout, _ = self.run('git', 'show-ref', '--tags')
+        # Hash for non-annotated tag is its commit hash, but for annotated tag it
+        # points to tag itself, so we need to dereference annotated tags.
+        # The output format is the same as `git show-ref --tags`, but with hashes
+        # of annotated tags pointing to tagged commits.
+        retcode, stdout, _ = self.run(
+            'git', 'for-each-ref',
+            '--format="%(if)%(*objectname)%(then)%(*objectname)'
+            '%(else)%(objectname)%(end) %(refname)"',
+            'refs/tags')
         # error (or no tags found)
         if retcode != 0:
             return []
@@ -100,7 +108,7 @@
 
     def parse_tags(self, data):
         """
-        Parses output of show-ref --tags, eg:
+        Parses output of `git show-ref --tags`, eg:
 
             3b32886c8d3cb815df3793b3937b2e91d0fb00f1 refs/tags/2.0.0
             bd533a768ff661991a689d3758fcfe72f455435d refs/tags/2.0.1

{"golden_diff": "diff --git a/readthedocs/vcs_support/backends/git.py b/readthedocs/vcs_support/backends/git.py\n--- a/readthedocs/vcs_support/backends/git.py\n+++ b/readthedocs/vcs_support/backends/git.py\n@@ -92,7 +92,15 @@\n \n     @property\n     def tags(self):\n-        retcode, stdout, _ = self.run('git', 'show-ref', '--tags')\n+        # Hash for non-annotated tag is its commit hash, but for annotated tag it\n+        # points to tag itself, so we need to dereference annotated tags.\n+        # The output format is the same as `git show-ref --tags`, but with hashes\n+        # of annotated tags pointing to tagged commits.\n+        retcode, stdout, _ = self.run(\n+            'git', 'for-each-ref',\n+            '--format=\"%(if)%(*objectname)%(then)%(*objectname)'\n+            '%(else)%(objectname)%(end) %(refname)\"',\n+            'refs/tags')\n         # error (or no tags found)\n         if retcode != 0:\n             return []\n@@ -100,7 +108,7 @@\n \n     def parse_tags(self, data):\n         \"\"\"\n-        Parses output of show-ref --tags, eg:\n+        Parses output of `git show-ref --tags`, eg:\n \n             3b32886c8d3cb815df3793b3937b2e91d0fb00f1 refs/tags/2.0.0\n             bd533a768ff661991a689d3758fcfe72f455435d refs/tags/2.0.1\n", "issue": "Broken edit links\nTwo issues which may or may not be related:\n- Module sources: the \"Edit on github\" links for pages like http://www.tornadoweb.org/en/stable/_modules/tornado/stack_context.html are broken; they point to a non-existent .rst file. Is it possible to suppress the edit link for these pages (or ideally point it to the real source)? (migrated from https://github.com/snide/sphinx_rtd_theme/issues/237)\n- Non-latest branches: on a page like http://www.tornadoweb.org/en/stable/, the \"edit on github\" link in the upper right is broken because it points to https://github.com/tornadoweb/tornado/blob/origin/stable/docs/index.rst (the 'origin' directory needs to be removed from the path). On the lower left, clicking \"v: stable\" for the menu and then \"Edit\" works (linking to https://github.com/tornadoweb/tornado/edit/stable/docs/index.rst).\n\nThe \"latest\" branch works fine (linking to \"master\"); this is only a problem for pages based on other branches (migrated from https://github.com/snide/sphinx_rtd_theme/issues/236)\n\n", "before_files": [{"content": "\"\"\"Git-related utilities.\"\"\"\n\nfrom __future__ import absolute_import\n\nimport csv\nimport logging\nimport os\nimport re\n\nfrom builtins import str\nfrom six import StringIO\n\nfrom readthedocs.projects.exceptions import ProjectImportError\nfrom readthedocs.vcs_support.base import BaseVCS, VCSVersion\n\n\nlog = logging.getLogger(__name__)\n\n\nclass Backend(BaseVCS):\n\n    \"\"\"Git VCS backend.\"\"\"\n\n    supports_tags = True\n    supports_branches = True\n    fallback_branch = 'master'  # default branch\n\n    def __init__(self, *args, **kwargs):\n        super(Backend, self).__init__(*args, **kwargs)\n        self.token = kwargs.get('token', None)\n        self.repo_url = self._get_clone_url()\n\n    def _get_clone_url(self):\n        if '://' in self.repo_url:\n            hacked_url = self.repo_url.split('://')[1]\n            hacked_url = re.sub('.git$', '', hacked_url)\n            clone_url = 'https://%s' % hacked_url\n            if self.token:\n                clone_url = 'https://%s@%s' % (self.token, hacked_url)\n                return clone_url\n            # Don't edit URL because all hosts aren't the same\n\n            # else:\n                # clone_url = 'git://%s' % (hacked_url)\n        return self.repo_url\n\n    def set_remote_url(self, url):\n        return self.run('git', 'remote', 'set-url', 'origin', url)\n\n    def update(self):\n        # Use checkout() to update repo\n        self.checkout()\n\n    def repo_exists(self):\n        code, _, _ = self.run('git', 'status')\n        return code == 0\n\n    def fetch(self):\n        code, _, err = self.run('git', 'fetch', '--tags', '--prune')\n        if code != 0:\n            raise ProjectImportError(\n                \"Failed to get code from '%s' (git fetch): %s\\n\\nStderr:\\n\\n%s\\n\\n\" % (\n                    self.repo_url, code, err)\n            )\n\n    def checkout_revision(self, revision=None):\n        if not revision:\n            branch = self.default_branch or self.fallback_branch\n            revision = 'origin/%s' % branch\n\n        code, out, err = self.run('git', 'checkout',\n                                  '--force', '--quiet', revision)\n        if code != 0:\n            log.warning(\"Failed to checkout revision '%s': %s\",\n                        revision, code)\n        return [code, out, err]\n\n    def clone(self):\n        code, _, err = self.run('git', 'clone', '--recursive', '--quiet',\n                                self.repo_url, '.')\n        if code != 0:\n            raise ProjectImportError(\n                (\n                    \"Failed to get code from '{url}' (git clone): {exit}\\n\\n\"\n                    \"git clone error output: {sterr}\"\n                ).format(\n                    url=self.repo_url,\n                    exit=code,\n                    sterr=err\n                )\n            )\n\n    @property\n    def tags(self):\n        retcode, stdout, _ = self.run('git', 'show-ref', '--tags')\n        # error (or no tags found)\n        if retcode != 0:\n            return []\n        return self.parse_tags(stdout)\n\n    def parse_tags(self, data):\n        \"\"\"\n        Parses output of show-ref --tags, eg:\n\n            3b32886c8d3cb815df3793b3937b2e91d0fb00f1 refs/tags/2.0.0\n            bd533a768ff661991a689d3758fcfe72f455435d refs/tags/2.0.1\n            c0288a17899b2c6818f74e3a90b77e2a1779f96a refs/tags/2.0.2\n            a63a2de628a3ce89034b7d1a5ca5e8159534eef0 refs/tags/2.1.0.beta2\n            c7fc3d16ed9dc0b19f0d27583ca661a64562d21e refs/tags/2.1.0.rc1\n            edc0a2d02a0cc8eae8b67a3a275f65cd126c05b1 refs/tags/2.1.0.rc2\n\n        Into VCSTag objects with the tag name as verbose_name and the commit\n        hash as identifier.\n        \"\"\"\n        # parse the lines into a list of tuples (commit-hash, tag ref name)\n        # StringIO below is expecting Unicode data, so ensure that it gets it.\n        if not isinstance(data, str):\n            data = str(data)\n        raw_tags = csv.reader(StringIO(data), delimiter=' ')\n        vcs_tags = []\n        for row in raw_tags:\n            row = [f for f in row if f != '']\n            if row == []:\n                continue\n            commit_hash, name = row\n            clean_name = name.split('/')[-1]\n            vcs_tags.append(VCSVersion(self, commit_hash, clean_name))\n        return vcs_tags\n\n    @property\n    def branches(self):\n        # Only show remote branches\n        retcode, stdout, _ = self.run('git', 'branch', '-r')\n        # error (or no tags found)\n        if retcode != 0:\n            return []\n        return self.parse_branches(stdout)\n\n    def parse_branches(self, data):\n        \"\"\"\n        Parse output of git branch -r\n\n        e.g.:\n\n              origin/2.0.X\n              origin/HEAD -> origin/master\n              origin/develop\n              origin/master\n              origin/release/2.0.0\n              origin/release/2.1.0\n        \"\"\"\n        clean_branches = []\n        # StringIO below is expecting Unicode data, so ensure that it gets it.\n        if not isinstance(data, str):\n            data = str(data)\n        raw_branches = csv.reader(StringIO(data), delimiter=' ')\n        for branch in raw_branches:\n            branch = [f for f in branch if f != '' and f != '*']\n            # Handle empty branches\n            if branch:\n                branch = branch[0]\n                if branch.startswith('origin/'):\n                    cut_len = len('origin/')\n                    slug = branch[cut_len:].replace('/', '-')\n                    if slug in ['HEAD']:\n                        continue\n                    clean_branches.append(VCSVersion(self, branch, slug))\n                else:\n                    # Believe this is dead code.\n                    slug = branch.replace('/', '-')\n                    clean_branches.append(VCSVersion(self, branch, slug))\n        return clean_branches\n\n    @property\n    def commit(self):\n        _, stdout, _ = self.run('git', 'rev-parse', 'HEAD')\n        return stdout.strip()\n\n    def checkout(self, identifier=None):\n        self.check_working_dir()\n\n        # Clone or update repository\n        if self.repo_exists():\n            self.set_remote_url(self.repo_url)\n            self.fetch()\n        else:\n            self.make_clean_working_dir()\n            self.clone()\n\n        # Find proper identifier\n        if not identifier:\n            identifier = self.default_branch or self.fallback_branch\n\n        identifier = self.find_ref(identifier)\n\n        # Checkout the correct identifier for this branch.\n        code, out, err = self.checkout_revision(identifier)\n        if code != 0:\n            return code, out, err\n\n        # Clean any remains of previous checkouts\n        self.run('git', 'clean', '-d', '-f', '-f')\n\n        # Update submodules\n        self.run('git', 'submodule', 'sync')\n        self.run('git', 'submodule', 'update',\n                 '--init', '--recursive', '--force')\n\n        return code, out, err\n\n    def find_ref(self, ref):\n        # Check if ref starts with 'origin/'\n        if ref.startswith('origin/'):\n            return ref\n\n        # Check if ref is a branch of the origin remote\n        if self.ref_exists('remotes/origin/' + ref):\n            return 'origin/' + ref\n\n        return ref\n\n    def ref_exists(self, ref):\n        code, _, _ = self.run('git', 'show-ref', ref)\n        return code == 0\n\n    @property\n    def env(self):\n        env = super(Backend, self).env\n        env['GIT_DIR'] = os.path.join(self.working_dir, '.git')\n        return env\n", "path": "readthedocs/vcs_support/backends/git.py"}], "after_files": [{"content": "\"\"\"Git-related utilities.\"\"\"\n\nfrom __future__ import absolute_import\n\nimport csv\nimport logging\nimport os\nimport re\n\nfrom builtins import str\nfrom six import StringIO\n\nfrom readthedocs.projects.exceptions import ProjectImportError\nfrom readthedocs.vcs_support.base import BaseVCS, VCSVersion\n\n\nlog = logging.getLogger(__name__)\n\n\nclass Backend(BaseVCS):\n\n    \"\"\"Git VCS backend.\"\"\"\n\n    supports_tags = True\n    supports_branches = True\n    fallback_branch = 'master'  # default branch\n\n    def __init__(self, *args, **kwargs):\n        super(Backend, self).__init__(*args, **kwargs)\n        self.token = kwargs.get('token', None)\n        self.repo_url = self._get_clone_url()\n\n    def _get_clone_url(self):\n        if '://' in self.repo_url:\n            hacked_url = self.repo_url.split('://')[1]\n            hacked_url = re.sub('.git$', '', hacked_url)\n            clone_url = 'https://%s' % hacked_url\n            if self.token:\n                clone_url = 'https://%s@%s' % (self.token, hacked_url)\n                return clone_url\n            # Don't edit URL because all hosts aren't the same\n\n            # else:\n                # clone_url = 'git://%s' % (hacked_url)\n        return self.repo_url\n\n    def set_remote_url(self, url):\n        return self.run('git', 'remote', 'set-url', 'origin', url)\n\n    def update(self):\n        # Use checkout() to update repo\n        self.checkout()\n\n    def repo_exists(self):\n        code, _, _ = self.run('git', 'status')\n        return code == 0\n\n    def fetch(self):\n        code, _, err = self.run('git', 'fetch', '--tags', '--prune')\n        if code != 0:\n            raise ProjectImportError(\n                \"Failed to get code from '%s' (git fetch): %s\\n\\nStderr:\\n\\n%s\\n\\n\" % (\n                    self.repo_url, code, err)\n            )\n\n    def checkout_revision(self, revision=None):\n        if not revision:\n            branch = self.default_branch or self.fallback_branch\n            revision = 'origin/%s' % branch\n\n        code, out, err = self.run('git', 'checkout',\n                                  '--force', '--quiet', revision)\n        if code != 0:\n            log.warning(\"Failed to checkout revision '%s': %s\",\n                        revision, code)\n        return [code, out, err]\n\n    def clone(self):\n        code, _, err = self.run('git', 'clone', '--recursive', '--quiet',\n                                self.repo_url, '.')\n        if code != 0:\n            raise ProjectImportError(\n                (\n                    \"Failed to get code from '{url}' (git clone): {exit}\\n\\n\"\n                    \"git clone error output: {sterr}\"\n                ).format(\n                    url=self.repo_url,\n                    exit=code,\n                    sterr=err\n                )\n            )\n\n    @property\n    def tags(self):\n        # Hash for non-annotated tag is its commit hash, but for annotated tag it\n        # points to tag itself, so we need to dereference annotated tags.\n        # The output format is the same as `git show-ref --tags`, but with hashes\n        # of annotated tags pointing to tagged commits.\n        retcode, stdout, _ = self.run(\n            'git', 'for-each-ref',\n            '--format=\"%(if)%(*objectname)%(then)%(*objectname)'\n            '%(else)%(objectname)%(end) %(refname)\"',\n            'refs/tags')\n        # error (or no tags found)\n        if retcode != 0:\n            return []\n        return self.parse_tags(stdout)\n\n    def parse_tags(self, data):\n        \"\"\"\n        Parses output of `git show-ref --tags`, eg:\n\n            3b32886c8d3cb815df3793b3937b2e91d0fb00f1 refs/tags/2.0.0\n            bd533a768ff661991a689d3758fcfe72f455435d refs/tags/2.0.1\n            c0288a17899b2c6818f74e3a90b77e2a1779f96a refs/tags/2.0.2\n            a63a2de628a3ce89034b7d1a5ca5e8159534eef0 refs/tags/2.1.0.beta2\n            c7fc3d16ed9dc0b19f0d27583ca661a64562d21e refs/tags/2.1.0.rc1\n            edc0a2d02a0cc8eae8b67a3a275f65cd126c05b1 refs/tags/2.1.0.rc2\n\n        Into VCSTag objects with the tag name as verbose_name and the commit\n        hash as identifier.\n        \"\"\"\n        # parse the lines into a list of tuples (commit-hash, tag ref name)\n        # StringIO below is expecting Unicode data, so ensure that it gets it.\n        if not isinstance(data, str):\n            data = str(data)\n        raw_tags = csv.reader(StringIO(data), delimiter=' ')\n        vcs_tags = []\n        for row in raw_tags:\n            row = [f for f in row if f != '']\n            if row == []:\n                continue\n            commit_hash, name = row\n            clean_name = name.split('/')[-1]\n            vcs_tags.append(VCSVersion(self, commit_hash, clean_name))\n        return vcs_tags\n\n    @property\n    def branches(self):\n        # Only show remote branches\n        retcode, stdout, _ = self.run('git', 'branch', '-r')\n        # error (or no tags found)\n        if retcode != 0:\n            return []\n        return self.parse_branches(stdout)\n\n    def parse_branches(self, data):\n        \"\"\"\n        Parse output of git branch -r\n\n        e.g.:\n\n              origin/2.0.X\n              origin/HEAD -> origin/master\n              origin/develop\n              origin/master\n              origin/release/2.0.0\n              origin/release/2.1.0\n        \"\"\"\n        clean_branches = []\n        # StringIO below is expecting Unicode data, so ensure that it gets it.\n        if not isinstance(data, str):\n            data = str(data)\n        raw_branches = csv.reader(StringIO(data), delimiter=' ')\n        for branch in raw_branches:\n            branch = [f for f in branch if f != '' and f != '*']\n            # Handle empty branches\n            if branch:\n                branch = branch[0]\n                if branch.startswith('origin/'):\n                    cut_len = len('origin/')\n                    slug = branch[cut_len:].replace('/', '-')\n                    if slug in ['HEAD']:\n                        continue\n                    clean_branches.append(VCSVersion(self, branch, slug))\n                else:\n                    # Believe this is dead code.\n                    slug = branch.replace('/', '-')\n                    clean_branches.append(VCSVersion(self, branch, slug))\n        return clean_branches\n\n    @property\n    def commit(self):\n        _, stdout, _ = self.run('git', 'rev-parse', 'HEAD')\n        return stdout.strip()\n\n    def checkout(self, identifier=None):\n        self.check_working_dir()\n\n        # Clone or update repository\n        if self.repo_exists():\n            self.set_remote_url(self.repo_url)\n            self.fetch()\n        else:\n            self.make_clean_working_dir()\n            self.clone()\n\n        # Find proper identifier\n        if not identifier:\n            identifier = self.default_branch or self.fallback_branch\n\n        identifier = self.find_ref(identifier)\n\n        # Checkout the correct identifier for this branch.\n        code, out, err = self.checkout_revision(identifier)\n        if code != 0:\n            return code, out, err\n\n        # Clean any remains of previous checkouts\n        self.run('git', 'clean', '-d', '-f', '-f')\n\n        # Update submodules\n        self.run('git', 'submodule', 'sync')\n        self.run('git', 'submodule', 'update',\n                 '--init', '--recursive', '--force')\n\n        return code, out, err\n\n    def find_ref(self, ref):\n        # Check if ref starts with 'origin/'\n        if ref.startswith('origin/'):\n            return ref\n\n        # Check if ref is a branch of the origin remote\n        if self.ref_exists('remotes/origin/' + ref):\n            return 'origin/' + ref\n\n        return ref\n\n    def ref_exists(self, ref):\n        code, _, _ = self.run('git', 'show-ref', ref)\n        return code == 0\n\n    @property\n    def env(self):\n        env = super(Backend, self).env\n        env['GIT_DIR'] = os.path.join(self.working_dir, '.git')\n        return env\n", "path": "readthedocs/vcs_support/backends/git.py"}]}