describe: fix --no-exact-match

Since 2c33f75754 (Teach git-describe --exact-match to avoid expensive tag searches, 2008-02-24) git describe accepts --no-exact-match, but it does the same as --exact-match, an alias for --candidates=0. That's because it's defined using OPT_SET_INT with a value of 0, which sets 0 when negated as well. Let --no-exact-match set the number of candidates to the default value instead. Users that need a more specific lack of exactitude can specify their preferred value using --candidates, as before. The "--no-exact-match" option was not covered in the tests, so let's add a few. Also add a case where --exact-match option is used on a commit that cannot be described without distance from tags and make sure the command fails. Signed-off-by: René Scharfe <l.s.r@web.de> [jc: added trivial tests] Signed-off-by: Junio C Hamano <gitster@pobox.com>

René Scharfe committed Jul 21, 2023 at 15:41 UTC c95ae3ff9cdcbe6229dc3aa4cd7aa14b1354759a
2 files changed +22 -3
builtin/describe.c
+14 -3
@@ -24,6 +24,7 @@
24 #include "commit-slab.h"
25
26 #define MAX_TAGS (FLAG_BITS - 1)
27 +#define DEFAULT_CANDIDATES 10
28
29 define_commit_slab(commit_names, struct commit_name *);
30
@@ -40,7 +41,7 @@ static int tags; /* Allow lightweight tags */
41 static int longformat;
42 static int first_parent;
43 static int abbrev = -1; /* unspecified */
43 -static int max_candidates = 10;
44 +static int max_candidates = DEFAULT_CANDIDATES;
45 static struct hashmap names;
46 static int have_util;
47 static struct string_list patterns = STRING_LIST_INIT_NODUP;
@@ -556,6 +557,15 @@ static void describe(const char *arg, int last_one)
557 strbuf_release(&sb);
558 }
559
560 +static int option_parse_exact_match(const struct option *opt, const char *arg,
561 + int unset)
562 +{
563 + BUG_ON_OPT_ARG(arg);
564 +
565 + max_candidates = unset ? DEFAULT_CANDIDATES : 0;
566 + return 0;
567 +}
568 +
569 int cmd_describe(int argc, const char **argv, const char *prefix)
570 {
571 int contains = 0;
@@ -567,8 +577,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
577 OPT_BOOL(0, "long", &longformat, N_("always use long format")),
578 OPT_BOOL(0, "first-parent", &first_parent, N_("only follow first parent")),
579 OPT__ABBREV(&abbrev),
570 - OPT_SET_INT(0, "exact-match", &max_candidates,
571 - N_("only output exact matches"), 0),
580 + OPT_CALLBACK_F(0, "exact-match", NULL, NULL,
581 + N_("only output exact matches"),
582 + PARSE_OPT_NOARG, option_parse_exact_match),
583 OPT_INTEGER(0, "candidates", &max_candidates,
584 N_("consider <n> most recent tags (default: 10)")),
585 OPT_STRING_LIST(0, "match", &patterns, N_("pattern"),
t/t6120-describe.sh
+8
@@ -85,6 +85,7 @@ check_describe e-1-gHASH --tags HEAD^^
85 check_describe c-2-gHASH --tags HEAD^^2
86 check_describe B --tags HEAD^^2^
87 check_describe e --tags HEAD^^^
88 +check_describe e --tags --exact-match HEAD^^^
89
90 check_describe heads/main --all HEAD
91 check_describe tags/c-6-gHASH --all HEAD^
@@ -96,6 +97,13 @@ check_describe A-3-gHASH --long HEAD^^2
97 check_describe c-7-gHASH --tags
98 check_describe e-3-gHASH --first-parent --tags
99
100 +check_describe c-7-gHASH --tags --no-exact-match HEAD
101 +check_describe e-3-gHASH --first-parent --tags --no-exact-match HEAD
102 +
103 +test_expect_success '--exact-match failure' '
104 + test_must_fail git describe --exact-match HEAD 2>err
105 +'
106 +
107 test_expect_success 'describe --contains defaults to HEAD without commit-ish' '
108 echo "A^0" >expect &&
109 git checkout A &&