git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Introduce notation "ref^{type}".
@ 2005-10-14  6:03 Junio C Hamano
  0 siblings, 0 replies; only message in thread
From: Junio C Hamano @ 2005-10-14  6:03 UTC (permalink / raw)
  To: git

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@@

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2005-10-14  6:04 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-10-14  6:03 [PATCH] Introduce notation "ref^{type}" Junio C Hamano

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).