git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Add a "git-describe" command
@ 2005-12-24 21:50 Linus Torvalds
  2005-12-24 22:13 ` Linus Torvalds
  2005-12-25  1:42 ` Add a "git-describe" command Junio C Hamano
  0 siblings, 2 replies; 14+ messages in thread
From: Linus Torvalds @ 2005-12-24 21:50 UTC (permalink / raw)
  To: Junio C Hamano, Git Mailing List


It shows you the most recent tag that is reachable from a particular
commit is.

Maybe this is something that "git-name-rev" should be taught to do, 
instead of having a separate command for it. Regardless, I find it useful.

What it does is to take any random commit, and "name" it by looking up the 
most recent commit that is tagged and reachable from that commit. If the 
match is exact, it will just print out that ref-name directly. Otherwise 
it will print out the ref-name, followed by the 8-character "short SHA".

IOW, with something like Junios current tree, I get:

	[torvalds@g5 git]$ git-describe parent
	refs/tags/v1.0.4-g2414721b

ie the current head of my "parent" branch (ie Junio) is based on v1.0.4, 
but since it has a few commits on top of that, it has added the git hash 
of the thing to the end: "-g" + 8-char shorthand for the commit 
2414721b194453f058079d897d13c4e377f92dc6.

Doing a "git-describe" on a tag-name will just show the full tag path:

	[torvalds@g5 git]$ git-describe v1.0.4
	refs/tags/v1.0.4

unless there are _other_ tags pointing to that commit, in which case it 
will just choose one at random.

This is useful for two things:

 - automatic version naming in Makefiles, for example. We could use it in 
   git itself: when doing "git --version", we could use this to give a 
   much more useful description of exactly what version was installed.

 - for any random commit (say, you use "gitk <pathname>" or 
   "git-whatchanged" to look at what has changed in some file), you can 
   figure out what the last version of the repo was. Ie, say I find a bug 
   in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:

	[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6
	refs/tags/v2.6.14-rc4-g39ca371c

   and I now know that it was _not_ in v2.6.14-rc4, but was presumably in 
   v2.6.14-rc5.

The latter is useful when you want to see what "version timeframe" a 
commit happened in.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---

Comments?

			Linus

diff --git a/Makefile b/Makefile
index 3395a9e..47e7898 100644
--- a/Makefile
+++ b/Makefile
@@ -135,7 +135,8 @@ PROGRAMS = \
 	git-unpack-objects$X git-update-index$X git-update-server-info$X \
 	git-upload-pack$X git-verify-pack$X git-write-tree$X \
 	git-update-ref$X git-symbolic-ref$X git-check-ref-format$X \
-	git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X
+	git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \
+	git-describe$X
 
 # what 'all' will build and 'install' will install.
 ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS) git$X
diff --git a/describe.c b/describe.c
new file mode 100644
index 0000000..ebfa429
--- /dev/null
+++ b/describe.c
@@ -0,0 +1,118 @@
+#include "cache.h"
+#include "commit.h"
+#include "refs.h"
+
+#define SEEN (1u << 0)
+
+static const char describe_usage[] = "git-describe [--all] <committish>*";
+
+static int all = 0;	/* Default to tags only */
+
+static int names = 0, allocs = 0;
+static struct commit_name {
+	const struct commit *commit;
+	char path[];
+} **name_array = NULL;
+
+static struct commit_name *match(struct commit *cmit)
+{
+	int i = names;
+	struct commit_name **p = name_array;
+
+	while (i-- > 0) {
+		struct commit_name *n = *p++;
+		if (n->commit == cmit)
+			return n;
+	}
+	return NULL;
+}
+
+static void add_to_known_names(const char *path, const struct commit *commit)
+{
+	int idx;
+	int len = strlen(path)+1;
+	struct commit_name *name = xmalloc(sizeof(struct commit_name) + len);
+
+	name->commit = commit;
+	memcpy(name->path, path, len);
+	idx = names;
+	if (idx >= allocs) {
+		allocs = (idx + 50) * 3 / 2;
+		name_array = xrealloc(name_array, allocs*sizeof(*name_array));
+	}
+	name_array[idx] = name;
+	names = ++idx;
+}
+
+static int get_name(const char *path, const unsigned char *sha1)
+{
+	struct commit *commit = lookup_commit_reference_gently(sha1, 1);
+	if (!commit)
+		return 0;
+	if (!all && strncmp(path, "refs/tags/", 10))
+		return 0;
+	add_to_known_names(path, commit);
+	return 0;
+}
+
+static int compare_names(const void *_a, const void *_b)
+{
+	struct commit_name *a = *(struct commit_name **)_a;
+	struct commit_name *b = *(struct commit_name **)_b;
+	unsigned long a_date = a->commit->date;
+	unsigned long b_date = b->commit->date;
+	return (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;
+}
+
+static void describe(struct commit *cmit)
+{
+	struct commit_list *list;
+	static int initialized = 0;
+	struct commit_name *n;
+
+	if (!initialized) {
+		initialized = 1;
+		for_each_ref(get_name);
+		qsort(name_array, names, sizeof(*name_array), compare_names);
+	}
+
+	n = match(cmit);
+	if (n) {
+		printf("%s\n", n->path);
+		return;
+	}
+
+	list = NULL;
+	commit_list_insert(cmit, &list);
+	while (list) {
+		struct commit *c = pop_most_recent_commit(&list, SEEN);
+		n = match(c);
+		if (n) {
+			printf("%s-g%.8s\n", n->path, sha1_to_hex(cmit->object.sha1));
+			return;
+		}
+	}
+}
+
+int main(int argc, char **argv)
+{
+	int i;
+
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+		unsigned char sha1[20];
+		struct commit *cmit;
+
+		if (!strcmp(arg, "--all")) {
+			all = 1;
+			continue;
+		}
+		if (get_sha1(arg, sha1) < 0)
+			usage(describe_usage);
+		cmit = lookup_commit_reference(sha1);
+		if (!cmit)
+			usage(describe_usage);
+		describe(cmit);
+	}
+	return 0;
+}

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: Add a "git-describe" command
  2005-12-24 21:50 Add a "git-describe" command Linus Torvalds
