{"thread":{"id":"6329","subject":"[PATCH 2/3] Make git-describe a builtin.","startedAt":"2007-01-10T11:36:36Z","lastAt":"2007-01-10T11:39:47Z","messageCount":2,"participants":["Shawn O. Pearce"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"31382","messageId":"20070110113636.GB25251@spearce.org","threadId":"6329","inReplyTo":"de93279981338622182dd8f00e4686c6624697b6.1168428978.git.spearce@spearce.org","subject":"[PATCH 2/3] Make git-describe a builtin.","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2007-01-10T11:36:36Z","receivedAt":"2007-01-10T11:36:36Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Signed-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n Makefile           |    3 +-\n builtin-describe.c |  176 ++++++++++++++++++++++++++++++++++++++++++++++++++++\n builtin.h          |    1 +\n describe.c         |  176 ----------------------------------------------------\n git.c              |    1 +\n 5 files changed, 180 insertions(+), 177 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex de746be..f648085 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -203,7 +203,7 @@ PROGRAMS = \\\n \tgit-update-server-info$X \\\n \tgit-upload-pack$X git-verify-pack$X \\\n \tgit-pack-redundant$X git-var$X \\\n-\tgit-describe$X git-merge-tree$X git-imap-send$X \\\n+\tgit-merge-tree$X git-imap-send$X \\\n \tgit-merge-recursive$X \\\n \t$(EXTRA_PROGRAMS)\n \n@@ -274,6 +274,7 @@ BUILTIN_OBJS = \\\n \tbuiltin-check-ref-format.o \\\n \tbuiltin-commit-tree.o \\\n \tbuiltin-count-objects.o \\\n+\tbuiltin-describe.o \\\n \tbuiltin-diff.o \\\n \tbuiltin-diff-files.o \\\n \tbuiltin-diff-index.o \\\ndiff --git a/builtin-describe.c b/builtin-describe.c\nnew file mode 100644\nindex 0000000..ad3b469\n--- /dev/null\n+++ b/builtin-describe.c\n@@ -0,0 +1,176 @@\n+#include \"cache.h\"\n+#include \"commit.h\"\n+#include \"tag.h\"\n+#include \"refs.h\"\n+#include \"builtin.h\"\n+\n+#define SEEN (1u << 0)\n+\n+static const char describe_usage[] =\n+\"git-describe [--all] [--tags] [--abbrev=<n>] <committish>*\";\n+\n+static int all;\t/* Default to annotated tags only */\n+static int tags;\t/* But allow any tags if --tags is specified */\n+\n+static int abbrev = DEFAULT_ABBREV;\n+\n+static int names, allocs;\n+static struct commit_name {\n+\tconst struct commit *commit;\n+\tint prio; /* annotated tag = 2, tag = 1, head = 0 */\n+\tchar path[FLEX_ARRAY]; /* more */\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,\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+\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, int flag, void *cb_data)\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 == OBJ_TAG)\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 (!prio)\n+\t\t\treturn 0;\n+\t\tif (!tags && prio < 2)\n+\t\t\treturn 0;\n+\t}\n+\tadd_to_known_names(all ? path + 5 : path + 10, commit, prio);\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+\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+static void describe(const char *arg, int last_one)\n+{\n+\tunsigned char sha1[20];\n+\tstruct commit *cmit;\n+\tstruct commit_list *list;\n+\tstatic int initialized = 0;\n+\tstruct commit_name *n;\n+\n+\tif (get_sha1(arg, sha1))\n+\t\tdie(\"Not a valid object name %s\", arg);\n+\tcmit = lookup_commit_reference(sha1);\n+\tif (!cmit)\n+\t\tdie(\"%s is not a valid '%s' object\", arg, commit_type);\n+\n+\tif (!initialized) {\n+\t\tinitialized = 1;\n+\t\tfor_each_ref(get_name, NULL);\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%s\\n\", n->path,\n+\t\t\t       find_unique_abbrev(cmit->object.sha1, abbrev));\n+\t\t\tif (!last_one)\n+\t\t\t\tclear_commit_marks(cmit, SEEN);\n+\t\t\treturn;\n+\t\t}\n+\t}\n+\tdie(\"cannot describe '%s'\", sha1_to_hex(cmit->object.sha1));\n+}\n+\n+int cmd_describe(int argc, const char **argv, const char *prefix)\n+{\n+\tint i;\n+\n+\tfor (i = 1; i < argc; i++) {\n+\t\tconst char *arg = argv[i];\n+\n+\t\tif (*arg != '-')\n+\t\t\tbreak;\n+\t\telse if (!strcmp(arg, \"--all\"))\n+\t\t\tall = 1;\n+\t\telse if (!strcmp(arg, \"--tags\"))\n+\t\t\ttags = 1;\n+\t\telse if (!strncmp(arg, \"--abbrev=\", 9)) {\n+\t\t\tabbrev = strtoul(arg + 9, NULL, 10);\n+\t\t\tif (abbrev < MINIMUM_ABBREV || 40 < abbrev)\n+\t\t\t\tabbrev = DEFAULT_ABBREV;\n+\t\t}\n+\t\telse\n+\t\t\tusage(describe_usage);\n+\t}\n+\n+\tsave_commit_buffer = 0;\n+\n+\tif (argc <= i)\n+\t\tdescribe(\"HEAD\", 1);\n+\telse\n+\t\twhile (i < argc) {\n+\t\t\tdescribe(argv[i], (i == argc - 1));\n+\t\t\ti++;\n+\t\t}\n+\n+\treturn 0;\n+}\ndiff --git a/builtin.h b/builtin.h\nindex ae32993..818c7bf 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -25,6 +25,7 @@ extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix)\n extern int cmd_cherry(int argc, const char **argv, const char *prefix);\n extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);\n extern int cmd_count_objects(int argc, const char **argv, const char *prefix);\n+extern int cmd_describe(int argc, const char **argv, const char *prefix);\n extern int cmd_diff_files(int argc, const char **argv, const char *prefix);\n extern int cmd_diff_index(int argc, const char **argv, const char *prefix);\n extern int cmd_diff(int argc, const char **argv, const char *prefix);\ndiff --git a/describe.c b/describe.c\ndeleted file mode 100644\nindex 3c2df03..0000000\n--- a/describe.c\n+++ /dev/null\n@@ -1,176 +0,0 @@\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[] =\n-\"git-describe [--all] [--tags] [--abbrev=<n>] <committish>*\";\n-\n-static int all;\t/* Default to annotated tags only */\n-static int tags;\t/* But allow any tags if --tags is specified */\n-\n-static int abbrev = DEFAULT_ABBREV;\n-\n-static int names, allocs;\n-static struct commit_name {\n-\tconst struct commit *commit;\n-\tint prio; /* annotated tag = 2, tag = 1, head = 0 */\n-\tchar path[FLEX_ARRAY]; /* more */\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,\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-\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, int flag, void *cb_data)\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 == OBJ_TAG)\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 (!prio)\n-\t\t\treturn 0;\n-\t\tif (!tags && prio < 2)\n-\t\t\treturn 0;\n-\t}\n-\tadd_to_known_names(all ? path + 5 : path + 10, commit, prio);\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-\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-static void describe(const char *arg, int last_one)\n-{\n-\tunsigned char sha1[20];\n-\tstruct commit *cmit;\n-\tstruct commit_list *list;\n-\tstatic int initialized = 0;\n-\tstruct commit_name *n;\n-\n-\tif (get_sha1(arg, sha1))\n-\t\tdie(\"Not a valid object name %s\", arg);\n-\tcmit = lookup_commit_reference(sha1);\n-\tif (!cmit)\n-\t\tdie(\"%s is not a valid '%s' object\", arg, commit_type);\n-\n-\tif (!initialized) {\n-\t\tinitialized = 1;\n-\t\tfor_each_ref(get_name, NULL);\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%s\\n\", n->path,\n-\t\t\t       find_unique_abbrev(cmit->object.sha1, abbrev));\n-\t\t\tif (!last_one)\n-\t\t\t\tclear_commit_marks(cmit, SEEN);\n-\t\t\treturn;\n-\t\t}\n-\t}\n-\tdie(\"cannot describe '%s'\", sha1_to_hex(cmit->object.sha1));\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-\n-\t\tif (*arg != '-')\n-\t\t\tbreak;\n-\t\telse if (!strcmp(arg, \"--all\"))\n-\t\t\tall = 1;\n-\t\telse if (!strcmp(arg, \"--tags\"))\n-\t\t\ttags = 1;\n-\t\telse if (!strncmp(arg, \"--abbrev=\", 9)) {\n-\t\t\tabbrev = strtoul(arg + 9, NULL, 10);\n-\t\t\tif (abbrev < MINIMUM_ABBREV || 40 < abbrev)\n-\t\t\t\tabbrev = DEFAULT_ABBREV;\n-\t\t}\n-\t\telse\n-\t\t\tusage(describe_usage);\n-\t}\n-\n-\tsetup_git_directory();\n-\tsave_commit_buffer = 0;\n-\n-\tif (argc <= i)\n-\t\tdescribe(\"HEAD\", 1);\n-\telse\n-\t\twhile (i < argc) {\n-\t\t\tdescribe(argv[i], (i == argc - 1));\n-\t\t\ti++;\n-\t\t}\n-\n-\treturn 0;\n-}\ndiff --git a/git.c b/git.c\nindex e7bc79a..9a0185c 100644\n--- a/git.c\n+++ b/git.c\n@@ -220,6 +220,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)\n \t\t{ \"cherry\", cmd_cherry, RUN_SETUP },\n \t\t{ \"commit-tree\", cmd_commit_tree, RUN_SETUP },\n \t\t{ \"count-objects\", cmd_count_objects, RUN_SETUP },\n+\t\t{ \"describe\", cmd_describe, RUN_SETUP },\n \t\t{ \"diff\", cmd_diff, RUN_SETUP | USE_PAGER },\n \t\t{ \"diff-files\", cmd_diff_files, RUN_SETUP },\n \t\t{ \"diff-index\", cmd_diff_index, RUN_SETUP },\n-- \n1.4.4.4.gf027-dirty\n"},{"id":"31383","messageId":"20070110113947.GC25251@spearce.org","threadId":"6329","inReplyTo":"de93279981338622182dd8f00e4686c6624697b6.1168428978.git.spearce@spearce.org","subject":"[PATCH 3/3] Chose better tag names in git-describe after merges.","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2007-01-10T11:39:47Z","receivedAt":"2007-01-10T11:39:47Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Recently git.git itself encountered a situation on its master and\nnext branches where git-describe stopped reporting 'v1.5.0-rc0-gN'\nand instead started reporting 'v1.4.4.4-gN'.  This appeared to be\na backward jump in version numbering.\n\n  maint     o-------------------4\n            \\                    \\\n  master     o-o-o-o-o-o-o-5-o-C-o-W\n\nThe issue is that commit C in the diagram claims it is version\n1.5.0, as the tag v1.5.0 is placed on commit 5.  Yet commit W\nclaims it is version 1.4.4.4 as the tag v1.5.0 has an older tag\ndate than the v1.4.4.4 tag.\n\nAs it turns out this situation is very common.  A bug fix applied\nto maint and later merged into master occurs frequently enough that\nit should Just Work Right(tm).\n\nRather than taking the first tag that gets found git-describe will\nnow generate a list of all possible tags and select the one which\nhas the most number of commits in common with HEAD (or whatever\nrevision the user requested the description of).\n\nThis rule is based on the principle shown in the diagram above.\nThere are a large number of commits on the primary development branch\n'master' which do not appear in the 'maint' branch, and many of\nthese are already tagged as part of v1.5.0-rc0.  Additionally these\ncommits are not in v1.4.4.4, as they are part of the v1.5.0 release\nstill being developed.  The v1.5.0-rc0 tag is more descriptive of\nW than v1.4.4.4 is, and therefore should be used.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n\n This implements the algorithm I suggested on the mailing list.\n\n In my limited testing on git.git its 4x slower than the previous\n git-describe on current 'next' as its coming up with about 10\n tags as possible matches and then needs to generate the rev-list\n for each of them.  (Old = 100 ms, new = 400 ms).  I think that is\n acceptable in exchange for a \"more likely to be correct\" answer,\n especially when users are embedding git-describe's output into\n their binaries and expecting it to make some sort of sense.\n\n Since this is my first foray into calling the revision machinary\n for any sort of useful computation I would certainly appreciate\n comments and suggestions for improvements from those who know it\n better than I.  :-)\n\n builtin-describe.c |   78 ++++++++++++++++++++++++++++++++++++++++++++-------\n 1 files changed, 67 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin-describe.c b/builtin-describe.c\nindex ad3b469..d65c7d2 100644\n--- a/builtin-describe.c\n+++ b/builtin-describe.c\n@@ -2,10 +2,11 @@\n #include \"commit.h\"\n #include \"tag.h\"\n #include \"refs.h\"\n+#include \"diff.h\"\n+#include \"diffcore.h\"\n+#include \"revision.h\"\n #include \"builtin.h\"\n \n-#define SEEN (1u << 0)\n-\n static const char describe_usage[] =\n \"git-describe [--all] [--tags] [--abbrev=<n>] <committish>*\";\n \n@@ -16,7 +17,7 @@ static int abbrev = DEFAULT_ABBREV;\n \n static int names, allocs;\n static struct commit_name {\n-\tconst struct commit *commit;\n+\tstruct commit *commit;\n \tint prio; /* annotated tag = 2, tag = 1, head = 0 */\n \tchar path[FLEX_ARRAY]; /* more */\n } **name_array = NULL;\n@@ -35,7 +36,7 @@ static struct commit_name *match(struct commit *cmit)\n }\n \n static void add_to_known_names(const char *path,\n-\t\t\t       const struct commit *commit,\n+\t\t\t       struct commit *commit,\n \t\t\t       int prio)\n {\n \tint idx;\n@@ -98,6 +99,12 @@ static int compare_names(const void *_a, const void *_b)\n \treturn (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;\n }\n \n+struct possible_tag {\n+\tstruct possible_tag *next;\n+\tstruct commit_name *name;\n+\tunsigned long depth;\n+};\n+\n static void describe(const char *arg, int last_one)\n {\n \tunsigned char sha1[20];\n@@ -105,6 +112,7 @@ static void describe(const char *arg, int last_one)\n \tstruct commit_list *list;\n \tstatic int initialized = 0;\n \tstruct commit_name *n;\n+\tstruct possible_tag *all_matches, *min_match, *cur_match;\n \n \tif (get_sha1(arg, sha1))\n \t\tdie(\"Not a valid object name %s\", arg);\n@@ -125,19 +133,67 @@ static void describe(const char *arg, int last_one)\n \t}\n \n \tlist = NULL;\n+\tall_matches = NULL;\n+\tcur_match = NULL;\n \tcommit_list_insert(cmit, &list);\n \twhile (list) {\n-\t\tstruct commit *c = pop_most_recent_commit(&list, SEEN);\n+\t\tstruct commit *c = pop_commit(&list);\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, abbrev));\n-\t\t\tif (!last_one)\n-\t\t\t\tclear_commit_marks(cmit, SEEN);\n-\t\t\treturn;\n+\t\t\tstruct possible_tag *p = xmalloc(sizeof(*p));\n+\t\t\tp->name = n;\n+\t\t\tp->next = NULL;\n+\t\t\tif (cur_match)\n+\t\t\t\tcur_match->next = p;\n+\t\t\telse\n+\t\t\t\tall_matches = p;\n+\t\t\tcur_match = p;\n+\t\t} else {\n+\t\t\tstruct commit_list *parents = c->parents;\n+\t\t\twhile (parents) {\n+\t\t\t\tstruct commit *p = parents->item;\n+\t\t\t\tparse_commit(p);\n+\t\t\t\tif (!(p->object.flags & SEEN)) {\n+\t\t\t\t\tp->object.flags |= SEEN;\n+\t\t\t\t\tinsert_by_date(p, &list);\n+\t\t\t\t}\n+\t\t\t\tparents = parents->next;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tif (!all_matches)\n+\t\tdie(\"cannot describe '%s'\", sha1_to_hex(cmit->object.sha1));\n+\n+\tmin_match = NULL;\n+\tfor (cur_match = all_matches; cur_match; cur_match = cur_match->next) {\n+\t\tstruct rev_info revs;\n+\t\tstruct commit *tagged = cur_match->name->commit;\n+\n+\t\tclear_commit_marks(cmit, -1);\n+\t\tinit_revisions(&revs, NULL);\n+\t\ttagged->object.flags |= UNINTERESTING;\n+\t\tadd_pending_object(&revs, &tagged->object, NULL);\n+\t\tadd_pending_object(&revs, &cmit->object, NULL);\n+\n+\t\tprepare_revision_walk(&revs);\n+\t\tcur_match->depth = 0;\n+\t\twhile ((!min_match || cur_match->depth < min_match->depth)\n+\t\t\t&& get_revision(&revs))\n+\t\t\tcur_match->depth++;\n+\t\tif (!min_match || cur_match->depth < min_match->depth)\n+\t\t\tmin_match = cur_match;\n+\t}\n+\tprintf(\"%s-g%s\\n\", min_match->name->path,\n+\t\t   find_unique_abbrev(cmit->object.sha1, abbrev));\n+\n+\tif (!last_one) {\n+\t\tfor (cur_match = all_matches; cur_match; cur_match = min_match) {\n+\t\t\tmin_match = cur_match->next;\n+\t\t\tfree(cur_match);\n \t\t}\n+\t\tclear_commit_marks(cmit, SEEN);\n \t}\n-\tdie(\"cannot describe '%s'\", sha1_to_hex(cmit->object.sha1));\n }\n \n int cmd_describe(int argc, const char **argv, const char *prefix)\n-- \n1.4.4.4.gf027-dirty\n"}]}