{"thread":{"id":"5771","subject":"[PATCH] git-describe: allow reflogs as reference points","startedAt":"2006-09-30T22:29:04Z","lastAt":"2006-10-01T00:20:52Z","messageCount":2,"participants":["Jeff King","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"28039","messageId":"20060930222903.GA11252@coredump.intra.peff.net","threadId":"5771","inReplyTo":null,"subject":"[PATCH] git-describe: allow reflogs as reference points","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2006-09-30T22:29:04Z","receivedAt":"2006-09-30T22:29:04Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"\nSigned-off-by: Jeff King <peff@peff.net>\n---\nIt's basically impossible to use this in the git repository, since we\nprefer tags to reflogs. Should --reflog turn off tag matching? Should\nthere be a command line option to turn off tags?\n\n Documentation/git-describe.txt |    9 ++++++-\n describe.c                     |   51 +++++++++++++++++++++++++++++++++++++++-\n 2 files changed, 58 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-describe.txt b/Documentation/git-describe.txt\nindex 2700f35..975da0f 100644\n--- a/Documentation/git-describe.txt\n+++ b/Documentation/git-describe.txt\n@@ -8,7 +8,7 @@ git-describe - Show the most recent tag \n \n SYNOPSIS\n --------\n-'git-describe' [--all] [--tags] [--abbrev=<n>] <committish>...\n+'git-describe' [--all] [--tags] [--reflog] [--abbrev=<n>] <committish>...\n \n DESCRIPTION\n -----------\n@@ -31,6 +31,13 @@ OPTIONS\n \tInstead of using only the annotated tags, use any tag\n \tfound in `.git/refs/tags`.\n \n+--reflog=<fmt>::\n+\tInstead of using only the annotated tags, use reference dates\n+\tmarked in branch reflogs. The output will be of the form\n+\t'branch@{date}' where the format of date is specified by <fmt>, which\n+\tmust be one of 'relative', '822', 'git'. If no format is specified,\n+\tthe default is 'relative'.\n+\n --abbrev=<n>::\n \tInstead of using the default 8 hexadecimal digits as the\n \tabbreviated object name, use <n> digits.\ndiff --git a/describe.c b/describe.c\nindex f4029ee..1dc5209 100644\n--- a/describe.c\n+++ b/describe.c\n@@ -6,11 +6,16 @@ #include \"refs.h\"\n #define SEEN (1u << 0)\n \n static const char describe_usage[] =\n-\"git-describe [--all] [--tags] [--abbrev=<n>] <committish>*\";\n+\"git-describe [--all] [--tags] [--reflog] [--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+#define FMT_DATE_822 1\n+#define FMT_DATE_GIT 2\n+#define FMT_DATE_REL 3\n+static int reflog;\n+\n static int abbrev = DEFAULT_ABBREV;\n \n static int names, allocs;\n@@ -85,6 +90,35 @@ static int get_name(const char *path, co\n \treturn 0;\n }\n \n+static int get_reflog_name(const char *ref, const unsigned char *head_sha1,\n+\t\tint flag, void *cb_data)\n+{\n+\tunsigned char sha1[20];\n+\tchar buf[1024];\n+\tstruct reflog log;\n+\tstruct reflog_entry c;\n+\n+\tsnprintf(buf, sizeof(buf), \"refs/heads/%s\", ref);\n+\tif (reflog_open(&log, buf) < 0) {\n+\t\tif (errno == ENOENT)\n+\t\t\treturn 0;\n+\t\tdie(\"unable to read log %s: %s\\n\", log.file, strerror(errno));\n+\t}\n+\treflog_start(&log);\n+\twhile (reflog_next(&log, &c)) {\n+\t\tsnprintf(buf, sizeof(buf), \"%s@{%s}\",\n+\t\t\tref,\n+\t\t\treflog == FMT_DATE_REL ? show_date(c.date, 0, 1) :\n+\t\t\treflog == FMT_DATE_GIT ? show_date(c.date, c.tz, 0) :\n+\t\t\tshow_rfc2822_date(c.date, c.tz));\n+\t\treflog_entry_to(&c, sha1);\n+\t\tadd_to_known_names(buf, lookup_commit_reference(sha1), 0);\n+\t}\n+\treflog_close(&log);\n+\treturn 0;\n+}\n+\n+\n static int compare_names(const void *_a, const void *_b)\n {\n \tstruct commit_name *a = *(struct commit_name **)_a;\n@@ -114,6 +148,8 @@ static void describe(const char *arg, in\n \tif (!initialized) {\n \t\tinitialized = 1;\n \t\tfor_each_ref(get_name, NULL);\n+\t\tif (reflog)\n+\t\t\tfor_each_branch_ref(get_reflog_name, NULL);\n \t\tqsort(name_array, names, sizeof(*name_array), compare_names);\n \t}\n \n@@ -152,6 +188,19 @@ int main(int argc, char **argv)\n \t\t\tall = 1;\n \t\telse if (!strcmp(arg, \"--tags\"))\n \t\t\ttags = 1;\n+\t\telse if (!strncmp(arg, \"--reflog=\", 9)) {\n+\t\t\tif (!strcmp(arg+9, \"2822\") || !strcmp(arg+9, \"822\"))\n+\t\t\t\treflog = FMT_DATE_822;\n+\t\t\telse if (!strcmp(arg+9, \"git\"))\n+\t\t\t\treflog = FMT_DATE_GIT;\n+\t\t\telse if (!strcmp(arg+9, \"relative\"))\n+\t\t\t\treflog = FMT_DATE_REL;\n+\t\t\telse\n+\t\t\t\tusage(describe_usage);\n+\t\t}\n+\t\telse if (!strcmp(arg, \"--reflog\")) {\n+\t\t\treflog = FMT_DATE_REL;\n+\t\t}\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-- \n1.4.2.1.gd4f1-dirty\n"},{"id":"28049","messageId":"7vac4g7uor.fsf@assigned-by-dhcp.cox.net","threadId":"5771","inReplyTo":"20060930222903.GA11252@coredump.intra.peff.net","subject":"Re: [PATCH] git-describe: allow reflogs as reference points","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-10-01T00:20:52Z","receivedAt":"2006-10-01T00:20:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> Signed-off-by: Jeff King <peff@peff.net>\n> ---\n> It's basically impossible to use this in the git repository, since we\n> prefer tags to reflogs. Should --reflog turn off tag matching? Should\n> there be a command line option to turn off tags?\n\n(Also please see my other message to Linus).\n\nI think the behaviour we want out of the command when using\nref-log and when describing based on well-known points (aka\ntags) are mutually incompatible, so I agree --reflog should turn\noff tag matching.  Also you need to be prepared to handle a\nref-log that happens to have a rewound history.  See attached\npatch.\n\nI do not however think the patch is useful to get the\ninformation the discussion which lead to this patch wanted to\nknow, as I described in a separate message today.  For example,\nasking:\n\n\t$ git describe --reflog ce74618\n\nanswers \"next@{3 months ago}-gce74618\", in my repository, which\nis quite bogus.  \"next@{3 months ago}\" is 47e5c0; it indeed is\nan ancestor of ce74618 and it probably was once at the tip of\n\"next\", so you are not giving any incorrect information, but\nthat one certainly did _not_ contain the change ce74618\nintroduced, so that form of output is not useful for answering\nthe question \"when did this commit hit this branch\".\n\n\t$ gitk master..next\n\nshows that the commit ce74618 is a direct descendant of the\ncurrent \"master\" (4839bd8), and was merged into \"next\" for the\nfirst time with 5a98f4e which was done last night.\n\nAnother example.  Recently somebody on the kernel list was\nbitten by an ancient bug in diff.c::emit_rewrite_diff().  The\nbug was there in the very first version of this feature (June\n19, 2005) and nobody touched the vicinity of the code.  I fixed\nit on top of recent master.\n\nHowever, somebody else could have fixed it on top of v0.99 and\nthen I could have merged the fix from his branch that is based\non v0.99 (the bug is that ancient).  I do not enable the reflog\non my \"master\", but if I did, it would have looked like:\n\n\tfrom v0.99^ to v0.99 on July 10th 15:40 2005\n\tfrom v0.99 to 013aab on July 10th 23:55 2005\n\t...\n\tfrom 18b633 to 4839bd on Sept 29th 18:54 2006\n\nIOW, my reflog would have recorded v0.99 was once at the tip of\nthe \"master\" branch.  Using it, describing \n\n\tgit describe --reflog $that_fixes_on_v0_99\n\nwould say v0.99 is the closest ancestor of the fix, which is\ntechnically correct.  And if I merge that on top of my \"master\"\ncreating a new merge commit, that merge commit is the first\ncommit my \"master\" branch sees the fix.  So when I make the\nmerge, the reflog would have a new entry at the end:\n\n\tfrom 4839bd to xxxxxx on Sept 30th 17:10 2006 merge the fix\n\nand what would be useful is to find this record and notice the\ncommit is the first one in the \"master\"'s history that has the\nfix as its ancestor.\n\n\ndiff --git a/describe.c b/describe.c\nindex 1dc5209..cc38651 100644\n--- a/describe.c\n+++ b/describe.c\n@@ -106,13 +106,18 @@ static int get_reflog_name(const char *r\n \t}\n \treflog_start(&log);\n \twhile (reflog_next(&log, &c)) {\n+\t\tstruct commit *commit;\n \t\tsnprintf(buf, sizeof(buf), \"%s@{%s}\",\n \t\t\tref,\n \t\t\treflog == FMT_DATE_REL ? show_date(c.date, 0, 1) :\n \t\t\treflog == FMT_DATE_GIT ? show_date(c.date, c.tz, 0) :\n \t\t\tshow_rfc2822_date(c.date, c.tz));\n \t\treflog_entry_to(&c, sha1);\n-\t\tadd_to_known_names(buf, lookup_commit_reference(sha1), 0);\n+\t\tcommit = lookup_commit_reference(sha1);\n+\t\tif (!commit)\n+\t\t\t/* rewound head */\n+\t\t\tcontinue;\n+\t\tadd_to_known_names(buf, commit, 0);\n \t}\n \treflog_close(&log);\n \treturn 0;\n@@ -147,9 +151,10 @@ static void describe(const char *arg, in\n \n \tif (!initialized) {\n \t\tinitialized = 1;\n-\t\tfor_each_ref(get_name, NULL);\n \t\tif (reflog)\n \t\t\tfor_each_branch_ref(get_reflog_name, NULL);\n+\t\telse\n+\t\t\tfor_each_ref(get_name, NULL);\n \t\tqsort(name_array, names, sizeof(*name_array), compare_names);\n \t}\n \n"}]}