@ 2005-12-24 22:13 ` Linus Torvalds
  2005-12-25 19:21   ` M_
                     ` (7 more replies)
  2005-12-25  1:42 ` Add a "git-describe" command Junio C Hamano
  1 sibling, 8 replies; 14+ messages in thread
From: Linus Torvalds @ 2005-12-24 22:13 UTC (permalink / raw)
  To: Junio C Hamano, Git Mailing List



On Sat, 24 Dec 2005, Linus Torvalds wrote:
> 
> This is useful for two things:
> 
>  - automatic version naming in Makefiles, for example. We could use it in 
>    git itself: when doing "git --version", we could use this to give a 
>    much more useful description of exactly what version was installed.

This trivial patch fails to do that correctly, but maybe somebody could 
fix it. 

The problem is not that it generates GIT_VERSION wrong. The problem is 
two-fold:
 - it should notice when "git-describe" doesn't exist, and fall back on 
   the old less-than-descriptive behaviour
 - it doesn't do dependencies correctly (ie it should now make "git" 
   depend on the version number, but it doesn't, so it doesn't re-build 
   git after a commit/pull)

but at least it shows the _idea_ of using git-describe.

With this I get

	[torvalds@g5 git]$ git --version
	git version v1.0.4-g6e9961d6

which I think is better than "1.0.GIT" which doesn't say anything about 
what the _actual_ version was.

(Ignore the particular SHA1 hash - it has my local commit that you can't 
re-create that just created that git-describe thing. You'll get your own 
version number).

		Linus

---
diff --git a/Makefile b/Makefile
index 47e7898..2e5c569 100644
--- a/Makefile
+++ b/Makefile
@@ -55,7 +55,7 @@ all:
 # Define USE_STDEV below if you want git to care about the underlying device
 # change being considered an inode change from the update-cache perspective.
 
-GIT_VERSION = 1.0.GIT
+GIT_VERSION = $(shell git-describe HEAD | sed 's:refs/tags/::')
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: Add a "git-describe" command
  2005-12-24 21:50 Add a "git-describe" command Linus Torvalds
  2005-12-24 22:13 ` Linus Torvalds
@ 2005-12-25  1:42 ` Junio C Hamano
  2005-12-25  3:46   ` Linus Torvalds
  1 sibling, 1 reply; 14+ messages in thread
From: Junio C Hamano @ 2005-12-25  1:42 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

Linus Torvalds <torvalds@osdl.org> writes:

> What it does is to take any random commit, and "name" it by looking up the 
> most recent commit that is tagged and reachable from that commit.

Sounds useful.

> Comments?

> +static struct commit_name {
> +	const struct commit *commit;
> +	char path[];
> +} **name_array = NULL;

I wonder if some tags are more important than others (we may
want to pick a signed tag that is a bit further down than an
autogenerated snapshot -git47 tag), but that depends on the
usage.  For bug hunting -git47 is more useful than sparsely done
signed tags e.g. -rc4.

> +static void describe(struct commit *cmit)
> +...
> +	list = NULL;
> +	commit_list_insert(cmit, &list);
> +	while (list) {
> +		struct commit *c = pop_most_recent_commit(&list, SEEN);
> +		n = match(c);
> +		if (n) {
> +			printf("%s-g%.8s\n", n->path, sha1_to_hex(cmit->object.sha1));
> +			return;
> +		}
> +	}
> +}

I think this leaks list elements but until/unless this is
libified we would not care too much about it.  We could use
find_unique_abbrev(cmit->object.sha1, 8) but probably it is an
overkill.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Add a "git-describe" command
  2005-12-25  1:42 ` Add a "git-describe" command Junio C Hamano
@ 2005-12-25  3:46   ` Linus Torvalds
  2005-12-25  9:44     ` Junio C Hamano
  0 siblings, 1 reply; 14+ messages in thread
From: Linus Torvalds @ 2005-12-25  3:46 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git



On Sat, 24 Dec 2005, Junio C Hamano wrote:
>
> I wonder if some tags are more important than others (we may
> want to pick a signed tag that is a bit further down than an
> autogenerated snapshot -git47 tag), but that depends on the
> usage.  For bug hunting -git47 is more useful than sparsely done
> signed tags e.g. -rc4.

