summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Thursfield <sam.thursfield@codethink.co.uk>2012-12-13 12:36:07 +0000
committerSam Thursfield <sam.thursfield@codethink.co.uk>2012-12-13 15:37:53 +0000
commitde50cec19b4f7e4c5a6da5ecc5cddd7a52ac3725 (patch)
tree552fdae98cd0cc15d0b8a23ee225751b1d8ae374
parentd63c97a0bef1cd2f03ca266acda67cad065632df (diff)
downloadmorph-de50cec19b4f7e4c5a6da5ecc5cddd7a52ac3725.tar.gz
Always use `git rev-parse --verify` to resolve refs
Previously some code used `git show-ref`, which is wrong -- given two refs named 'alpha/master' and 'master', `git show-ref master` will return both, sorted alphabetically. This can lead to build failures, etc. due to refs resolving to the wrong SHAs. We should also use `git rev-parse --verify` to verify SHA1s, which we previously did with `git rev-list`. Finally, `git rev-parse --verify` is more than twice as fast as `git show-ref`.
-rw-r--r--morphlib/cachedrepo.py29
-rw-r--r--morphlib/cachedrepo_tests.py32
-rw-r--r--morphlib/git.py2
-rw-r--r--morphlib/plugins/branch_and_merge_plugin.py4
-rwxr-xr-xtests.branching/ambiguous-refs.script6
-rwxr-xr-xtests/update-gits-chunk.script4
6 files changed, 27 insertions, 50 deletions
diff --git a/morphlib/cachedrepo.py b/morphlib/cachedrepo.py
index 0b5ce60f..312f580f 100644
--- a/morphlib/cachedrepo.py
+++ b/morphlib/cachedrepo.py
@@ -112,18 +112,10 @@ class CachedRepo(object):
'''
- if not morphlib.git.is_valid_sha1(ref):
- try:
- refs = self._show_ref(ref).split('\n')
- refs = [x.split() for x in refs]
- absref = refs[0][0]
- except cliapp.AppException:
- raise InvalidReferenceError(self, ref)
- else:
- try:
- absref = self._rev_list(ref).strip()
- except cliapp.AppException:
- raise InvalidReferenceError(self, ref)
+ try:
+ absref = self._rev_parse(ref)
+ except cliapp.AppException:
+ raise InvalidReferenceError(self, ref)
tree = self._show_tree_hash(absref)
return absref, tree
@@ -141,7 +133,7 @@ class CachedRepo(object):
if not morphlib.git.is_valid_sha1(ref):
raise UnresolvedNamedReferenceError(self, ref)
try:
- sha1 = self._rev_list(ref).strip()
+ sha1 = self._rev_parse(ref)
except cliapp.AppException:
raise InvalidReferenceError(self, ref)
@@ -193,7 +185,7 @@ class CachedRepo(object):
'''Loads a morphology from a given ref'''
if not morphlib.git.is_valid_sha1(ref):
- ref = self._rev_list(ref).strip()
+ ref = self._rev_parse(ref)
text = self.cat(ref, '%s.morph' % name)
morphology = morphlib.morph2.Morphology(text)
return morphology
@@ -210,7 +202,7 @@ class CachedRepo(object):
if not morphlib.git.is_valid_sha1(ref):
raise UnresolvedNamedReferenceError(self, ref)
try:
- sha1 = self._rev_list(ref).strip()
+ sha1 = self._rev_parse(ref)
except cliapp.AppException:
raise InvalidReferenceError(self, ref)
@@ -237,16 +229,13 @@ class CachedRepo(object):
kwargs['cwd'] = self.path
return self.app.runcmd(*args, **kwargs)
- def _show_ref(self, ref): # pragma: no cover
- return self._runcmd(['git', 'show-ref', ref])
+ def _rev_parse(self, ref): # pragma: no cover
+ return self._runcmd(['git', 'rev-parse', '--verify', ref])[0:40]
def _show_tree_hash(self, absref): # pragma: no cover
return self._runcmd(
['git', 'log', '-1', '--format=format:%T', absref]).strip()
- def _rev_list(self, ref): # pragma: no cover
- return self._runcmd(['git', 'rev-list', '--no-walk', ref])
-
def _ls_tree(self, ref): # pragma: no cover
result = self._runcmd(['git', 'ls-tree', '--name-only', ref])
return result.split('\n')
diff --git a/morphlib/cachedrepo_tests.py b/morphlib/cachedrepo_tests.py
index 81673880..0c1ec5de 100644
--- a/morphlib/cachedrepo_tests.py
+++ b/morphlib/cachedrepo_tests.py
@@ -31,19 +31,19 @@ class CachedRepoTests(unittest.TestCase):
"kind": "chunk"
}'''
- def show_ref(self, ref):
+ def rev_parse(self, ref):
output = {
- 'master':
- 'e28a23812eadf2fce6583b8819b9c5dbd36b9fb9'
- ' refs/heads/master',
- 'baserock/morph':
- '8b780e2e6f102fcf400ff973396566d36d730501'
- ' refs/heads/baserock/morph',
+ 'a4da32f5a81c8bc6d660404724cedc3bc0914a75':
+ 'a4da32f5a81c8bc6d660404724cedc3bc0914a75',
+ 'e28a23812eadf2fce6583b8819b9c5dbd36b9fb9':
+ 'e28a23812eadf2fce6583b8819b9c5dbd36b9fb9',
+ 'master': 'e28a23812eadf2fce6583b8819b9c5dbd36b9fb9',
+ 'baserock/morph': '8b780e2e6f102fcf400ff973396566d36d730501'
}
try:
return output[ref]
except:
- raise cliapp.AppException('git show-ref %s' % ref)
+ raise cliapp.AppException('git rev-parse --verify %s' % ref)
def show_tree_hash(self, absref):
output = {
@@ -60,19 +60,6 @@ class CachedRepoTests(unittest.TestCase):
raise cliapp.AppException('git log -1 --format=format:%%T %s' %
absref)
- def rev_list(self, ref):
- output = {
- 'master': 'e28a23812eadf2fce6583b8819b9c5dbd36b9fb9',
- 'e28a23812eadf2fce6583b8819b9c5dbd36b9fb9':
- 'e28a23812eadf2fce6583b8819b9c5dbd36b9fb9',
- 'a4da32f5a81c8bc6d660404724cedc3bc0914a75':
- 'a4da32f5a81c8bc6d660404724cedc3bc0914a75',
- }
- try:
- return output[ref]
- except:
- raise cliapp.AppException('git rev-list %s' % ref)
-
def cat_file(self, ref, filename):
output = {
'e28a23812eadf2fce6583b8819b9c5dbd36b9fb9:foo.morph':
@@ -125,9 +112,8 @@ class CachedRepoTests(unittest.TestCase):
self.repo_path = '/tmp/foo'
self.repo = cachedrepo.CachedRepo(
object(), self.repo_name, self.repo_url, self.repo_path)
- self.repo._show_ref = self.show_ref
+ self.repo._rev_parse = self.rev_parse
self.repo._show_tree_hash = self.show_tree_hash
- self.repo._rev_list = self.rev_list
self.repo._cat_file = self.cat_file
self.repo._copy_repository = self.copy_repository
self.repo._checkout_ref = self.checkout_ref
diff --git a/morphlib/git.py b/morphlib/git.py
index 7985b815..1c704337 100644
--- a/morphlib/git.py
+++ b/morphlib/git.py
@@ -256,4 +256,4 @@ def is_valid_sha1(ref):
def rev_parse(runcmd, gitdir, ref):
'''Find the sha1 for the given ref'''
- return runcmd(['git', 'rev-parse', ref], cwd=gitdir)[0:40]
+ return runcmd(['git', 'rev-parse', '--verify', ref], cwd=gitdir)[0:40]
diff --git a/morphlib/plugins/branch_and_merge_plugin.py b/morphlib/plugins/branch_and_merge_plugin.py
index efaa8dfe..31b661b6 100644
--- a/morphlib/plugins/branch_and_merge_plugin.py
+++ b/morphlib/plugins/branch_and_merge_plugin.py
@@ -194,8 +194,8 @@ class BranchAndMergePlugin(cliapp.Plugin):
def resolve_ref(self, repodir, ref):
try:
- return self.app.runcmd(['git', 'show-ref', ref],
- cwd=repodir).split()[0]
+ return self.app.runcmd(['git', 'rev-parse', '--verify', ref],
+ cwd=repodir)[0:40]
except:
return None
diff --git a/tests.branching/ambiguous-refs.script b/tests.branching/ambiguous-refs.script
index a93c4b66..0ea8a55f 100755
--- a/tests.branching/ambiguous-refs.script
+++ b/tests.branching/ambiguous-refs.script
@@ -16,8 +16,10 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-## 'git show-ref master' sorts its output alphabetically, so we can't rely on
-## it to resolve 'master': we might get 'alpha/master' instead.
+## Guard against a bug that occurs if 'git show-ref' is used to resolve refs
+## instead of 'git rev-parse --verify': show-ref returns a list of partial
+## matches sorted alphabetically, so any code using it may resolve refs
+## incorrectly.
set -eu
diff --git a/tests/update-gits-chunk.script b/tests/update-gits-chunk.script
index c2ad08d0..288438ec 100755
--- a/tests/update-gits-chunk.script
+++ b/tests/update-gits-chunk.script
@@ -31,7 +31,7 @@ REPO_ALIAS='test=git://localhost:9419/%s#git://localhost:9419/%s'
cd "$DATADIR/chunk-repo"
git checkout --quiet farrokh
git commit --quiet --allow-empty --allow-empty-message -m ""
-NEWREF="$(git show-ref --hash farrokh)"
+NEWREF="$(git rev-parse --verify farrokh)"
"$SRCDIR/scripts/test-morph" --repo-alias=$REPO_ALIAS update-gits \
test:chunk-repo farrokh hello
@@ -40,4 +40,4 @@ kill $(cat "$DATADIR/git.pid")
# Check the top commit of the cached repo's farrokh branch
cd "$DATADIR/cache/gits/"*chunk?repo*
-test "$(git show-ref --hash refs/heads/farrokh)" = "$NEWREF"
+test "$(git rev-parse --verify refs/heads/farrokh)" = "$NEWREF"