git/list[1] front-page[2] threads[3] people[4] search[5] about
 

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

From
Junio C Hamano <junkio@cox.net>
Date
Oct 14, 2005, 06:03 UTC
Message-ID
<7vd5m8ws6y.fsf@assigned-by-dhcp.cox.net>

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

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@@
Message 1 of 1 in “Introduce notation "ref^{type}".”
  1. Introduce notation "ref^{type}".Junio C Hamano, Oct 14, 2005

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.