Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.kernel.org/pub/scm/git/git.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2005-10-16 04:14:10 +0400
committerJunio C Hamano <junkio@cox.net>2005-10-16 04:14:10 +0400
commit4baf5dda9e30ddc472bec444af7a572e5d3cb467 (patch)
tree361c7d681fc476d8ad07b622e519a46d98136d08
parent5a2e04d2031b229a242d07e11e514220e71a0d33 (diff)
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>
-rw-r--r--sha1_name.c83
1 files changed, 83 insertions, 0 deletions
diff --git a/sha1_name.c b/sha1_name.c
index f64755fbce..d0896f8183 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -1,5 +1,8 @@
#include "cache.h"
+#include "tag.h"
#include "commit.h"
+#include "tree.h"
+#include "blob.h"
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;
}
+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)
{
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);
}
+ ret = peel_onion(name, len, sha1);
+ if (!ret)
+ return 0;
+
ret = get_sha1_basic(name, len, sha1);
if (!ret)
return 0;