peel_onion(): add support for <rev>^{tag}

Complete the <rev>^{<type>} family of object descriptors by having
<rev>^{tag} dereference <rev> until a tag object is found (or fail if
unable).

At first glance this may not seem very useful, as commits, trees, and
blobs cannot be peeled to a tag, and a tag would just peel to itself.
However, this can be used to ensure that <rev> names a tag object:

    $ git rev-parse --verify v1.8.4^{tag}
    04f013dc38
    $ git rev-parse --verify master^{tag}
    error: master^{tag}: expected tag type, but the object dereferences to tree type
    fatal: Needed a single revision

Users can already ensure that <rev> is a tag object by checking the
output of 'git cat-file -t <rev>', but:
  * users may expect <rev>^{tag} to exist given that <rev>^{commit},
    <rev>^{tree}, and <rev>^{blob} all exist
  * this syntax is more convenient/natural in some circumstances

Signed-off-by: Richard Hansen <rhansen@bbn.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Richard Hansen
2013-09-03 15:50:16 -04:00
committed by Junio C Hamano
parent e230c568c4
commit 75aa26d34c
3 changed files with 12 additions and 0 deletions

View File

@ -121,6 +121,9 @@ some output processing may assume ref names in UTF-8.
object that exists, without requiring 'rev' to be a tag, and object that exists, without requiring 'rev' to be a tag, and
without dereferencing 'rev'; because a tag is already an object, without dereferencing 'rev'; because a tag is already an object,
it does not have to be dereferenced even once to get to an object. it does not have to be dereferenced even once to get to an object.
+
'rev{caret}\{tag\}' can be used to ensure that 'rev' identifies an
existing tag object.
'<rev>{caret}\{\}', e.g. 'v0.99.8{caret}\{\}':: '<rev>{caret}\{\}', e.g. 'v0.99.8{caret}\{\}'::
A suffix '{caret}' followed by an empty brace pair A suffix '{caret}' followed by an empty brace pair

View File

@ -679,6 +679,8 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
sp++; /* beginning of type name, or closing brace for empty */ sp++; /* beginning of type name, or closing brace for empty */
if (!strncmp(commit_type, sp, 6) && sp[6] == '}') if (!strncmp(commit_type, sp, 6) && sp[6] == '}')
expected_type = OBJ_COMMIT; expected_type = OBJ_COMMIT;
else if (!strncmp(tag_type, sp, 3) && sp[3] == '}')
expected_type = OBJ_TAG;
else if (!strncmp(tree_type, sp, 4) && sp[4] == '}') else if (!strncmp(tree_type, sp, 4) && sp[4] == '}')
expected_type = OBJ_TREE; expected_type = OBJ_TREE;
else if (!strncmp(blob_type, sp, 4) && sp[4] == '}') else if (!strncmp(blob_type, sp, 4) && sp[4] == '}')

View File

@ -54,6 +54,13 @@ test_expect_success 'ref^{tree}' '
test_must_fail git rev-parse blob-tag^{tree} test_must_fail git rev-parse blob-tag^{tree}
' '
test_expect_success 'ref^{tag}' '
test_must_fail git rev-parse HEAD^{tag} &&
git rev-parse commit-tag >expected &&
git rev-parse commit-tag^{tag} >actual &&
test_cmp expected actual
'
test_expect_success 'ref^{/.}' ' test_expect_success 'ref^{/.}' '
git rev-parse master >expected && git rev-parse master >expected &&
git rev-parse master^{/.} >actual && git rev-parse master^{/.} >actual &&