I considered just printing every tag I could reach, and then you could do 

	git-describe xyz | head -1

to get the closest one.

But then I decided that almost always, you just want the most recent one. 
But we could add a "--history" cmd line option to show all the reachable 
ones (or limit it to <n> tags shown or something)..

But there's already some logic to cull out uninteresting references (ie 
the "--all" flag enables all kinds of references, normally we only look at 
tags), and yes, we could also just add some other culling logic. For 
example, maybe we only care about annotated tags (ie real tag objects with 
a message, rather than just direct references to commits).

My real goal was to see a real meaningful version when I do "git 
--version". I just hate how it normally just says it's version "1.0.GIT", 
and I have no idea how new/old it really is.

			Linus

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Add a "git-describe" command
  2005-12-25  3:46   ` Linus Torvalds
@ 2005-12-25  9:44     ` Junio C Hamano
  0 siblings, 0 replies; 14+ messages in thread
From: Junio C Hamano @ 2005-12-25  9:44 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

Linus Torvalds <torvalds@osdl.org> writes:

> My real goal was to see a real meaningful version when I do "git 
> --version". I just hate how it normally just says it's version "1.0.GIT", 
> and I have no idea how new/old it really is.

Hmph.  I am not so interested in "git --version", but I find
git-describe to be pretty attractive.

