Merge branch 'jp/dirty-describe'
authorJunio C Hamano <gitster@pobox.com>
Tue, 10 Nov 2009 20:30:43 +0000 (12:30 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 10 Nov 2009 20:30:43 +0000 (12:30 -0800)
* jp/dirty-describe:
Teach "git describe" --dirty option

1  2 
Documentation/git-describe.txt
builtin-describe.c
t/t6120-describe.sh
index 2f979167819f0e4500b998b41092e18ef053cead,5253d86118f1f8345e46fac64994a28a15f065cb..d7329eb4c0b5c7c7190870dded3b31b6d068eb78
@@@ -9,6 -9,7 +9,7 @@@ git-describe - Show the most recent ta
  SYNOPSIS
  --------
  'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] <committish>...
+ 'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]
  
  DESCRIPTION
  -----------
@@@ -27,6 -28,11 +28,11 @@@ OPTION
  <committish>...::
        Committish object names to describe.
  
+ --dirty[=<mark>]::
+       Describe the working tree.
+       It means describe HEAD and appends <mark> (`-dirty` by
+       default) if the working tree is dirty.
  --all::
        Instead of using only the annotated tags, use any ref
        found in `.git/refs/`.  This option enables matching
@@@ -44,9 -50,7 +50,9 @@@
  
  --abbrev=<n>::
        Instead of using the default 7 hexadecimal digits as the
 -      abbreviated object name, use <n> digits.
 +      abbreviated object name, use <n> digits, or as many digits
 +      as needed to form a unique object name.  An <n> of 0
 +      will suppress long format, only showing the closest tag.
  
  --candidates=<n>::
        Instead of considering only the 10 most recent tags as
@@@ -70,8 -74,8 +76,8 @@@
        This is useful when you want to see parts of the commit object name
        in "describe" output, even when the commit in question happens to be
        a tagged version.  Instead of just emitting the tag name, it will
 -      describe such a commit as v1.2-0-deadbeef (0th commit since tag v1.2
 -      that points at object deadbeef....).
 +      describe such a commit as v1.2-0-gdeadbee (0th commit since tag v1.2
 +      that points at object deadbee....).
  
  --match <pattern>::
        Only consider tags matching the given pattern (can be used to avoid
@@@ -110,7 -114,7 +116,7 @@@ the output shows the reference path as 
        [torvalds@g5 git]$ git describe --all --abbrev=4 v1.0.5^2
        tags/v1.0.0-21-g975b
  
 -      [torvalds@g5 git]$ git describe --all HEAD^
 +      [torvalds@g5 git]$ git describe --all --abbrev=4 HEAD^
        heads/lt/describe-7-g975b
  
  With --abbrev set to 0, the command can be used to find the
@@@ -119,13 -123,6 +125,13 @@@ closest tagname without any suffix
        [torvalds@g5 git]$ git describe --abbrev=0 v1.0.5^2
        tags/v1.0.0
  
 +Note that the suffix you get if you type these commands today may be
 +longer than what Linus saw above when he ran these commands, as your
 +git repository may have new commits whose object names begin with
 +975b that did not exist back then, and "-g975b" suffix alone may not
 +be sufficient to disambiguate these commits.
 +
 +
  SEARCH STRATEGY
  ---------------
  
diff --combined builtin-describe.c
index eaa8a9d229c97ebaab9ee3aa09d2456f68cd172c,7dbbee36accecfbfc9b592c9f7f35678ca24a515..390c14ec5953447bc2458ba8cc39d35373fdeb51
@@@ -5,12 -5,14 +5,14 @@@
  #include "builtin.h"
  #include "exec_cmd.h"
  #include "parse-options.h"
+ #include "diff.h"
  
  #define SEEN          (1u<<0)
  #define MAX_TAGS      (FLAG_BITS - 1)
  
  static const char * const describe_usage[] = {
        "git describe [options] <committish>*",
+       "git describe [options] --dirty",
        NULL
  };
  
@@@ -23,6 -25,13 +25,13 @@@ static int max_candidates = 10
  static int found_names;
  static const char *pattern;
  static int always;
+ static const char *dirty;
+ /* diff-index command arguments to check if working tree is dirty. */
+ static const char *diff_index_args[] = {
+       "diff-index", "--quiet", "HEAD", "--", NULL
+ };
  
  struct commit_name {
        struct tag *tag;
@@@ -180,6 -189,7 +189,6 @@@ static void describe(const char *arg, i
        unsigned char sha1[20];
        struct commit *cmit, *gave_up_on = NULL;
        struct commit_list *list;
 -      static int initialized = 0;
        struct commit_name *n;
        struct possible_tag all_matches[MAX_TAGS];
        unsigned int match_cnt = 0, annotated_cnt = 0, cur_match;
        if (!cmit)
                die("%s is not a valid '%s' object", arg, commit_type);
  
 -      if (!initialized) {
 -              initialized = 1;
 -              for_each_ref(get_name, NULL);
 -      }
 -
 -      if (!found_names)
 -              die("cannot describe '%s'", sha1_to_hex(sha1));
 -
        n = cmit->util;
        if (n) {
                /*
                display_name(n);
                if (longformat)
                        show_suffix(0, n->tag ? n->tag->tagged->sha1 : sha1);
+               if (dirty)
+                       printf("%s", dirty);
                printf("\n");
                return;
        }
        if (!match_cnt) {
                const unsigned char *sha1 = cmit->object.sha1;
                if (always) {
-                       printf("%s\n", find_unique_abbrev(sha1, abbrev));
+                       printf("%s", find_unique_abbrev(sha1, abbrev));
+                       if (dirty)
+                               printf("%s", dirty);
+                       printf("\n");
                        return;
                }
                die("cannot describe '%s'", sha1_to_hex(sha1));
        display_name(all_matches[0].name);
        if (abbrev)
                show_suffix(all_matches[0].depth, cmit->object.sha1);
+       if (dirty)
+               printf("%s", dirty);
        printf("\n");
  
        if (!last_one)
@@@ -315,6 -340,9 +331,9 @@@ int cmd_describe(int argc, const char *
                           "only consider tags matching <pattern>"),
                OPT_BOOLEAN(0, "always",     &always,
                           "show abbreviated commit object as fallback"),
+               {OPTION_STRING, 0, "dirty",  &dirty, "mark",
+                          "append <mark> on dirty working tree (default: \"-dirty\")",
+                PARSE_OPT_OPTARG, NULL, (intptr_t) "-dirty"},
                OPT_END(),
        };
  
                return cmd_name_rev(i + argc, args, prefix);
        }
  
 +      for_each_ref(get_name, NULL);
 +      if (!found_names && !always)
 +              die("No names found, cannot describe anything.");
 +
        if (argc == 0) {
+               if (dirty && !cmd_diff_index(ARRAY_SIZE(diff_index_args) - 1, diff_index_args, prefix))
+                       dirty = NULL;
                describe("HEAD", 1);
+       } else if (dirty) {
+               die("--dirty is incompatible with committishes");
        } else {
                while (argc-- > 0) {
                        describe(*argv++, argc == 0);
diff --combined t/t6120-describe.sh
index f5a1b615f65ecac2becff67d47842e7aed3d6091,100c4d99fbb4d693b3d972652222fa826efdd07c..c050f94bc626c340d27ebfca824116f12b4fda26
@@@ -34,8 -34,6 +34,8 @@@ test_expect_success setup 
        echo one >file && git add file && git commit -m initial &&
        one=$(git rev-parse HEAD) &&
  
 +      git describe --always HEAD &&
 +
        test_tick &&
        echo two >file && git add file && git commit -m second &&
        two=$(git rev-parse HEAD) &&
@@@ -125,6 -123,20 +125,20 @@@ test_expect_success 'rename tag Q back 
  test_expect_success 'pack tag refs' 'git pack-refs'
  check_describe A-* HEAD
  
+ check_describe "A-*[0-9a-f]" --dirty
+ test_expect_success 'set-up dirty work tree' '
+       echo >>file
+ '
+ check_describe "A-*[0-9a-f]-dirty" --dirty
+ check_describe "A-*[0-9a-f].mod" --dirty=.mod
+ test_expect_success 'describe --dirty HEAD' '
+       test_must_fail git describe --dirty HEAD
+ '
  test_expect_success 'set-up matching pattern tests' '
        git tag -a -m test-annotated test-annotated &&
        echo >>file &&