{"thread":{"id":"21304","subject":"[PATCH v3] new --dirty option for git describe","startedAt":"2009-10-21T13:35:22Z","lastAt":"2009-10-21T22:07:27Z","messageCount":2,"participants":["Jean Privat","Junio C Hamano"],"isPatch":true,"patchVersion":3,"patchTotal":null},"messages":[{"id":"125595","messageId":"1256132122-12509-1-git-send-email-jean@pryen.org","threadId":"21304","inReplyTo":null,"subject":"[PATCH v3] new --dirty option for git describe","fromName":"Jean Privat","fromEmail":"jean@pryen.org","sentAt":"2009-10-21T13:35:22Z","receivedAt":"2009-10-21T13:35:22Z","isPatch":true,"sender":{"key":"jean@pryen.org","avatar":"https://avatars.githubusercontent.com/u/135828?v=4"},"body":"With the --dirty option, git describe works on HEAD but append \"-dirty\"\nif the working tree is dirty. If the working tree is clean, nothing\nis appended.\n\n$ git describe --dirty\nv1.6.5-15-gc274db7\n$ echo >> Makefile\n$ git describe --dirty\nv1.6.5-15-gc274db7-dirty\n\n--dirty can also be used to specify what is append if the working\ntree is dirty.\n\n$ git describe --dirty=.mod\nv1.6.5-15-gc274db7.mod\n\nMany build scripts use `git describe` to produce a version number based\non the description of HEAD (on which is based the working tree) + saying\nthat if the working tree is dirty or no.\nThis patch helps the writing of such scripts since `git describe --dirty`\ndo directly the intended thing.\n\nAlternatives specifications:\n\n1 Describe the working tree by default and describe HEAD only if \"HEAD\"\n  is explicitly specified\nPro: does the right thing by default (both for users and for scripts)\nPro: is coherent with other git commands that works on the working tree\n     by default\nCon: breaks existing scripts (since the world is not ideal)\n\n2 Use --worktree instead of --dirty\nPro: does what it says: \"git describe --worktree\" will describe the\n     working three\nCon: is incoherent with other commands that do not require a --worktree\n     option to work on the working tree\nCon: unusable with an optional value: \"git describe --worktree=.mod\"\n     is quite unintuitive.\n\n3 Use --dirty as in this patch\nPro: make sense to specify an optional value (what the dirty mark is)\nPro: do not have any of the big cons of previous alternatives\n     * does not break scripts\n     * is not inconsistent with other git commands\nPro: has an easy fallback to alternative 1 if the world become suddenly\n     ideal, or at least allows some kind of future transition plan if\n     people *really* bother:\n     1- ask that scripts use either \"git describe HEAD\" or\n        \"git describe --dirty\" (no more \"git describe\")\n     2- change default\n     Once the transition is done, the role of the --dirty option will\n     just be the way to specify an alternative mark (and a noop if alone)\n\nSigned-off-by: Jean Privat <jean@pryen.org>\n\n---\n\nChanges since v2.5:\nUse test_must_fail\n\nChanges since v2:\nNo more line breaks (I hope)\n\nChanges since v1:\nuse --dirty (alternative 3) instead of defaulting on workdir (alternative 1)\n---\n Documentation/git-describe.txt |    6 ++++++\n builtin-describe.c             |   25 ++++++++++++++++++++++++-\n t/t6120-describe.sh            |   14 ++++++++++++++\n 3 files changed, 44 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/git-describe.txt b/Documentation/git-describe.txt\nindex b231dbb..5253d86 100644\n--- a/Documentation/git-describe.txt\n+++ b/Documentation/git-describe.txt\n@@ -9,6 +9,7 @@ git-describe - Show the most recent tag that is reachable from a commit\n SYNOPSIS\n --------\n 'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] <committish>...\n+'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]\n \n DESCRIPTION\n -----------\n@@ -27,6 +28,11 @@ OPTIONS\n <committish>...::\n \tCommittish object names to describe.\n \n+--dirty[=<mark>]::\n+\tDescribe the working tree.\n+\tIt means describe HEAD and appends <mark> (`-dirty` by\n+\tdefault) if the working tree is dirty.\n+\n --all::\n \tInstead of using only the annotated tags, use any ref\n \tfound in `.git/refs/`.  This option enables matching\ndiff --git a/builtin-describe.c b/builtin-describe.c\nindex df67a73..84af981 100644\n--- a/builtin-describe.c\n+++ b/builtin-describe.c\n@@ -5,12 +5,14 @@\n #include \"builtin.h\"\n #include \"exec_cmd.h\"\n #include \"parse-options.h\"\n+#include \"diff.h\"\n \n #define SEEN\t\t(1u<<0)\n #define MAX_TAGS\t(FLAG_BITS - 1)\n \n static const char * const describe_usage[] = {\n \t\"git describe [options] <committish>*\",\n+\t\"git describe [options] --dirty\",\n \tNULL\n };\n \n@@ -23,6 +25,13 @@ static int max_candidates = 10;\n static int found_names;\n static const char *pattern;\n static int always;\n+static const char *dirty;\n+\n+/* diff-index command arguments to check if working tree is dirty. */\n+static const char *diff_index_args[] = {\n+\t\"diff-index\", \"--quiet\", \"HEAD\", \"--\", NULL\n+};\n+\n \n struct commit_name {\n \tstruct tag *tag;\n@@ -208,6 +217,8 @@ static void describe(const char *arg, int last_one)\n \t\tdisplay_name(n);\n \t\tif (longformat)\n \t\t\tshow_suffix(0, n->tag ? n->tag->tagged->sha1 : sha1);\n+\t\tif (dirty)\n+\t\t\tprintf(\"%s\", dirty);\n \t\tprintf(\"\\n\");\n \t\treturn;\n \t}\n@@ -265,7 +276,10 @@ static void describe(const char *arg, int last_one)\n \tif (!match_cnt) {\n \t\tconst unsigned char *sha1 = cmit->object.sha1;\n \t\tif (always) {\n-\t\t\tprintf(\"%s\\n\", find_unique_abbrev(sha1, abbrev));\n+\t\t\tprintf(\"%s\", find_unique_abbrev(sha1, abbrev));\n+\t\t\tif (dirty)\n+\t\t\t\tprintf(\"%s\", dirty);\n+\t\t\tprintf(\"\\n\");\n \t\t\treturn;\n \t\t}\n \t\tdie(\"cannot describe '%s'\", sha1_to_hex(sha1));\n@@ -300,6 +314,8 @@ static void describe(const char *arg, int last_one)\n \tdisplay_name(all_matches[0].name);\n \tif (abbrev)\n \t\tshow_suffix(all_matches[0].depth, cmit->object.sha1);\n+\tif (dirty)\n+\t\tprintf(\"%s\", dirty);\n \tprintf(\"\\n\");\n \n \tif (!last_one)\n@@ -324,6 +340,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)\n \t\t\t   \"only consider tags matching <pattern>\"),\n \t\tOPT_BOOLEAN(0, \"always\",     &always,\n \t\t\t   \"show abbreviated commit object as fallback\"),\n+\t\t{OPTION_STRING, 0, \"dirty\",       &dirty, \"mark\",\n+\t\t\t   \"append <mark> on dirty working tree (default: \\\"-dirty\\\")\",\n+\t\t\t   PARSE_OPT_OPTARG, NULL, \"-dirty\"},\n \t\tOPT_END(),\n \t};\n \n@@ -360,7 +379,11 @@ int cmd_describe(int argc, const char **argv, const char *prefix)\n \t}\n \n \tif (argc == 0) {\n+\t\tif (dirty && !cmd_diff_index(ARRAY_SIZE(diff_index_args) - 1, diff_index_args, prefix))\n+\t\t\tdirty = NULL;\n \t\tdescribe(\"HEAD\", 1);\n+\t} else if (dirty) {\n+\t\tdie(\"--dirty is incompatible with committishes\");\n \t} else {\n \t\twhile (argc-- > 0) {\n \t\t\tdescribe(*argv++, argc == 0);\ndiff --git a/t/t6120-describe.sh b/t/t6120-describe.sh\nindex 8c7e081..e061177 100755\n--- a/t/t6120-describe.sh\n+++ b/t/t6120-describe.sh\n@@ -123,6 +123,20 @@ test_expect_success 'rename tag Q back to A' '\n test_expect_success 'pack tag refs' 'git pack-refs'\n check_describe A-* HEAD\n \n+check_describe \"A-*[0-9a-f]\" --dirty\n+\n+test_expect_success 'set-up dirty working tree' '\n+\techo >>file\n+'\n+\n+check_describe \"A-*[0-9a-f]-dirty\" --dirty\n+\n+check_describe \"A-*[0-9a-f].mod\" --dirty=.mod\n+\n+test_expect_success 'describe --dirty HEAD' '\n+\ttest_must_fail git describe --dirty HEAD\n+'\n+\n test_expect_success 'set-up matching pattern tests' '\n \tgit tag -a -m test-annotated test-annotated &&\n \techo >>file &&\n-- \n1.6.5\n"},{"id":"125656","messageId":"7v63a81jvk.fsf@alter.siamese.dyndns.org","threadId":"21304","inReplyTo":"1256132122-12509-1-git-send-email-jean@pryen.org","subject":"Re: [PATCH v3] new --dirty option for git describe","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-10-21T22:07:27Z","receivedAt":"2009-10-21T22:07:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thanks.  I'll queue it to 'pu' after minor reformatting and typofixes to\nthe log message.\n\n> 3 Use --dirty as in this patch\n> ...\n> Pro: has an easy fallback to alternative 1 if the world become suddenly\n>      ideal, or at least allows some kind of future transition plan if\n>      people *really* bother:\n>      1- ask that scripts use either \"git describe HEAD\" or\n>         \"git describe --dirty\" (no more \"git describe\")\n>      2- change default\n>      Once the transition is done, the role of the --dirty option will\n>      just be the way to specify an alternative mark (and a noop if alone)\n\nAlso I'd drop this as a Pro specific to #3.  It is clear that the first\none is incompatible from the beginning and there is no \"smooth migration\npath\" possible; also I think the second one can be migrated equally well\nin exactly the same way, so this is not an advantage specific to #3.\n\n> diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh\n> index 8c7e081..e061177 100755\n> --- a/t/t6120-describe.sh\n> +++ b/t/t6120-describe.sh\n> @@ -123,6 +123,20 @@ test_expect_success 'rename tag Q back to A' '\n>  test_expect_success 'pack tag refs' 'git pack-refs'\n>  check_describe A-* HEAD\n>  \n> +check_describe \"A-*[0-9a-f]\" --dirty\n> +\n> +test_expect_success 'set-up dirty working tree' '\n> +\techo >>file\n> +'\n> +\n> +check_describe \"A-*[0-9a-f]-dirty\" --dirty\n> +\n> +check_describe \"A-*[0-9a-f].mod\" --dirty=.mod\n> +\n> +test_expect_success 'describe --dirty HEAD' '\n> +\ttest_must_fail git describe --dirty HEAD\n> +'\n\n\"clean work tree gets no marks; dirty work tree gets expected marks with\nor without the mark string; the option is incompatible with an explicit\nrev\".  Nicely covers all cases.  Good job.\n"}]}