Last night I proposed to tighten pack naming which would promote
so-far just a convention to a rule, which would introduce an
backward incompatibility and wanted to know which released
versions are affected.  With git-whatchanged I can identify the
exact commit that changed the packname SHA1 computation with
ease:

        $ git whatchanged --abbrev --pretty=oneline \
          -S'	sorted_by_sha = create_sorted_list(sha1_sort);
                SHA1_Init(&ctx);
                list = sorted_by_sha;
                for (i = 0; i < nr_objects; i++) {
        ' HEAD -- pack-objects.c
        diff-tree 84c8d8a... (from 9cf6d33...)
        Fix packname hash generation.
        :100644 100644 3d62278... ef55cab... M	pack-objects.c

and from that I would have been able to find that the change was
between 0.99.8 and 0.99.9:

        $ git describe 84c8d8a
        refs/tags/v0.99.8-g84c8d8ae

I used "git-show-branch $that_commit tags/v0.99.?" to get that
information instead, but git describe would have been very
useful.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Add a "git-describe" command
  2005-12-24 22:13 ` Linus Torvalds
@ 2005-12-25 19:21   ` M_
  2005-12-28  0:42   ` Junio C Hamano
                     ` (6 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: M_ @ 2005-12-25 19:21 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds, Junio C Hamano

Alle 23:13, sabato 24 dicembre 2005, Linus Torvalds ha scritto:
>  - it should notice when "git-describe" doesn't exist, and fall back on
>    the old less-than-descriptive behaviour

And something like this?

GIT_VERSION = $(shell (git-describe HEAD || echo "1.0.GIT") | sed 's:refs/tags/::')

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Add a "git-describe" command
  2005-12-24 22:13 ` Linus Torvalds
  2005-12-25 19:21   ` M_
@ 2005-12-28  0:42   ` Junio C Hamano
  2005-12-28  2:05     ` Johannes Schindelin
  2005-12-28  0:42   ` [PATCH 1/6] git-describe: really prefer tags only Junio C Hamano
                     ` (5 subsequent siblings)
  7 siblings, 1 reply; 14+ messages in thread
From: Junio C Hamano @ 2005-12-28  0:42 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

Linus Torvalds <torvalds@osdl.org> writes:

> The problem is not that it generates GIT_VERSION wrong. The problem is 
> two-fold:
>  - it should notice when "git-describe" doesn't exist, and fall back on 
>    the old less-than-descriptive behaviour
>  - it doesn't do dependencies correctly (ie it should now make "git" 
>    depend on the version number, but it doesn't, so it doesn't re-build 
>    git after a commit/pull)
>
> but at least it shows the _idea_ of using git-describe.
>
> With this I get
>
> 	[torvalds@g5 git]$ git --version
> 	git version v1.0.4-g6e9961d6
>
> which I think is better than "1.0.GIT" which doesn't say anything about 
> what the _actual_ version was.

I do not think 1.0.GIT is a good name either, so obviously there
is a room for improvement.

One problem with git-describe is that getting tags is a concious
user action, and you need to do "git fetch --tags" from time to
time in order to see the v1.0.4-g6e9961d6 name.  It could well
say v1.0.3-g6649c466 if the end user has built on top of
otherwise fully up-to-date maint branch without fetching v1.0.4
nor v1.0.5 tags, so when we learn that the v1.0.3-g6649c466 does
not work for an end-user, it would not help us to look for
regression between v1.0.3 and v1.0.4.  All it tells us is that
it is not older than v1.0.3, and it may well be the v1.0.5
without any local modification.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 1/6] git-describe: really prefer tags only.
  2005-12-24 22:13 ` Linus Torvalds
  2005-12-25 19:21   ` M_
  2005-12-28  0:42   ` Junio C Hamano
@ 2005-12-28  0:42   ` Junio C Hamano
  2005-12-28  0:42   ` [PATCH 2/6] git-describe: use find_unique_abbrev() Junio C Hamano
                     ` (4 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Junio C Hamano @ 2005-12-28  0:42 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

Often there are references other than annotated tags under
refs/tags hierarchy that are used to "keep things just in case".
default to use annotated tags only, still leaving the option to
use any ref with --all flag.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 Linus Torvalds <torvalds@osdl.org> writes:

 > On Sat, 24 Dec 2005, Linus Torvalds wrote:
 >> 
 >> This is useful for two things:
 >> 
 >>  - automatic version naming in Makefiles, for example. We could use it in 
 >>    git itself: when doing "git --version", we could use this to give a 
 >>    much more useful description of exactly what version was installed.
 >
 > This trivial patch fails to do that correctly, but maybe somebody could 
 > fix it. 

 Here is a 6-patch series towards that.  Will be in the proposed
 updates later tonight.

 describe.c |   15 +++++++++++----
 1 files changed, 11 insertions(+), 4 deletions(-)

170c7e67e7792e0d5ce2328c1d7b8d4139a7c7e7
diff --git a/describe.c b/describe.c
index ebfa429..e1b6588 100644
--- a/describe.c
+++ b/describe.c
@@ -1,12 +1,13 @@
 #include "cache.h"
 #include "commit.h"
+#include "tag.h"
 #include "refs.h"
 
 #define SEEN (1u << 0)
 
 static const char describe_usage[] = "git-describe [--all] <committish>*";
 
-static int all = 0;	/* Default to tags only */
+static int all = 0;	/* Default to annotated tags only */
 
 static int names = 0, allocs = 0;
 static struct commit_name {
@@ -49,9 +50,15 @@ static int get_name(const char *path, co
 	struct commit *commit = lookup_commit_reference_gently(sha1, 1);
 	if (!commit)
 		return 0;
-	if (!all && strncmp(path, "refs/tags/", 10))
-		return 0;
-	add_to_known_names(path, commit);
+	if (!all) {
+		struct object *object;
+		if (strncmp(path, "refs/tags/", 10))
+			return 0;
+		object = parse_object(sha1);
+		if (object->type != tag_type)
+			return 0;
+	}
+	add_to_known_names(all ? path : path + 10, commit);
 	return 0;
 }
 
-- 
1.0.5-geb9d

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2/6] git-describe: use find_unique_abbrev()
  2005-12-24 22:13 ` Linus Torvalds
                     ` (2 preceding siblings ...)
  2005-12-28  0:42   ` [PATCH 1/6] git-describe: really prefer tags only Junio C Hamano
@ 2005-12-28  0:42   ` Junio C Hamano
  2005-12-28  0:42   ` [PATCH 3/6] git-describe: --tags and --abbrev Junio C Hamano
                     ` (3 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Junio C Hamano @ 2005-12-28  0:42 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

Just in case 8 hexadecimal digits are not enough.  We could use
shorter default if we wanted to.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 describe.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

298f9203cf85d5de28a8380bd26f85206530b7d0
diff --git a/describe.c b/describe.c
index e1b6588..ba49d00 100644
--- a/describe.c
+++ b/describe.c
@@ -95,7 +95,8 @@ static void describe(struct commit *cmit
 		struct commit *c = pop_most_recent_commit(&list, SEEN);
 		n = match(c);
 		if (n) {
-			printf("%s-g%.8s\n", n->path, sha1_to_hex(cmit->object.sha1));
+			printf("%s-g%s\n", n->path,
+			       find_unique_abbrev(cmit->object.sha1, 8));
 			return;
 		}
 	}
-- 
1.0.5-geb9d

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 3/6] git-describe: --tags and --abbrev
  2005-12-24 22:13 ` Linus Torvalds
                     ` (3 preceding siblings ...)
  2005-12-28  0:42   ` [PATCH 2/6] git-describe: use find_unique_abbrev() Junio C Hamano
@ 2005-12-28  0:42   ` Junio C Hamano
  2005-12-28  0:42   ` [PATCH 4/6] git-describe: still prefer annotated tag under --all and --tags Junio C Hamano
                     ` (2 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Junio C Hamano @ 2005-12-28  0:42 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

With --tags, not just annontated tags, but also any ref under
refs/tags/ are used to name the revision.

The number of digits is configurable with the --abbrev=<n> option.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 describe.c |   33 +++++++++++++++++++++++++++------
 1 files changed, 27 insertions(+), 6 deletions(-)

970d400993d27a3228bccd72c0ddba767ebbbfff
diff --git a/describe.c b/describe.c
index ba49d00..ee38f5f 100644
--- a/describe.c
+++ b/describe.c
@@ -5,9 +5,14 @@
 
 #define SEEN (1u << 0)
 
-static const char describe_usage[] = "git-describe [--all] <committish>*";
+static const char describe_usage[] =
+"git-describe [--all] [--tags] [--abbrev=<n>] <committish>*";
 
 static int all = 0;	/* Default to annotated tags only */
+static int tags = 0;	/* But allow any tags if --tags is specified */
+
+#define DEFAULT_ABBREV 8 /* maybe too many */
+static int abbrev = DEFAULT_ABBREV;
 
 static int names = 0, allocs = 0;
 static struct commit_name {
@@ -50,13 +55,19 @@ static int get_name(const char *path, co
 	struct commit *commit = lookup_commit_reference_gently(sha1, 1);
 	if (!commit)
 		return 0;
+	/* If --all, then any refs are used.
+	 * If --tags, then any tags are used.
+	 * Otherwise only annotated tags are used.
+	 */
 	if (!all) {
-		struct object *object;
 		if (strncmp(path, "refs/tags/", 10))
 			return 0;
-		object = parse_object(sha1);
-		if (object->type != tag_type)
-			return 0;
+		if (!tags) {
+			struct object *object;
+			object = parse_object(sha1);
+			if (object->type != tag_type)
+				return 0;
+		}
 	}
 	add_to_known_names(all ? path : path + 10, commit);
 	return 0;
@@ -96,7 +107,7 @@ static void describe(struct commit *cmit
 		n = match(c);
 		if (n) {
 			printf("%s-g%s\n", n->path,
-			       find_unique_abbrev(cmit->object.sha1, 8));
+			       find_unique_abbrev(cmit->object.sha1, abbrev));
 			return;
 		}
 	}
@@ -115,6 +126,16 @@ int main(int argc, char **argv)
 			all = 1;
 			continue;
 		}
+		if (!strcmp(arg, "--tags")) {
+			tags = 1;
+			continue;
+		}
+		if (!strncmp(arg, "--abbrev=", 9)) {
+			abbrev = strtoul(arg + 9, NULL, 10);
+			if (abbrev < 4 || 40 <= abbrev)
+				abbrev = DEFAULT_ABBREV;
+			continue;
+		}
 		if (get_sha1(arg, sha1) < 0)
 			usage(describe_usage);
 		cmit = lookup_commit_reference(sha1);
-- 
1.0.5-geb9d

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 4/6] git-describe: still prefer annotated tag under --all and --tags
  2005-12-24 22:13 ` Linus Torvalds
                     ` (4 preceding siblings ...)
  2005-12-28  0:42   ` [PATCH 3/6] git-describe: --tags and --abbrev Junio C Hamano
@ 2005-12-28  0:42   ` Junio C Hamano
  2005-12-28  0:42   ` [PATCH 5/6] git-describe: documentation Junio C Hamano
  2005-12-28  0:42   ` [PATCH 6/6] Makefile: use git-describe to mark the git version Junio C Hamano
  7 siblings, 0 replies; 14+ messages in thread
From: Junio C Hamano @ 2005-12-28  0:42 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

Even though --all and --tags can be used to include non
annotated tags in the reference point candidates, prefer to use
annotated tags if there are more than one refs that name the
same commit.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 describe.c |   34 +++++++++++++++++++++++++---------
 1 files changed, 25 insertions(+), 9 deletions(-)

43214fab3416d54dcf41a8f89c59484e9c930b23
diff --git a/describe.c b/describe.c
index ee38f5f..84d96b5 100644
--- a/describe.c
+++ b/describe.c
@@ -17,6 +17,7 @@ static int abbrev = DEFAULT_ABBREV;
 static int names = 0, allocs = 0;
 static struct commit_name {
 	const struct commit *commit;
+	int prio; /* annotated tag = 2, tag = 1, head = 0 */
 	char path[];
 } **name_array = NULL;
 
@@ -33,13 +34,16 @@ static struct commit_name *match(struct 
 	return NULL;
 }
 
-static void add_to_known_names(const char *path, const struct commit *commit)
+static void add_to_known_names(const char *path,
+			       const struct commit *commit,
+			       int prio)
 {
 	int idx;
 	int len = strlen(path)+1;
 	struct commit_name *name = xmalloc(sizeof(struct commit_name) + len);
 
 	name->commit = commit;
+	name->prio = prio; 
 	memcpy(name->path, path, len);
 	idx = names;
 	if (idx >= allocs) {
@@ -53,23 +57,32 @@ static void add_to_known_names(const cha
 static int get_name(const char *path, const unsigned char *sha1)
 {
 	struct commit *commit = lookup_commit_reference_gently(sha1, 1);
+	struct object *object;
+	int prio;
+
 	if (!commit)
 		return 0;
+	object = parse_object(sha1);
 	/* If --all, then any refs are used.
 	 * If --tags, then any tags are used.
 	 * Otherwise only annotated tags are used.
 	 */
+	if (!strncmp(path, "refs/tags/", 10)) {
+		if (object->type == tag_type)
+			prio = 2;
+		else
+			prio = 1;
+	}
+	else
+		prio = 0;
+
 	if (!all) {
-		if (strncmp(path, "refs/tags/", 10))
+		if (!prio)
+			return 0;
+		if (!tags && prio < 2)
 			return 0;
-		if (!tags) {
-			struct object *object;
-			object = parse_object(sha1);
-			if (object->type != tag_type)
-				return 0;
-		}
 	}
-	add_to_known_names(all ? path : path + 10, commit);
+	add_to_known_names(all ? path + 5 : path + 10, commit, prio);
 	return 0;
 }
 
@@ -79,6 +92,9 @@ static int compare_names(const void *_a,
 	struct commit_name *b = *(struct commit_name **)_b;
 	unsigned long a_date = a->commit->date;
 	unsigned long b_date = b->commit->date;
+
+	if (a->prio != b->prio)
+		return b->prio - a->prio;
 	return (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;
 }
 
-- 
1.0.5-geb9d

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 5/6] git-describe: documentation.
  2005-12-24 22:13 ` Linus Torvalds
                     ` (5 preceding siblings ...)
  2005-12-28  0:42   ` [PATCH 4/6] git-describe: still prefer annotated tag under --all and --tags Junio C Hamano
@ 2005-12-28  0:42   ` Junio C Hamano
  2005-12-28  0:42   ` [PATCH 6/6] Makefile: use git-describe to mark the git version Junio C Hamano
  7 siblings, 0 replies; 14+ messages in thread
From: Junio C Hamano @ 2005-12-28  0:42 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git


Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 Documentation/git-describe.txt |   79 ++++++++++++++++++++++++++++++++++++++++
 Documentation/git.txt          |    3 ++
 2 files changed, 82 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/git-describe.txt

82c11e802b05278d902138abc627982273b777c7
diff --git a/Documentation/git-describe.txt b/Documentation/git-describe.txt
new file mode 100644
index 0000000..0efe82a
--- /dev/null
+++ b/Documentation/git-describe.txt
@@ -0,0 +1,79 @@
+git-describe(1)
+===============
+
+NAME
+----
+git-describe - Show the most recent tag that is reachable from a commit.
+
+
+SYNOPSIS
+--------
+'git-describe' [--all] [--tags] [--abbrev=<n>] <committish>...
+
+DESCRIPTION
+-----------
+The command finds the most recent tag that is reachable from a
+commit, and if the commit itself is pointed at by the tag, shows
+the tag.  Otherwise, it suffixes the tag name with abbreviated
+object name of the commit.
+
+
+OPTIONS
+-------
+<committish>::
+	The object name of the comittish. 
+
+--all::
+	Instead of using only the annotated tags, use any ref
+	found in `.git/refs/`.
+
+--tags::
+	Instead of using only the annotated tags, use any tag
+	found in `.git/refs/tags`.
+
+--abbrev=<n>::
+	Instead of using the default 8 hexadecimal digits as the
+	abbreviated object name, use <n> digits.
+
+
+EXAMPLES
+--------
+
+With something like git.git current tree, I get:
+
+	[torvalds@g5 git]$ git-describe parent
+	v1.0.4-g2414721b
+
+i.e. the current head of my "parent" branch is based on v1.0.4,
+but since it has a few commits on top of that, it has added the
+git hash of the thing to the end: "-g" + 8-char shorthand for
+the commit `2414721b194453f058079d897d13c4e377f92dc6`.
+
+Doing a "git-describe" on a tag-name will just show the tag name:
+
+	[torvalds@g5 git]$ git-describe v1.0.4
+	v1.0.4
+
+With --all, the command can use branch heads as references, so
+the output shows the reference path as well:
+
+	[torvalds@g5 git]$ git describe --all --abbrev=4 v1.0.5^2
+	tags/v1.0.0-g975b
+
+	[torvalds@g5 git]$ git describe --all HEAD^
+	heads/lt/describe-g975b
+
+
+Author
+------
+Written by Linus Torvalds <torvalds@osdl.org>, but somewhat
+butchered by Junio C Hamano <junkio@cox.net>
+
+Documentation
+--------------
+Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the gitlink:git[7] suite
+
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 5f068c2..90c5bfa 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -139,6 +139,9 @@ Interrogation commands
 gitlink:git-cat-file[1]::
 	Provide content or type/size information for repository objects.
 
+gitlink:git-describe[1]::
+	Show the most recent tag that is reachable from a commit.
+
 gitlink:git-diff-index[1]::
 	Compares content and mode of blobs between the index and repository.
 
-- 
1.0.5-geb9d

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 6/6] Makefile: use git-describe to mark the git version.
  2005-12-24 22:13 ` Linus Torvalds
                     ` (6 preceding siblings ...)
  2005-12-28  0:42   ` [PATCH 5/6] git-describe: documentation Junio C Hamano
@ 2005-12-28  0:42   ` Junio C Hamano
  7 siblings, 0 replies; 14+ messages in thread
From: Junio C Hamano @ 2005-12-28  0:42 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

Note: with this commit, the GIT maintainer workflow must change.
GIT-VERSION-GEN is now the file to munge when the default
version needs to be changed, not Makefile.  The tag needs to be
pushed into the repository to build the official tarball and
binary package beforehand.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---
 * Only lightly tested.  Especially bootstrapping might be
   fishy, but I'll be heading off to Japan for fishful new year
   meals in a few days ;-), so...

 .gitignore      |    1 +
 GIT-VERSION-GEN |   18 ++++++++++++++++++
 Makefile        |   10 ++++++++--
 3 files changed, 27 insertions(+), 2 deletions(-)
 create mode 100755 GIT-VERSION-GEN

8e517cdeb5644b9857c8a9d8ce204ec9b7405297
diff --git a/.gitignore b/.gitignore
index 6bd508e..47d76f4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+GIT-VERSION-FILE
 git
 git-add
 git-am
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
new file mode 100755
index 0000000..196402c
--- /dev/null
+++ b/GIT-VERSION-GEN
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+GVF=GIT-VERSION-FILE
+
+VN=$(git describe --abbrev=4 HEAD 2>/dev/null) || VN=v1.0.GIT
+VN=$(expr "$VN" : v'\(.*\)')
+if test -r $GVF
+then
+	VC=$(sed -e 's/^GIT_VERSION = //' <$GVF)
+else
+	VC=unset
+fi
+test "$VN" = "$VC" || {
+	echo >&2 "GIT_VERSION = $VN"
+	echo "GIT_VERSION = $VN" >$GVF
+}
+
+
diff --git a/Makefile b/Makefile
index 47e7898..6f1d123 100644
--- a/Makefile
+++ b/Makefile
@@ -55,7 +55,9 @@ all:
 # Define USE_STDEV below if you want git to care about the underlying device
 # change being considered an inode change from the update-cache perspective.
 
-GIT_VERSION = 1.0.GIT
+GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
+	@sh ./GIT-VERSION-GEN
+-include GIT-VERSION-FILE
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
@@ -369,7 +371,7 @@ all: $(ALL_PROGRAMS)
 all:
 	$(MAKE) -C templates
 
-git$X: git.c $(LIB_FILE) Makefile
+git$X: git.c $(LIB_FILE) Makefile GIT-VERSION-FILE
 	$(CC) -DGIT_EXEC_PATH='"$(bindir)"' -DGIT_VERSION='"$(GIT_VERSION)"' \
 		$(CFLAGS) $(COMPAT_CFLAGS) -o $@ $(filter %.c,$^) $(LIB_FILE)
 
@@ -499,6 +501,7 @@ deb: dist
 ### Cleaning rules
 
 clean:
+	rm -f GIT-VERSION-FILE
 	rm -f *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o $(LIB_FILE)
 	rm -f $(PROGRAMS) $(SIMPLE_PROGRAMS) git$X
 	rm -f $(filter-out gitk,$(SCRIPTS))
@@ -511,3 +514,6 @@ clean:
 	$(MAKE) -C templates clean
 	$(MAKE) -C t/ clean
 
+.PHONY: all install clean
+.PHONY: .FORCE-GIT-VERSION-FILE
+
-- 
1.0.5-geb9d

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: Add a "git-describe" command
  2005-12-28  0:42   ` Junio C Hamano
@ 2005-12-28  2:05     ` Johannes Schindelin
  0 siblings, 0 replies; 14+ messages in thread
From: Johannes Schindelin @ 2005-12-28  2:05 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Hi,

On Tue, 27 Dec 2005, Junio C Hamano wrote:

> One problem with git-describe is that getting tags is a concious
> user action, and you need to do "git fetch --tags" from time to
> time in order to see the v1.0.4-g6e9961d6 name.

This is probably the biggest problem. I trust you to set the correct 
version in the Makefile just before tagging it.

Also, Linus hinted at similarities between git-describe and git-name-rev:

---
[PATCH] Teach name-rev to understand the "--inverse" flag

If "--inverse" is passed to name-rev, instead of naming the given revs
by the available refs, it does the opposite. The output is sorted by
distance, i.e. how many hops are between the rev and the ref. If the ref is
not an ancestor of the rev, the distance is inifinite, and the name is
undefined.

You can combine "--inverse" with "--tags", in effect getting the list of tags
ordered such that the tag describing the rev best comes first.

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>

---

	I guess this is what Linus has been hinting at when he said that
	git-name-rev could be adapted to achieve something similar to
	git-describe.

 name-rev.c |   85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 78 insertions(+), 7 deletions(-)

b1831f3f66f659445d2628dda73a1d79fc8c3b6f
diff --git a/name-rev.c b/name-rev.c
index 65333d4..4f7c04e 100644
--- a/name-rev.c
+++ b/name-rev.c
@@ -5,19 +5,21 @@
 #include "refs.h"
 
 static const char name_rev_usage[] =
-	"git-name-rev [--tags] ( --all | --stdin | commitish [commitish...] )\n";
+	"git-name-rev [--tags] ( --all | --stdin | \n"
+	"                       [--inverse] commitish [commitish...] )\n";
 
 typedef struct rev_name {
 	const char *tip_name;
 	int merge_traversals;
 	int generation;
+	int distance;
 } rev_name;
 
 static long cutoff = LONG_MAX;
 
 static void name_rev(struct commit *commit,
 		const char *tip_name, int merge_traversals, int generation,
-		int deref)
+		int distance, int deref)
 {
 	struct rev_name *name = (struct rev_name *)commit->object.util;
 	struct commit_list *parents;
@@ -50,6 +52,7 @@ copy_data:
 		name->tip_name = tip_name;
 		name->merge_traversals = merge_traversals;
 		name->generation = generation;
+		name->distance = distance;
 	} else
 		return;
 
@@ -66,10 +69,10 @@ copy_data:
 				sprintf(new_name, "%s^%d", tip_name, parent_number);
 
 			name_rev(parents->item, new_name,
-				merge_traversals + 1 , 0, 0);
+				merge_traversals + 1 , 0, distance + 1, 0);
 		} else {
 			name_rev(parents->item, tip_name, merge_traversals,
-				generation + 1, 0);
+				generation + 1, distance + 1, 0);
 		}
 	}
 }
@@ -98,7 +101,7 @@ static int name_ref(const char *path, co
 		while ((p = strchr(path, '/')))
 			path = p+1;
 
-		name_rev(commit, strdup(path), 0, 0, deref);
+		name_rev(commit, strdup(path), 0, 0, 0, deref);
 	}
 	return 0;
 }
@@ -118,12 +121,56 @@ static const char* get_rev_name(struct o
 
 	return buffer;
 }
-	
+
+typedef struct {
+	const char* name;
+	struct object* o;
+} named_commit_t;
+static named_commit_t* ref_list = NULL;
+static int ref_count = 0;
+
+static int inverse_build_ref_list(const char *path, const unsigned char *sha1)
+{
+	struct object *o = deref_tag(parse_object(sha1), path, 0);
+
+	if ((!tags_only || !strncmp(path, "refs/tags/", 10)) &&
+			o->type == commit_type) {
+		struct commit* commit = (struct commit*)o;
+
+		if (cutoff > commit->date)
+			cutoff = commit->date;
+
+		if ((ref_count % 256) == 0)
+			ref_list = xrealloc(ref_list,
+				sizeof(named_commit_t*) * (ref_count + 256));
+		ref_list[ref_count].name = strdup(path);
+		ref_list[ref_count].o = (struct object*)commit;
+		ref_count++;
+	}
+	return 0;
+}
+
+static int name_comp(const void* a, const void* b)
+{
+	const rev_name* c = ((const named_commit_t*)a)->o->util;
+	const rev_name* d = ((const named_commit_t*)b)->o->util;
+
+	if (!c)
+		return 1;
+	if (!d)
+		return -1;
+	if (c->distance > d->distance)
+		return 1;
+	if (c->distance < d->distance)
+		return -1;
+	return 0;
+}
+
 int main(int argc, char **argv)
 {
 	struct object_list *revs = NULL;
 	struct object_list **walker = &revs;
-	int as_is = 0, all = 0, transform_stdin = 0;
+	int as_is = 0, all = 0, inverse = 0, transform_stdin = 0;
 
 	setup_git_directory();
 
@@ -142,6 +189,9 @@ int main(int argc, char **argv)
 			} else if (!strcmp(*argv, "--tags")) {
 				tags_only = 1;
 				continue;
+			} else if (!strcmp(*argv, "--inverse")) {
+				inverse = 1;
+				continue;
 			} else if (!strcmp(*argv, "--all")) {
 				if (argc > 1)
 					die("Specify either a list, or --all, not both!");
@@ -181,6 +231,27 @@ int main(int argc, char **argv)
 		walker = &((*walker)->next);
 	}
 
+	if (inverse) {
+		int i;
+
+		if (transform_stdin || all || !revs)
+			usage(name_rev_usage);
+
+		for_each_ref(inverse_build_ref_list);
+		
+		tags_only = 0;
+		for (; revs; revs = revs->next)
+			name_ref(revs->name, revs->item->sha1);
+
+		qsort(ref_list, ref_count, sizeof(named_commit_t), name_comp);
+
+		for (i = 0; i < ref_count; i++)
+			printf("%s %s\n", ref_list[i].name,
+				get_rev_name(ref_list[i].o));
+
+		return 0;
+	}
+
 	for_each_ref(name_ref);
 
 	if (transform_stdin) {
-- 
1.0.GIT

^ permalink raw reply related	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2005-12-28  2:05 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-12-24 21:50 Add a "git-describe" command Linus Torvalds
2005-12-24 22:13 ` Linus Torvalds
2005-12-25 19:21   ` M_
2005-12-28  0:42   ` Junio C Hamano
2005-12-28  2:05     ` Johannes Schindelin
2005-12-28  0:42   ` [PATCH 1/6] git-describe: really prefer tags only Junio C Hamano
2005-12-28  0:42   ` [PATCH 2/6] git-describe: use find_unique_abbrev() Junio C Hamano
2005-12-28  0:42   ` [PATCH 3/6] git-describe: --tags and --abbrev Junio C Hamano
2005-12-28  0:42   ` [PATCH 4/6] git-describe: still prefer annotated tag under --all and --tags Junio C Hamano
2005-12-28  0:42   ` [PATCH 5/6] git-describe: documentation Junio C Hamano
2005-12-28  0:42   ` [PATCH 6/6] Makefile: use git-describe to mark the git version Junio C Hamano
2005-12-25  1:42 ` Add a "git-describe" command Junio C Hamano
2005-12-25  3:46   ` Linus Torvalds
2005-12-25  9:44     ` 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).