diff mbox series

describe: --no-exact-match should not be the same as --exact-match

Message ID xmqqy1jcgbiv.fsf@gitster.g (mailing list archive)
State New, archived
Headers show
Series describe: --no-exact-match should not be the same as --exact-match | expand

Commit Message

Junio C Hamano July 18, 2023, 9:22 p.m. UTC
"git describe --exact-match X" is designed to fail when no tags are
pointing at X.  When given "--no-exact-match", the command line
parser did the same thing as "--exact-match", which was clearly
bogus.

What "--no-exact-match" should do is not entirely clear, though.

Internally, there is an integer "max-candidates" that specifies how
many possible "describe" names are computed (among which, the best
name is picked), and this limit is set to 10 by default.  The
"--candidates=<number>" option sets it to an arbitrary number (the
idea being that by spending a bit more computing resource, we might
be able to come up with a better name).  "--exact-match" uses this
mechanism to express that the user refuses to accept a name that is
any non-zero distance away from a tag, and it does so by setting the
limit to 0.

Making "--no-exact-match" reset the counter to its default value
would allow "git describe --exact-match --no-exact-match X" to
defeat the earlier "--exact-match", and that is the solution we
adopt here in this patch.  However, it is not clear what should
happen in this command:

    git describe --exact-match --candidates=20 --no-exact-match X

Saying --candidates=20 allows us to go inexact, but then should
"--no-exact-match" become a no-op?  The implementation in this patch
resets the counter to its default value, defeating the earlier
setting done by the "--candidates" option.  We probably could solve
it by introducing an extra variable and combining the two after
parse_options() returns, but let's declare that it is not worth
solving and use the simpler solution, i.e. "--no-exact-match" resets
the limit to its default value.

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: Junio C Hamano <gitster@pobox.com>
---
 builtin/describe.c  | 11 ++++++++---
 t/t6120-describe.sh |  8 ++++++++
 2 files changed, 16 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/builtin/describe.c b/builtin/describe.c
index 55b4baaa22..879f8a8d45 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -34,13 +34,15 @@  static const char * const describe_usage[] = {
 	NULL
 };
 
+#define DEFAULT_MAX_CANDIATES 10
+
 static int debug;	/* Display lots of verbose info */
 static int all;	/* Any valid ref can be used */
 static int tags;	/* Allow lightweight tags */
 static int longformat;
 static int first_parent;
 static int abbrev = -1; /* unspecified */
-static int max_candidates = 10;
+static int max_candidates = DEFAULT_MAX_CANDIATES;
 static struct hashmap names;
 static int have_util;
 static struct string_list patterns = STRING_LIST_INIT_NODUP;
@@ -567,8 +569,11 @@  int cmd_describe(int argc, const char **argv, const char *prefix)
 		OPT_BOOL(0, "long",       &longformat, N_("always use long format")),
 		OPT_BOOL(0, "first-parent", &first_parent, N_("only follow first parent")),
 		OPT__ABBREV(&abbrev),
-		OPT_SET_INT(0, "exact-match", &max_candidates,
-			    N_("only output exact matches"), 0),
+		OPT_SET_INT_F(0, "exact-match", &max_candidates,
+			      N_("only output exact matches"), 0, PARSE_OPT_NONEG),
+		OPT_SET_INT_F(0, "no-exact-match", &max_candidates,
+			      N_("only output exact matches"), DEFAULT_MAX_CANDIATES,
+			      PARSE_OPT_NONEG),
 		OPT_INTEGER(0, "candidates", &max_candidates,
 			    N_("consider <n> most recent tags (default: 10)")),
 		OPT_STRING_LIST(0, "match", &patterns, N_("pattern"),
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index c9afcef201..0a5c487540 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -85,6 +85,7 @@  check_describe e-1-gHASH --tags HEAD^^
 check_describe c-2-gHASH --tags HEAD^^2
 check_describe B --tags HEAD^^2^
 check_describe e --tags HEAD^^^
+check_describe e --tags --exact-match HEAD^^^
 
 check_describe heads/main --all HEAD
 check_describe tags/c-6-gHASH --all HEAD^
@@ -96,6 +97,13 @@  check_describe A-3-gHASH --long HEAD^^2
 check_describe c-7-gHASH --tags
 check_describe e-3-gHASH --first-parent --tags
 
+check_describe c-7-gHASH --tags --no-exact-match HEAD
+check_describe e-3-gHASH --first-parent --tags --no-exact-match HEAD
+
+test_expect_success '--exact-match failure' '
+	test_must_fail git describe --exact-match HEAD 2>err
+'
+
 test_expect_success 'describe --contains defaults to HEAD without commit-ish' '
 	echo "A^0" >expect &&
 	git checkout A &&