mirror of
https://github.com/git/git.git
synced 2024-11-07 09:43:00 +01:00
Introduce notation "ref^{type}".
Existing "tagname^0" notation means "dereference tag zero or more times until you cannot dereference it anymore, and make sure it is a commit -- otherwise barf". But tags do not necessarily reference commit objects. This commit introduces a bit more generalized notation, "ref^{type}". Existing "ref^0" is a shorthand for "ref^{commit}". If the type is empty, it just dereferences tags until it hits a non-tag object. With this, "git-rev-parse --verify 'junio-gpg-pub^{}'" shows the blob object name -- there is no need to manually read the tag object and find out the object name anymore. "git-rev-parse --verify 'HEAD^{tree}'" can be used to find out the tree object name of the HEAD commit. Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
parent
5a2e04d203
commit
4baf5dda9e
1 changed files with 83 additions and 0 deletions
83
sha1_name.c
83
sha1_name.c
|
@ -1,5 +1,8 @@
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
#include "tag.h"
|
||||||
#include "commit.h"
|
#include "commit.h"
|
||||||
|
#include "tree.h"
|
||||||
|
#include "blob.h"
|
||||||
|
|
||||||
static int find_short_object_filename(int len, const char *name, unsigned char *sha1)
|
static int find_short_object_filename(int len, const char *name, unsigned char *sha1)
|
||||||
{
|
{
|
||||||
|
@ -248,6 +251,82 @@ static int get_nth_ancestor(const char *name, int len,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int peel_onion(const char *name, int len, unsigned char *sha1)
|
||||||
|
{
|
||||||
|
unsigned char outer[20];
|
||||||
|
const char *sp;
|
||||||
|
const char *type_string = NULL;
|
||||||
|
struct object *o;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "ref^{type}" dereferences ref repeatedly until you cannot
|
||||||
|
* dereference anymore, or you get an object of given type,
|
||||||
|
* whichever comes first. "ref^{}" means just dereference
|
||||||
|
* tags until you get a non-tag. "ref^0" is a shorthand for
|
||||||
|
* "ref^{commit}". "commit^{tree}" could be used to find the
|
||||||
|
* top-level tree of the given commit.
|
||||||
|
*/
|
||||||
|
if (len < 4 || name[len-1] != '}')
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (sp = name + len - 1; name <= sp; sp--) {
|
||||||
|
int ch = *sp;
|
||||||
|
if (ch == '{' && name < sp && sp[-1] == '^')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (sp <= name)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
sp++; /* beginning of type name, or closing brace for empty */
|
||||||
|
if (!strncmp(commit_type, sp, 6) && sp[6] == '}')
|
||||||
|
type_string = commit_type;
|
||||||
|
else if (!strncmp(tree_type, sp, 4) && sp[4] == '}')
|
||||||
|
type_string = tree_type;
|
||||||
|
else if (!strncmp(blob_type, sp, 4) && sp[4] == '}')
|
||||||
|
type_string = blob_type;
|
||||||
|
else if (sp[0] == '}')
|
||||||
|
type_string = NULL;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (get_sha1_1(name, sp - name - 2, outer))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
o = parse_object(outer);
|
||||||
|
if (!o)
|
||||||
|
return -1;
|
||||||
|
if (!type_string) {
|
||||||
|
o = deref_tag(o);
|
||||||
|
memcpy(sha1, o->sha1, 20);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* At this point, the syntax look correct, so
|
||||||
|
* if we do not get the needed object, we should
|
||||||
|
* barf.
|
||||||
|
*/
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (!o)
|
||||||
|
return -1;
|
||||||
|
if (o->type == type_string) {
|
||||||
|
memcpy(sha1, o->sha1, 20);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (o->type == tag_type)
|
||||||
|
o = ((struct tag*) o)->tagged;
|
||||||
|
else if (o->type == commit_type)
|
||||||
|
o = &(((struct commit *) o)->tree->object);
|
||||||
|
else
|
||||||
|
return error("%.*s: expected %s type, but the object dereferences to %s type",
|
||||||
|
len, name, type_string,
|
||||||
|
o->type);
|
||||||
|
if (!o->parsed)
|
||||||
|
parse_object(o->sha1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int get_sha1_1(const char *name, int len, unsigned char *sha1)
|
static int get_sha1_1(const char *name, int len, unsigned char *sha1)
|
||||||
{
|
{
|
||||||
int parent, ret;
|
int parent, ret;
|
||||||
|
@ -289,6 +368,10 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1)
|
||||||
return get_nth_ancestor(name, len1, sha1, parent);
|
return get_nth_ancestor(name, len1, sha1, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = peel_onion(name, len, sha1);
|
||||||
|
if (!ret)
|
||||||
|
return 0;
|
||||||
|
|
||||||
ret = get_sha1_basic(name, len, sha1);
|
ret = get_sha1_basic(name, len, sha1);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue