@matheusbsbs / matheus-bagliano / commits / 9f67d2e827
Fork 0

Teach "git describe" --dirty option

With the --dirty option, git describe works on HEAD but append s"-dirty" iff the contents of the work tree differs from HEAD. E.g. $ git describe --dirty v1.6.5-15-gc274db7 $ echo >> Makefile $ git describe --dirty v1.6.5-15-gc274db7-dirty The --dirty option can also be used to specify what is appended, instead of the default string "-dirty". $ git describe --dirty=.mod v1.6.5-15-gc274db7.mod Many build scripts use `git describe` to produce a version number based on the description of HEAD (on which the work tree is based) + saying that if the build contains uncommitted changes. This patch helps the writing of such scripts since `git describe --dirty` does directly the intended thing. Three possiblities were considered while discussing this new feature: 1. Describe the work tree by default and describe HEAD only if "HEAD" is explicitly specified Pro: does the right thing by default (both for users and for scripts) Pro: other git commands that works on the work tree by default Con: breaks existing scripts used by the Linux kernel and other projects 2. Use --worktree instead of --dirty Pro: does what it says: "git describe --worktree" describes the work tree Con: other commands do not require a --worktree option when working on the work tree (it often is the default mode for them) Con: unusable with an optional value: "git describe --worktree=.mod" is quite unintuitive. 3. Use --dirty as in this patch Pro: makes sense to specify an optional value (what the dirty mark is) Pro: does not have any of the big cons of previous alternatives * does not break scripts * is not inconsistent with other git commands This patch takes the third approach. Signed-off-by: Jean Privat <jean@pryen.org> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jean Privat committed Oct 21, 2009 at 09:35 UTC 9f67d2e8279e1885ef2b4681c19cef8534259783
3 files changed +44 -1
Documentation/git-describe.txt
+6
@@ -9,6 +9,7 @@ git-describe - Show the most recent tag that is reachable from a commit
9 SYNOPSIS
10 --------
11 'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] <committish>...
12 +'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]
13
14 DESCRIPTION
15 -----------
@@ -27,6 +28,11 @@ OPTIONS
28 <committish>...::
29 Committish object names to describe.
30
31 +--dirty[=<mark>]::
32 + Describe the working tree.
33 + It means describe HEAD and appends <mark> (`-dirty` by
34 + default) if the working tree is dirty.
35 +
36 --all::
37 Instead of using only the annotated tags, use any ref
38 found in `.git/refs/`. This option enables matching
builtin-describe.c
+24 -1
@@ -5,12 +5,14 @@
5 #include "builtin.h"
6 #include "exec_cmd.h"
7 #include "parse-options.h"
8 +#include "diff.h"
9
10 #define SEEN (1u<<0)
11 #define MAX_TAGS (FLAG_BITS - 1)
12
13 static const char * const describe_usage[] = {
14 "git describe [options] <committish>*",
15 + "git describe [options] --dirty",
16 NULL
17 };
18
@@ -23,6 +25,13 @@ static int max_candidates = 10;
25 static int found_names;
26 static const char *pattern;
27 static int always;
28 +static const char *dirty;
29 +
30 +/* diff-index command arguments to check if working tree is dirty. */
31 +static const char *diff_index_args[] = {
32 + "diff-index", "--quiet", "HEAD", "--", NULL
33 +};
34 +
35
36 struct commit_name {
37 struct tag *tag;
@@ -208,6 +217,8 @@ static void describe(const char *arg, int last_one)
217 display_name(n);
218 if (longformat)
219 show_suffix(0, n->tag ? n->tag->tagged->sha1 : sha1);
220 + if (dirty)
221 + printf("%s", dirty);
222 printf("\n");
223 return;
224 }
@@ -265,7 +276,10 @@ static void describe(const char *arg, int last_one)
276 if (!match_cnt) {
277 const unsigned char *sha1 = cmit->object.sha1;
278 if (always) {
268 - printf("%s\n", find_unique_abbrev(sha1, abbrev));
279 + printf("%s", find_unique_abbrev(sha1, abbrev));
280 + if (dirty)
281 + printf("%s", dirty);
282 + printf("\n");
283 return;
284 }
285 die("cannot describe '%s'", sha1_to_hex(sha1));
@@ -300,6 +314,8 @@ static void describe(const char *arg, int last_one)
314 display_name(all_matches[0].name);
315 if (abbrev)
316 show_suffix(all_matches[0].depth, cmit->object.sha1);
317 + if (dirty)
318 + printf("%s", dirty);
319 printf("\n");
320
321 if (!last_one)
@@ -324,6 +340,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
340 "only consider tags matching <pattern>"),
341 OPT_BOOLEAN(0, "always", &always,
342 "show abbreviated commit object as fallback"),
343 + {OPTION_STRING, 0, "dirty", &dirty, "mark",
344 + "append <mark> on dirty working tree (default: \"-dirty\")",
345 + PARSE_OPT_OPTARG, NULL, (intptr_t) "-dirty"},
346 OPT_END(),
347 };
348
@@ -360,7 +379,11 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
379 }
380
381 if (argc == 0) {
382 + if (dirty && !cmd_diff_index(ARRAY_SIZE(diff_index_args) - 1, diff_index_args, prefix))
383 + dirty = NULL;
384 describe("HEAD", 1);
385 + } else if (dirty) {
386 + die("--dirty is incompatible with committishes");
387 } else {
388 while (argc-- > 0) {
389 describe(*argv++, argc == 0);
t/t6120-describe.sh
+14
@@ -123,6 +123,20 @@ test_expect_success 'rename tag Q back to A' '
123 test_expect_success 'pack tag refs' 'git pack-refs'
124 check_describe A-* HEAD
125
126 +check_describe "A-*[0-9a-f]" --dirty
127 +
128 +test_expect_success 'set-up dirty work tree' '
129 + echo >>file
130 +'
131 +
132 +check_describe "A-*[0-9a-f]-dirty" --dirty
133 +
134 +check_describe "A-*[0-9a-f].mod" --dirty=.mod
135 +
136 +test_expect_success 'describe --dirty HEAD' '
137 + test_must_fail git describe --dirty HEAD
138 +'
139 +
140 test_expect_success 'set-up matching pattern tests' '
141 git tag -a -m test-annotated test-annotated &&
142 echo >>file &&