threads / patch / 2102

patchIntroduce notation "ref^{type}".

Subject: [PATCH] Introduce notation "ref^{type}".

## tl;dr

One message between Oct 14, 2005 and Oct 14, 2005. Diffs are folded; open one to read it.

replies: 0people: 1as markdown or json

Junio C Hamano· Oct 14, 2005, 06:03 UTC · lore

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 is another preparation, which is not strictly needed but
   for notational consistency.  The next one is the gem in the
   series -- upload-pack starts sending extra information on
   refs it has using this notation, so that client side can find
   out what each tag on the remote side refers to without first
   getting them.
 sha1_name.c |   83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 83 insertions(+), 0 deletions(-)

applies-to: 8edf2fed07b27673ab24e1bb40a0887f757d60b0 24552507a1fd71c707199bca0a225f2715a6759b

Show changes to sha1_name.c +83 −0
diff --git a/sha1_name.c b/sha1_name.c
index 4e9a052..75c688e 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)
 {
@@ -274,6 +277,82 @@ static int get_nth_ancestor(const char *
 	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;
@@ -315,6 +394,10 @@ static int get_sha1_1(const char *name, 
 		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;
---
@@GIT_VERSION@@

← back to recent threads