{"thread":{"id":"2927","subject":"Add a \"git-describe\" command","startedAt":"2005-12-24T21:50:45Z","lastAt":"2005-12-28T02:05:20Z","messageCount":14,"participants":["Linus Torvalds","Junio C Hamano","M_","Johannes Schindelin"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"14026","messageId":"Pine.LNX.4.64.0512241339120.14098@g5.osdl.org","threadId":"2927","inReplyTo":null,"subject":"Add a \"git-describe\" command","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-12-24T21:50:45Z","receivedAt":"2005-12-24T21:50:45Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nIt shows you the most recent tag that is reachable from a particular\ncommit is.\n\nMaybe this is something that \"git-name-rev\" should be taught to do, \ninstead of having a separate command for it. Regardless, I find it useful.\n\nWhat it does is to take any random commit, and \"name\" it by looking up the \nmost recent commit that is tagged and reachable from that commit. If the \nmatch is exact, it will just print out that ref-name directly. Otherwise \nit will print out the ref-name, followed by the 8-character \"short SHA\".\n\nIOW, with something like Junios current tree, I get:\n\n\t[torvalds@g5 git]$ git-describe parent\n\trefs/tags/v1.0.4-g2414721b\n\nie the current head of my \"parent\" branch (ie Junio) is based on v1.0.4, \nbut since it has a few commits on top of that, it has added the git hash \nof the thing to the end: \"-g\" + 8-char shorthand for the commit \n2414721b194453f058079d897d13c4e377f92dc6.\n\nDoing a \"git-describe\" on a tag-name will just show the full tag path:\n\n\t[torvalds@g5 git]$ git-describe v1.0.4\n\trefs/tags/v1.0.4\n\nunless there are _other_ tags pointing to that commit, in which case it \nwill just choose one at random.\n\nThis is useful for two things:\n\n - automatic version naming in Makefiles, for example. We could use it in \n   git itself: when doing \"git --version\", we could use this to give a \n   much more useful description of exactly what version was installed.\n\n - for any random commit (say, you use \"gitk <pathname>\" or \n   \"git-whatchanged\" to look at what has changed in some file), you can \n   figure out what the last version of the repo was. Ie, say I find a bug \n   in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:\n\n\t[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6\n\trefs/tags/v2.6.14-rc4-g39ca371c\n\n   and I now know that it was _not_ in v2.6.14-rc4, but was presumably in \n   v2.6.14-rc5.\n\nThe latter is useful when you want to see what \"version timeframe\" a \ncommit happened in.\n\nSigned-off-by: Linus Torvalds <torvalds@osdl.org>\n---\n\nComments?\n\n\t\t\tLinus\n\ndiff --git a/Makefile b/Makefile\nindex 3395a9e..47e7898 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -135,7 +135,8 @@ PROGRAMS = \\\n \tgit-unpack-objects$X git-update-index$X git-update-server-info$X \\\n \tgit-upload-pack$X git-verify-pack$X git-write-tree$X \\\n \tgit-update-ref$X git-symbolic-ref$X git-check-ref-format$X \\\n-\tgit-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X\n+\tgit-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \\\n+\tgit-describe$X\n \n # what 'all' will build and 'install' will install.\n ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS) git$X\ndiff --git a/describe.c b/describe.c\nnew file mode 100644\nindex 0000000..ebfa429\n--- /dev/null\n+++ b/describe.c\n@@ -0,0 +1,118 @@\n+#include \"cache.h\"\n+#include \"commit.h\"\n+#include \"refs.h\"\n+\n+#define SEEN (1u << 0)\n+\n+static const char describe_usage[] = \"git-describe [--all] <committish>*\";\n+\n+static int all = 0;\t/* Default to tags only */\n+\n+static int names = 0, allocs = 0;\n+static struct commit_name {\n+\tconst struct commit *commit;\n+\tchar path[];\n+} **name_array = NULL;\n+\n+static struct commit_name *match(struct commit *cmit)\n+{\n+\tint i = names;\n+\tstruct commit_name **p = name_array;\n+\n+\twhile (i-- > 0) {\n+\t\tstruct commit_name *n = *p++;\n+\t\tif (n->commit == cmit)\n+\t\t\treturn n;\n+\t}\n+\treturn NULL;\n+}\n+\n+static void add_to_known_names(const char *path, const struct commit *commit)\n+{\n+\tint idx;\n+\tint len = strlen(path)+1;\n+\tstruct commit_name *name = xmalloc(sizeof(struct commit_name) + len);\n+\n+\tname->commit = commit;\n+\tmemcpy(name->path, path, len);\n+\tidx = names;\n+\tif (idx >= allocs) {\n+\t\tallocs = (idx + 50) * 3 / 2;\n+\t\tname_array = xrealloc(name_array, allocs*sizeof(*name_array));\n+\t}\n+\tname_array[idx] = name;\n+\tnames = ++idx;\n+}\n+\n+static int get_name(const char *path, const unsigned char *sha1)\n+{\n+\tstruct commit *commit = lookup_commit_reference_gently(sha1, 1);\n+\tif (!commit)\n+\t\treturn 0;\n+\tif (!all && strncmp(path, \"refs/tags/\", 10))\n+\t\treturn 0;\n+\tadd_to_known_names(path, commit);\n+\treturn 0;\n+}\n+\n+static int compare_names(const void *_a, const void *_b)\n+{\n+\tstruct commit_name *a = *(struct commit_name **)_a;\n+\tstruct commit_name *b = *(struct commit_name **)_b;\n+\tunsigned long a_date = a->commit->date;\n+\tunsigned long b_date = b->commit->date;\n+\treturn (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;\n+}\n+\n+static void describe(struct commit *cmit)\n+{\n+\tstruct commit_list *list;\n+\tstatic int initialized = 0;\n+\tstruct commit_name *n;\n+\n+\tif (!initialized) {\n+\t\tinitialized = 1;\n+\t\tfor_each_ref(get_name);\n+\t\tqsort(name_array, names, sizeof(*name_array), compare_names);\n+\t}\n+\n+\tn = match(cmit);\n+\tif (n) {\n+\t\tprintf(\"%s\\n\", n->path);\n+\t\treturn;\n+\t}\n+\n+\tlist = NULL;\n+\tcommit_list_insert(cmit, &list);\n+\twhile (list) {\n+\t\tstruct commit *c = pop_most_recent_commit(&list, SEEN);\n+\t\tn = match(c);\n+\t\tif (n) {\n+\t\t\tprintf(\"%s-g%.8s\\n\", n->path, sha1_to_hex(cmit->object.sha1));\n+\t\t\treturn;\n+\t\t}\n+\t}\n+}\n+\n+int main(int argc, char **argv)\n+{\n+\tint i;\n+\n+\tfor (i = 1; i < argc; i++) {\n+\t\tconst char *arg = argv[i];\n+\t\tunsigned char sha1[20];\n+\t\tstruct commit *cmit;\n+\n+\t\tif (!strcmp(arg, \"--all\")) {\n+\t\t\tall = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (get_sha1(arg, sha1) < 0)\n+\t\t\tusage(describe_usage);\n+\t\tcmit = lookup_commit_reference(sha1);\n+\t\tif (!cmit)\n+\t\t\tusage(describe_usage);\n+\t\tdescribe(cmit);\n+\t}\n+\treturn 0;\n+}\n"},{"id":"14027","messageId":"Pine.LNX.4.64.0512241409300.14098@g5.osdl.org","threadId":"2927","inReplyTo":"Pine.LNX.4.64.0512241339120.14098@g5.osdl.org","subject":"Re: Add a \"git-describe\" command","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-12-24T22:13:25Z","receivedAt":"2005-12-24T22:13:25Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sat, 24 Dec 2005, Linus Torvalds wrote:\n> \n> This is useful for two things:\n> \n>  - automatic version naming in Makefiles, for example. We could use it in \n>    git itself: when doing \"git --version\", we could use this to give a \n>    much more useful description of exactly what version was installed.\n\nThis trivial patch fails to do that correctly, but maybe somebody could \nfix it. \n\nThe problem is not that it generates GIT_VERSION wrong. The problem is \ntwo-fold:\n - it should notice when \"git-describe\" doesn't exist, and fall back on \n   the old less-than-descriptive behaviour\n - it doesn't do dependencies correctly (ie it should now make \"git\" \n   depend on the version number, but it doesn't, so it doesn't re-build \n   git after a commit/pull)\n\nbut at least it shows the _idea_ of using git-describe.\n\nWith this I get\n\n\t[torvalds@g5 git]$ git --version\n\tgit version v1.0.4-g6e9961d6\n\nwhich I think is better than \"1.0.GIT\" which doesn't say anything about \nwhat the _actual_ version was.\n\n(Ignore the particular SHA1 hash - it has my local commit that you can't \nre-create that just created that git-describe thing. You'll get your own \nversion number).\n\n\t\tLinus\n\n---\ndiff --git a/Makefile b/Makefile\nindex 47e7898..2e5c569 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -55,7 +55,7 @@ all:\n # Define USE_STDEV below if you want git to care about the underlying device\n # change being considered an inode change from the update-cache perspective.\n \n-GIT_VERSION = 1.0.GIT\n+GIT_VERSION = $(shell git-describe HEAD | sed 's:refs/tags/::')\n \n # CFLAGS and LDFLAGS are for the users to override from the command line.\n \n"},{"id":"14029","messageId":"7v4q4yq7f2.fsf@assigned-by-dhcp.cox.net","threadId":"2927","inReplyTo":"Pine.LNX.4.64.0512241339120.14098@g5.osdl.org","subject":"Re: Add a \"git-describe\" command","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-25T01:42:09Z","receivedAt":"2005-12-25T01:42:09Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> What it does is to take any random commit, and \"name\" it by looking up the \n> most recent commit that is tagged and reachable from that commit.\n\nSounds useful.\n\n> Comments?\n\n> +static struct commit_name {\n> +\tconst struct commit *commit;\n> +\tchar path[];\n> +} **name_array = NULL;\n\nI wonder if some tags are more important than others (we may\nwant to pick a signed tag that is a bit further down than an\nautogenerated snapshot -git47 tag), but that depends on the\nusage.  For bug hunting -git47 is more useful than sparsely done\nsigned tags e.g. -rc4.\n\n> +static void describe(struct commit *cmit)\n> +...\n> +\tlist = NULL;\n> +\tcommit_list_insert(cmit, &list);\n> +\twhile (list) {\n> +\t\tstruct commit *c = pop_most_recent_commit(&list, SEEN);\n> +\t\tn = match(c);\n> +\t\tif (n) {\n> +\t\t\tprintf(\"%s-g%.8s\\n\", n->path, sha1_to_hex(cmit->object.sha1));\n> +\t\t\treturn;\n> +\t\t}\n> +\t}\n> +}\n\nI think this leaks list elements but until/unless this is\nlibified we would not care too much about it.  We could use\nfind_unique_abbrev(cmit->object.sha1, 8) but probably it is an\noverkill.\n"},{"id":"14031","messageId":"Pine.LNX.4.64.0512241939490.14098@g5.osdl.org","threadId":"2927","inReplyTo":"7v4q4yq7f2.fsf@assigned-by-dhcp.cox.net","subject":"Re: Add a \"git-describe\" command","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-12-25T03:46:22Z","receivedAt":"2005-12-25T03:46:22Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sat, 24 Dec 2005, Junio C Hamano wrote:\n>\n> I wonder if some tags are more important than others (we may\n> want to pick a signed tag that is a bit further down than an\n> autogenerated snapshot -git47 tag), but that depends on the\n> usage.  For bug hunting -git47 is more useful than sparsely done\n> signed tags e.g. -rc4.\n\nI considered just printing every tag I could reach, and then you could do \n\n\tgit-describe xyz | head -1\n\nto get the closest one.\n\nBut then I decided that almost always, you just want the most recent one. \nBut we could add a \"--history\" cmd line option to show all the reachable \nones (or limit it to <n> tags shown or something)..\n\nBut there's already some logic to cull out uninteresting references (ie \nthe \"--all\" flag enables all kinds of references, normally we only look at \ntags), and yes, we could also just add some other culling logic. For \nexample, maybe we only care about annotated tags (ie real tag objects with \na message, rather than just direct references to commits).\n\nMy real goal was to see a real meaningful version when I do \"git \n--version\". I just hate how it normally just says it's version \"1.0.GIT\", \nand I have no idea how new/old it really is.\n\n\t\t\tLinus\n"},{"id":"14032","messageId":"7vr781o6j9.fsf@assigned-by-dhcp.cox.net","threadId":"2927","inReplyTo":"Pine.LNX.4.64.0512241939490.14098@g5.osdl.org","subject":"Re: Add a \"git-describe\" command","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-25T09:44:10Z","receivedAt":"2005-12-25T09:44:10Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> My real goal was to see a real meaningful version when I do \"git \n> --version\". I just hate how it normally just says it's version \"1.0.GIT\", \n> and I have no idea how new/old it really is.\n\nHmph.  I am not so interested in \"git --version\", but I find\ngit-describe to be pretty attractive.\n\nLast night I proposed to tighten pack naming which would promote\nso-far just a convention to a rule, which would introduce an\nbackward incompatibility and wanted to know which released\nversions are affected.  With git-whatchanged I can identify the\nexact commit that changed the packname SHA1 computation with\nease:\n\n        $ git whatchanged --abbrev --pretty=oneline \\\n          -S'\tsorted_by_sha = create_sorted_list(sha1_sort);\n                SHA1_Init(&ctx);\n                list = sorted_by_sha;\n                for (i = 0; i < nr_objects; i++) {\n        ' HEAD -- pack-objects.c\n        diff-tree 84c8d8a... (from 9cf6d33...)\n        Fix packname hash generation.\n        :100644 100644 3d62278... ef55cab... M\tpack-objects.c\n\nand from that I would have been able to find that the change was\nbetween 0.99.8 and 0.99.9:\n\n        $ git describe 84c8d8a\n        refs/tags/v0.99.8-g84c8d8ae\n\nI used \"git-show-branch $that_commit tags/v0.99.?\" to get that\ninformation instead, but git describe would have been very\nuseful.\n"},{"id":"14038","messageId":"200512252021.09481.barra_cuda@katamail.com","threadId":"2927","inReplyTo":"Pine.LNX.4.64.0512241409300.14098@g5.osdl.org","subject":"Re: Add a \"git-describe\" command","fromName":"M_","fromEmail":"barra_cuda@katamail.com","sentAt":"2005-12-25T19:21:09Z","receivedAt":"2005-12-25T19:21:09Z","isPatch":false,"sender":{"key":"barra_cuda@katamail.com","avatar":"https://avatars.githubusercontent.com/u/16371673?v=4"},"body":"Alle 23:13, sabato 24 dicembre 2005, Linus Torvalds ha scritto:\n>  - it should notice when \"git-describe\" doesn't exist, and fall back on\n>    the old less-than-descriptive behaviour\n\nAnd something like this?\n\nGIT_VERSION = $(shell (git-describe HEAD || echo \"1.0.GIT\") | sed 's:refs/tags/::')\n"},{"id":"14077","messageId":"7v7j9q3vdu.fsf@assigned-by-dhcp.cox.net","threadId":"2927","inReplyTo":"Pine.LNX.4.64.0512241409300.14098@g5.osdl.org","subject":"Re: Add a \"git-describe\" command","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-28T00:42:05Z","receivedAt":"2005-12-28T00:42:05Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> The problem is not that it generates GIT_VERSION wrong. The problem is \n> two-fold:\n>  - it should notice when \"git-describe\" doesn't exist, and fall back on \n>    the old less-than-descriptive behaviour\n>  - it doesn't do dependencies correctly (ie it should now make \"git\" \n>    depend on the version number, but it doesn't, so it doesn't re-build \n>    git after a commit/pull)\n>\n> but at least it shows the _idea_ of using git-describe.\n>\n> With this I get\n>\n> \t[torvalds@g5 git]$ git --version\n> \tgit version v1.0.4-g6e9961d6\n>\n> which I think is better than \"1.0.GIT\" which doesn't say anything about \n> what the _actual_ version was.\n\nI do not think 1.0.GIT is a good name either, so obviously there\nis a room for improvement.\n\nOne problem with git-describe is that getting tags is a concious\nuser action, and you need to do \"git fetch --tags\" from time to\ntime in order to see the v1.0.4-g6e9961d6 name.  It could well\nsay v1.0.3-g6649c466 if the end user has built on top of\notherwise fully up-to-date maint branch without fetching v1.0.4\nnor v1.0.5 tags, so when we learn that the v1.0.3-g6649c466 does\nnot work for an end-user, it would not help us to look for\nregression between v1.0.3 and v1.0.4.  All it tells us is that\nit is not older than v1.0.3, and it may well be the v1.0.5\nwithout any local modification.\n"},{"id":"14074","messageId":"7v1wzy3vdl.fsf@assigned-by-dhcp.cox.net","threadId":"2927","inReplyTo":"Pine.LNX.4.64.0512241409300.14098@g5.osdl.org","subject":"[PATCH 1/6] git-describe: really prefer tags only.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-28T00:42:14Z","receivedAt":"2005-12-28T00:42:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Often there are references other than annotated tags under\nrefs/tags hierarchy that are used to \"keep things just in case\".\ndefault to use annotated tags only, still leaving the option to\nuse any ref with --all flag.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n Linus Torvalds <torvalds@osdl.org> writes:\n\n > On Sat, 24 Dec 2005, Linus Torvalds wrote:\n >> \n >> This is useful for two things:\n >> \n >>  - automatic version naming in Makefiles, for example. We could use it in \n >>    git itself: when doing \"git --version\", we could use this to give a \n >>    much more useful description of exactly what version was installed.\n >\n > This trivial patch fails to do that correctly, but maybe somebody could \n > fix it. \n\n Here is a 6-patch series towards that.  Will be in the proposed\n updates later tonight.\n\n describe.c |   15 +++++++++++----\n 1 files changed, 11 insertions(+), 4 deletions(-)\n\n170c7e67e7792e0d5ce2328c1d7b8d4139a7c7e7\ndiff --git a/describe.c b/describe.c\nindex ebfa429..e1b6588 100644\n--- a/describe.c\n+++ b/describe.c\n@@ -1,12 +1,13 @@\n #include \"cache.h\"\n #include \"commit.h\"\n+#include \"tag.h\"\n #include \"refs.h\"\n \n #define SEEN (1u << 0)\n \n static const char describe_usage[] = \"git-describe [--all] <committish>*\";\n \n-static int all = 0;\t/* Default to tags only */\n+static int all = 0;\t/* Default to annotated tags only */\n \n static int names = 0, allocs = 0;\n static struct commit_name {\n@@ -49,9 +50,15 @@ static int get_name(const char *path, co\n \tstruct commit *commit = lookup_commit_reference_gently(sha1, 1);\n \tif (!commit)\n \t\treturn 0;\n-\tif (!all && strncmp(path, \"refs/tags/\", 10))\n-\t\treturn 0;\n-\tadd_to_known_names(path, commit);\n+\tif (!all) {\n+\t\tstruct object *object;\n+\t\tif (strncmp(path, \"refs/tags/\", 10))\n+\t\t\treturn 0;\n+\t\tobject = parse_object(sha1);\n+\t\tif (object->type != tag_type)\n+\t\t\treturn 0;\n+\t}\n+\tadd_to_known_names(all ? path : path + 10, commit);\n \treturn 0;\n }\n \n-- \n1.0.5-geb9d\n"},{"id":"14075","messageId":"7vvexa2gsw.fsf@assigned-by-dhcp.cox.net","threadId":"2927","inReplyTo":"Pine.LNX.4.64.0512241409300.14098@g5.osdl.org","subject":"[PATCH 2/6] git-describe: use find_unique_abbrev()","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-28T00:42:23Z","receivedAt":"2005-12-28T00:42:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Just in case 8 hexadecimal digits are not enough.  We could use\nshorter default if we wanted to.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n describe.c |    3 ++-\n 1 files changed, 2 insertions(+), 1 deletions(-)\n\n298f9203cf85d5de28a8380bd26f85206530b7d0\ndiff --git a/describe.c b/describe.c\nindex e1b6588..ba49d00 100644\n--- a/describe.c\n+++ b/describe.c\n@@ -95,7 +95,8 @@ static void describe(struct commit *cmit\n \t\tstruct commit *c = pop_most_recent_commit(&list, SEEN);\n \t\tn = match(c);\n \t\tif (n) {\n-\t\t\tprintf(\"%s-g%.8s\\n\", n->path, sha1_to_hex(cmit->object.sha1));\n+\t\t\tprintf(\"%s-g%s\\n\", n->path,\n+\t\t\t       find_unique_abbrev(cmit->object.sha1, 8));\n \t\t\treturn;\n \t\t}\n \t}\n-- \n1.0.5-geb9d\n"},{"id":"14072","messageId":"7vpsni2gso.fsf@assigned-by-dhcp.cox.net","threadId":"2927","inReplyTo":"Pine.LNX.4.64.0512241409300.14098@g5.osdl.org","subject":"[PATCH 3/6] git-describe: --tags and --abbrev","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-28T00:42:31Z","receivedAt":"2005-12-28T00:42:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"With --tags, not just annontated tags, but also any ref under\nrefs/tags/ are used to name the revision.\n\nThe number of digits is configurable with the --abbrev=<n> option.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n describe.c |   33 +++++++++++++++++++++++++++------\n 1 files changed, 27 insertions(+), 6 deletions(-)\n\n970d400993d27a3228bccd72c0ddba767ebbbfff\ndiff --git a/describe.c b/describe.c\nindex ba49d00..ee38f5f 100644\n--- a/describe.c\n+++ b/describe.c\n@@ -5,9 +5,14 @@\n \n #define SEEN (1u << 0)\n \n-static const char describe_usage[] = \"git-describe [--all] <committish>*\";\n+static const char describe_usage[] =\n+\"git-describe [--all] [--tags] [--abbrev=<n>] <committish>*\";\n \n static int all = 0;\t/* Default to annotated tags only */\n+static int tags = 0;\t/* But allow any tags if --tags is specified */\n+\n+#define DEFAULT_ABBREV 8 /* maybe too many */\n+static int abbrev = DEFAULT_ABBREV;\n \n static int names = 0, allocs = 0;\n static struct commit_name {\n@@ -50,13 +55,19 @@ static int get_name(const char *path, co\n \tstruct commit *commit = lookup_commit_reference_gently(sha1, 1);\n \tif (!commit)\n \t\treturn 0;\n+\t/* If --all, then any refs are used.\n+\t * If --tags, then any tags are used.\n+\t * Otherwise only annotated tags are used.\n+\t */\n \tif (!all) {\n-\t\tstruct object *object;\n \t\tif (strncmp(path, \"refs/tags/\", 10))\n \t\t\treturn 0;\n-\t\tobject = parse_object(sha1);\n-\t\tif (object->type != tag_type)\n-\t\t\treturn 0;\n+\t\tif (!tags) {\n+\t\t\tstruct object *object;\n+\t\t\tobject = parse_object(sha1);\n+\t\t\tif (object->type != tag_type)\n+\t\t\t\treturn 0;\n+\t\t}\n \t}\n \tadd_to_known_names(all ? path : path + 10, commit);\n \treturn 0;\n@@ -96,7 +107,7 @@ static void describe(struct commit *cmit\n \t\tn = match(c);\n \t\tif (n) {\n \t\t\tprintf(\"%s-g%s\\n\", n->path,\n-\t\t\t       find_unique_abbrev(cmit->object.sha1, 8));\n+\t\t\t       find_unique_abbrev(cmit->object.sha1, abbrev));\n \t\t\treturn;\n \t\t}\n \t}\n@@ -115,6 +126,16 @@ int main(int argc, char **argv)\n \t\t\tall = 1;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strcmp(arg, \"--tags\")) {\n+\t\t\ttags = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strncmp(arg, \"--abbrev=\", 9)) {\n+\t\t\tabbrev = strtoul(arg + 9, NULL, 10);\n+\t\t\tif (abbrev < 4 || 40 <= abbrev)\n+\t\t\t\tabbrev = DEFAULT_ABBREV;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (get_sha1(arg, sha1) < 0)\n \t\t\tusage(describe_usage);\n \t\tcmit = lookup_commit_reference(sha1);\n-- \n1.0.5-geb9d\n"},{"id":"14076","messageId":"7vk6dq2gsg.fsf@assigned-by-dhcp.cox.net","threadId":"2927","inReplyTo":"Pine.LNX.4.64.0512241409300.14098@g5.osdl.org","subject":"[PATCH 4/6] git-describe: still prefer annotated tag under --all and --tags","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-28T00:42:39Z","receivedAt":"2005-12-28T00:42:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Even though --all and --tags can be used to include non\nannotated tags in the reference point candidates, prefer to use\nannotated tags if there are more than one refs that name the\nsame commit.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n describe.c |   34 +++++++++++++++++++++++++---------\n 1 files changed, 25 insertions(+), 9 deletions(-)\n\n43214fab3416d54dcf41a8f89c59484e9c930b23\ndiff --git a/describe.c b/describe.c\nindex ee38f5f..84d96b5 100644\n--- a/describe.c\n+++ b/describe.c\n@@ -17,6 +17,7 @@ static int abbrev = DEFAULT_ABBREV;\n static int names = 0, allocs = 0;\n static struct commit_name {\n \tconst struct commit *commit;\n+\tint prio; /* annotated tag = 2, tag = 1, head = 0 */\n \tchar path[];\n } **name_array = NULL;\n \n@@ -33,13 +34,16 @@ static struct commit_name *match(struct \n \treturn NULL;\n }\n \n-static void add_to_known_names(const char *path, const struct commit *commit)\n+static void add_to_known_names(const char *path,\n+\t\t\t       const struct commit *commit,\n+\t\t\t       int prio)\n {\n \tint idx;\n \tint len = strlen(path)+1;\n \tstruct commit_name *name = xmalloc(sizeof(struct commit_name) + len);\n \n \tname->commit = commit;\n+\tname->prio = prio; \n \tmemcpy(name->path, path, len);\n \tidx = names;\n \tif (idx >= allocs) {\n@@ -53,23 +57,32 @@ static void add_to_known_names(const cha\n static int get_name(const char *path, const unsigned char *sha1)\n {\n \tstruct commit *commit = lookup_commit_reference_gently(sha1, 1);\n+\tstruct object *object;\n+\tint prio;\n+\n \tif (!commit)\n \t\treturn 0;\n+\tobject = parse_object(sha1);\n \t/* If --all, then any refs are used.\n \t * If --tags, then any tags are used.\n \t * Otherwise only annotated tags are used.\n \t */\n+\tif (!strncmp(path, \"refs/tags/\", 10)) {\n+\t\tif (object->type == tag_type)\n+\t\t\tprio = 2;\n+\t\telse\n+\t\t\tprio = 1;\n+\t}\n+\telse\n+\t\tprio = 0;\n+\n \tif (!all) {\n-\t\tif (strncmp(path, \"refs/tags/\", 10))\n+\t\tif (!prio)\n+\t\t\treturn 0;\n+\t\tif (!tags && prio < 2)\n \t\t\treturn 0;\n-\t\tif (!tags) {\n-\t\t\tstruct object *object;\n-\t\t\tobject = parse_object(sha1);\n-\t\t\tif (object->type != tag_type)\n-\t\t\t\treturn 0;\n-\t\t}\n \t}\n-\tadd_to_known_names(all ? path : path + 10, commit);\n+\tadd_to_known_names(all ? path + 5 : path + 10, commit, prio);\n \treturn 0;\n }\n \n@@ -79,6 +92,9 @@ static int compare_names(const void *_a,\n \tstruct commit_name *b = *(struct commit_name **)_b;\n \tunsigned long a_date = a->commit->date;\n \tunsigned long b_date = b->commit->date;\n+\n+\tif (a->prio != b->prio)\n+\t\treturn b->prio - a->prio;\n \treturn (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;\n }\n \n-- \n1.0.5-geb9d\n"},{"id":"14078","messageId":"7vek3y2gs8.fsf@assigned-by-dhcp.cox.net","threadId":"2927","inReplyTo":"Pine.LNX.4.64.0512241409300.14098@g5.osdl.org","subject":"[PATCH 5/6] git-describe: documentation.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-28T00:42:47Z","receivedAt":"2005-12-28T00:42:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n Documentation/git-describe.txt |   79 ++++++++++++++++++++++++++++++++++++++++\n Documentation/git.txt          |    3 ++\n 2 files changed, 82 insertions(+), 0 deletions(-)\n create mode 100644 Documentation/git-describe.txt\n\n82c11e802b05278d902138abc627982273b777c7\ndiff --git a/Documentation/git-describe.txt b/Documentation/git-describe.txt\nnew file mode 100644\nindex 0000000..0efe82a\n--- /dev/null\n+++ b/Documentation/git-describe.txt\n@@ -0,0 +1,79 @@\n+git-describe(1)\n+===============\n+\n+NAME\n+----\n+git-describe - Show the most recent tag that is reachable from a commit.\n+\n+\n+SYNOPSIS\n+--------\n+'git-describe' [--all] [--tags] [--abbrev=<n>] <committish>...\n+\n+DESCRIPTION\n+-----------\n+The command finds the most recent tag that is reachable from a\n+commit, and if the commit itself is pointed at by the tag, shows\n+the tag.  Otherwise, it suffixes the tag name with abbreviated\n+object name of the commit.\n+\n+\n+OPTIONS\n+-------\n+<committish>::\n+\tThe object name of the comittish. \n+\n+--all::\n+\tInstead of using only the annotated tags, use any ref\n+\tfound in `.git/refs/`.\n+\n+--tags::\n+\tInstead of using only the annotated tags, use any tag\n+\tfound in `.git/refs/tags`.\n+\n+--abbrev=<n>::\n+\tInstead of using the default 8 hexadecimal digits as the\n+\tabbreviated object name, use <n> digits.\n+\n+\n+EXAMPLES\n+--------\n+\n+With something like git.git current tree, I get:\n+\n+\t[torvalds@g5 git]$ git-describe parent\n+\tv1.0.4-g2414721b\n+\n+i.e. the current head of my \"parent\" branch is based on v1.0.4,\n+but since it has a few commits on top of that, it has added the\n+git hash of the thing to the end: \"-g\" + 8-char shorthand for\n+the commit `2414721b194453f058079d897d13c4e377f92dc6`.\n+\n+Doing a \"git-describe\" on a tag-name will just show the tag name:\n+\n+\t[torvalds@g5 git]$ git-describe v1.0.4\n+\tv1.0.4\n+\n+With --all, the command can use branch heads as references, so\n+the output shows the reference path as well:\n+\n+\t[torvalds@g5 git]$ git describe --all --abbrev=4 v1.0.5^2\n+\ttags/v1.0.0-g975b\n+\n+\t[torvalds@g5 git]$ git describe --all HEAD^\n+\theads/lt/describe-g975b\n+\n+\n+Author\n+------\n+Written by Linus Torvalds <torvalds@osdl.org>, but somewhat\n+butchered by Junio C Hamano <junkio@cox.net>\n+\n+Documentation\n+--------------\n+Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.\n+\n+GIT\n+---\n+Part of the gitlink:git[7] suite\n+\ndiff --git a/Documentation/git.txt b/Documentation/git.txt\nindex 5f068c2..90c5bfa 100644\n--- a/Documentation/git.txt\n+++ b/Documentation/git.txt\n@@ -139,6 +139,9 @@ Interrogation commands\n gitlink:git-cat-file[1]::\n \tProvide content or type/size information for repository objects.\n \n+gitlink:git-describe[1]::\n+\tShow the most recent tag that is reachable from a commit.\n+\n gitlink:git-diff-index[1]::\n \tCompares content and mode of blobs between the index and repository.\n \n-- \n1.0.5-geb9d\n"},{"id":"14073","messageId":"7v8xu62gs0.fsf@assigned-by-dhcp.cox.net","threadId":"2927","inReplyTo":"Pine.LNX.4.64.0512241409300.14098@g5.osdl.org","subject":"[PATCH 6/6] Makefile: use git-describe to mark the git version.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-28T00:42:55Z","receivedAt":"2005-12-28T00:42:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Note: with this commit, the GIT maintainer workflow must change.\nGIT-VERSION-GEN is now the file to munge when the default\nversion needs to be changed, not Makefile.  The tag needs to be\npushed into the repository to build the official tarball and\nbinary package beforehand.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n * Only lightly tested.  Especially bootstrapping might be\n   fishy, but I'll be heading off to Japan for fishful new year\n   meals in a few days ;-), so...\n\n .gitignore      |    1 +\n GIT-VERSION-GEN |   18 ++++++++++++++++++\n Makefile        |   10 ++++++++--\n 3 files changed, 27 insertions(+), 2 deletions(-)\n create mode 100755 GIT-VERSION-GEN\n\n8e517cdeb5644b9857c8a9d8ce204ec9b7405297\ndiff --git a/.gitignore b/.gitignore\nindex 6bd508e..47d76f4 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -1,3 +1,4 @@\n+GIT-VERSION-FILE\n git\n git-add\n git-am\ndiff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN\nnew file mode 100755\nindex 0000000..196402c\n--- /dev/null\n+++ b/GIT-VERSION-GEN\n@@ -0,0 +1,18 @@\n+#!/bin/sh\n+\n+GVF=GIT-VERSION-FILE\n+\n+VN=$(git describe --abbrev=4 HEAD 2>/dev/null) || VN=v1.0.GIT\n+VN=$(expr \"$VN\" : v'\\(.*\\)')\n+if test -r $GVF\n+then\n+\tVC=$(sed -e 's/^GIT_VERSION = //' <$GVF)\n+else\n+\tVC=unset\n+fi\n+test \"$VN\" = \"$VC\" || {\n+\techo >&2 \"GIT_VERSION = $VN\"\n+\techo \"GIT_VERSION = $VN\" >$GVF\n+}\n+\n+\ndiff --git a/Makefile b/Makefile\nindex 47e7898..6f1d123 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -55,7 +55,9 @@ all:\n # Define USE_STDEV below if you want git to care about the underlying device\n # change being considered an inode change from the update-cache perspective.\n \n-GIT_VERSION = 1.0.GIT\n+GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE\n+\t@sh ./GIT-VERSION-GEN\n+-include GIT-VERSION-FILE\n \n # CFLAGS and LDFLAGS are for the users to override from the command line.\n \n@@ -369,7 +371,7 @@ all: $(ALL_PROGRAMS)\n all:\n \t$(MAKE) -C templates\n \n-git$X: git.c $(LIB_FILE) Makefile\n+git$X: git.c $(LIB_FILE) Makefile GIT-VERSION-FILE\n \t$(CC) -DGIT_EXEC_PATH='\"$(bindir)\"' -DGIT_VERSION='\"$(GIT_VERSION)\"' \\\n \t\t$(CFLAGS) $(COMPAT_CFLAGS) -o $@ $(filter %.c,$^) $(LIB_FILE)\n \n@@ -499,6 +501,7 @@ deb: dist\n ### Cleaning rules\n \n clean:\n+\trm -f GIT-VERSION-FILE\n \trm -f *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o $(LIB_FILE)\n \trm -f $(PROGRAMS) $(SIMPLE_PROGRAMS) git$X\n \trm -f $(filter-out gitk,$(SCRIPTS))\n@@ -511,3 +514,6 @@ clean:\n \t$(MAKE) -C templates clean\n \t$(MAKE) -C t/ clean\n \n+.PHONY: all install clean\n+.PHONY: .FORCE-GIT-VERSION-FILE\n+\n-- \n1.0.5-geb9d\n"},{"id":"14079","messageId":"Pine.LNX.4.63.0512280300280.3194@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"2927","inReplyTo":"7v7j9q3vdu.fsf@assigned-by-dhcp.cox.net","subject":"Re: Add a \"git-describe\" command","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2005-12-28T02:05:20Z","receivedAt":"2005-12-28T02:05:20Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 27 Dec 2005, Junio C Hamano wrote:\n\n> One problem with git-describe is that getting tags is a concious\n> user action, and you need to do \"git fetch --tags\" from time to\n> time in order to see the v1.0.4-g6e9961d6 name.\n\nThis is probably the biggest problem. I trust you to set the correct \nversion in the Makefile just before tagging it.\n\nAlso, Linus hinted at similarities between git-describe and git-name-rev:\n\n---\n[PATCH] Teach name-rev to understand the \"--inverse\" flag\n\nIf \"--inverse\" is passed to name-rev, instead of naming the given revs\nby the available refs, it does the opposite. The output is sorted by\ndistance, i.e. how many hops are between the rev and the ref. If the ref is\nnot an ancestor of the rev, the distance is inifinite, and the name is\nundefined.\n\nYou can combine \"--inverse\" with \"--tags\", in effect getting the list of tags\nordered such that the tag describing the rev best comes first.\n\nSigned-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n\n---\n\n\tI guess this is what Linus has been hinting at when he said that\n\tgit-name-rev could be adapted to achieve something similar to\n\tgit-describe.\n\n name-rev.c |   85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-----\n 1 files changed, 78 insertions(+), 7 deletions(-)\n\nb1831f3f66f659445d2628dda73a1d79fc8c3b6f\ndiff --git a/name-rev.c b/name-rev.c\nindex 65333d4..4f7c04e 100644\n--- a/name-rev.c\n+++ b/name-rev.c\n@@ -5,19 +5,21 @@\n #include \"refs.h\"\n \n static const char name_rev_usage[] =\n-\t\"git-name-rev [--tags] ( --all | --stdin | commitish [commitish...] )\\n\";\n+\t\"git-name-rev [--tags] ( --all | --stdin | \\n\"\n+\t\"                       [--inverse] commitish [commitish...] )\\n\";\n \n typedef struct rev_name {\n \tconst char *tip_name;\n \tint merge_traversals;\n \tint generation;\n+\tint distance;\n } rev_name;\n \n static long cutoff = LONG_MAX;\n \n static void name_rev(struct commit *commit,\n \t\tconst char *tip_name, int merge_traversals, int generation,\n-\t\tint deref)\n+\t\tint distance, int deref)\n {\n \tstruct rev_name *name = (struct rev_name *)commit->object.util;\n \tstruct commit_list *parents;\n@@ -50,6 +52,7 @@ copy_data:\n \t\tname->tip_name = tip_name;\n \t\tname->merge_traversals = merge_traversals;\n \t\tname->generation = generation;\n+\t\tname->distance = distance;\n \t} else\n \t\treturn;\n \n@@ -66,10 +69,10 @@ copy_data:\n \t\t\t\tsprintf(new_name, \"%s^%d\", tip_name, parent_number);\n \n \t\t\tname_rev(parents->item, new_name,\n-\t\t\t\tmerge_traversals + 1 , 0, 0);\n+\t\t\t\tmerge_traversals + 1 , 0, distance + 1, 0);\n \t\t} else {\n \t\t\tname_rev(parents->item, tip_name, merge_traversals,\n-\t\t\t\tgeneration + 1, 0);\n+\t\t\t\tgeneration + 1, distance + 1, 0);\n \t\t}\n \t}\n }\n@@ -98,7 +101,7 @@ static int name_ref(const char *path, co\n \t\twhile ((p = strchr(path, '/')))\n \t\t\tpath = p+1;\n \n-\t\tname_rev(commit, strdup(path), 0, 0, deref);\n+\t\tname_rev(commit, strdup(path), 0, 0, 0, deref);\n \t}\n \treturn 0;\n }\n@@ -118,12 +121,56 @@ static const char* get_rev_name(struct o\n \n \treturn buffer;\n }\n-\t\n+\n+typedef struct {\n+\tconst char* name;\n+\tstruct object* o;\n+} named_commit_t;\n+static named_commit_t* ref_list = NULL;\n+static int ref_count = 0;\n+\n+static int inverse_build_ref_list(const char *path, const unsigned char *sha1)\n+{\n+\tstruct object *o = deref_tag(parse_object(sha1), path, 0);\n+\n+\tif ((!tags_only || !strncmp(path, \"refs/tags/\", 10)) &&\n+\t\t\to->type == commit_type) {\n+\t\tstruct commit* commit = (struct commit*)o;\n+\n+\t\tif (cutoff > commit->date)\n+\t\t\tcutoff = commit->date;\n+\n+\t\tif ((ref_count % 256) == 0)\n+\t\t\tref_list = xrealloc(ref_list,\n+\t\t\t\tsizeof(named_commit_t*) * (ref_count + 256));\n+\t\tref_list[ref_count].name = strdup(path);\n+\t\tref_list[ref_count].o = (struct object*)commit;\n+\t\tref_count++;\n+\t}\n+\treturn 0;\n+}\n+\n+static int name_comp(const void* a, const void* b)\n+{\n+\tconst rev_name* c = ((const named_commit_t*)a)->o->util;\n+\tconst rev_name* d = ((const named_commit_t*)b)->o->util;\n+\n+\tif (!c)\n+\t\treturn 1;\n+\tif (!d)\n+\t\treturn -1;\n+\tif (c->distance > d->distance)\n+\t\treturn 1;\n+\tif (c->distance < d->distance)\n+\t\treturn -1;\n+\treturn 0;\n+}\n+\n int main(int argc, char **argv)\n {\n \tstruct object_list *revs = NULL;\n \tstruct object_list **walker = &revs;\n-\tint as_is = 0, all = 0, transform_stdin = 0;\n+\tint as_is = 0, all = 0, inverse = 0, transform_stdin = 0;\n \n \tsetup_git_directory();\n \n@@ -142,6 +189,9 @@ int main(int argc, char **argv)\n \t\t\t} else if (!strcmp(*argv, \"--tags\")) {\n \t\t\t\ttags_only = 1;\n \t\t\t\tcontinue;\n+\t\t\t} else if (!strcmp(*argv, \"--inverse\")) {\n+\t\t\t\tinverse = 1;\n+\t\t\t\tcontinue;\n \t\t\t} else if (!strcmp(*argv, \"--all\")) {\n \t\t\t\tif (argc > 1)\n \t\t\t\t\tdie(\"Specify either a list, or --all, not both!\");\n@@ -181,6 +231,27 @@ int main(int argc, char **argv)\n \t\twalker = &((*walker)->next);\n \t}\n \n+\tif (inverse) {\n+\t\tint i;\n+\n+\t\tif (transform_stdin || all || !revs)\n+\t\t\tusage(name_rev_usage);\n+\n+\t\tfor_each_ref(inverse_build_ref_list);\n+\t\t\n+\t\ttags_only = 0;\n+\t\tfor (; revs; revs = revs->next)\n+\t\t\tname_ref(revs->name, revs->item->sha1);\n+\n+\t\tqsort(ref_list, ref_count, sizeof(named_commit_t), name_comp);\n+\n+\t\tfor (i = 0; i < ref_count; i++)\n+\t\t\tprintf(\"%s %s\\n\", ref_list[i].name,\n+\t\t\t\tget_rev_name(ref_list[i].o));\n+\n+\t\treturn 0;\n+\t}\n+\n \tfor_each_ref(name_ref);\n \n \tif (transform_stdin) {\n-- \n1.0.GIT\n"}]}