git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v3 02/22] git check-ref-format: add options --allow-onelevel and --refspec-pattern

From
Michael Haggerty <mhagger@alum.mit.edu>
Date
Sep 15, 2011, 21:10 UTC
Message-ID
<1316121043-29367-3-git-send-email-mhagger@alum.mit.edu>
In-Reply-To
<1316121043-29367-1-git-send-email-mhagger@alum.mit.edu>

Also add tests of the new options. (Actually, one big reason to add the new options is to make it easy to test check_ref_format(), though the options should also be useful to other scripts.)

Interpret the result of check_ref_format() based on which types of refnames are allowed. However, because check_ref_format() can only return a single value, one test case is still broken. Specifically, the case "git check-ref-format --onelevel '*'" incorrectly succeeds because check_ref_format() returns CHECK_REF_FORMAT_ONELEVEL for this refname even though the refname is also CHECK_REF_FORMAT_WILDCARD. The type of check that leads to this failure is used elsewhere in "real" code and could lead to bugs; it will be fixed over the next few commits.

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
 Documentation/git-check-ref-format.txt |   29 +++++++++--
 builtin/check-ref-format.c             |   56 +++++++++++++++++---
 t/t1402-check-ref-format.sh            |   88 +++++++++++++++++++++++++++++---
 3 files changed, 152 insertions(+), 21 deletions(-)
diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt
index c9fdf84..dcb8cc3 100644
--- a/Documentation/git-check-ref-format.txt
+++ b/Documentation/git-check-ref-format.txt
@@ -8,8 +8,8 @@ git-check-ref-format - Ensures that a reference name is well formed
 SYNOPSIS
 --------
 [verse]
-'git check-ref-format' <refname>
-'git check-ref-format' --print <refname>
+'git check-ref-format' [--print]
+       [--[no-]allow-onelevel] [--refspec-pattern] <refname>
 'git check-ref-format' --branch <branchname-shorthand>
 
 DESCRIPTION
@@ -32,14 +32,18 @@ git imposes the following rules on how references are named:
 
 . They must contain at least one `/`. This enforces the presence of a
   category like `heads/`, `tags/` etc. but the actual names are not
-  restricted.
+  restricted.  If the `--allow-onelevel` option is used, this rule
+  is waived.
 
 . They cannot have two consecutive dots `..` anywhere.
 
 . They cannot have ASCII control characters (i.e. bytes whose
   values are lower than \040, or \177 `DEL`), space, tilde `~`,
-  caret `{caret}`, colon `:`, question-mark `?`, asterisk `*`,
-  or open bracket `[` anywhere.
+  caret `{caret}`, or colon `:` anywhere.
+
+. They cannot have question-mark `?`, asterisk `{asterisk}`, or open
+  bracket `[` anywhere.  See the `--refspec-pattern` option below for
+  an exception to this rule.
 
 . They cannot end with a slash `/` nor a dot `.`.
 
@@ -78,6 +82,21 @@ were on.  This option should be used by porcelains to accept this
 syntax anywhere a branch name is expected, so they can act as if you
 typed the branch name.
 
+OPTIONS
+-------
+--allow-onelevel::
+--no-allow-onelevel::
+	Controls whether one-level refnames are accepted (i.e.,
+	refnames that do not contain multiple `/`-separated
+	components).  The default is `--no-allow-onelevel`.
+
+--refspec-pattern::
+	Interpret <refname> as a reference name pattern for a refspec
+	(as used with remote repositories).  If this option is
+	enabled, <refname> is allowed to contain a single `{asterisk}`
+	in place of a one full pathname component (e.g.,
+	`foo/{asterisk}/bar` but not `foo/bar{asterisk}`).
+
 EXAMPLES
 --------
 
diff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c
index 0723cf2..7295954 100644
--- a/builtin/check-ref-format.c
+++ b/builtin/check-ref-format.c
@@ -8,7 +8,7 @@
 #include "strbuf.h"
 
 static const char builtin_check_ref_format_usage[] =
-"git check-ref-format [--print] <refname>\n"
+"git check-ref-format [--print] [options] <refname>\n"
 "   or: git check-ref-format --branch <branchname-shorthand>";
 
 /*
@@ -45,27 +45,65 @@ static int check_ref_format_branch(const char *arg)
 	return 0;
 }
 
-static int check_ref_format_print(const char *arg)
+static void refname_format_print(const char *arg)
 {
 	char *refname = xmalloc(strlen(arg) + 1);
 
-	if (check_ref_format(arg))
-		return 1;
 	collapse_slashes(refname, arg);
 	printf("%s\n", refname);
-	return 0;
 }
 
+#define REFNAME_ALLOW_ONELEVEL 1
+#define REFNAME_REFSPEC_PATTERN 2
+
 int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
 {
+	int i;
+	int print = 0;
+	int flags = 0;
+
 	if (argc == 2 && !strcmp(argv[1], "-h"))
 		usage(builtin_check_ref_format_usage);
 
 	if (argc == 3 && !strcmp(argv[1], "--branch"))
 		return check_ref_format_branch(argv[2]);
-	if (argc == 3 && !strcmp(argv[1], "--print"))
-		return check_ref_format_print(argv[2]);
-	if (argc != 2)
+
+	for (i = 1; i < argc && argv[i][0] == '-'; i++) {
+		if (!strcmp(argv[i], "--print"))
+			print = 1;
+		else if (!strcmp(argv[i], "--allow-onelevel"))
+			flags |= REFNAME_ALLOW_ONELEVEL;
+		else if (!strcmp(argv[i], "--no-allow-onelevel"))
+			flags &= ~REFNAME_ALLOW_ONELEVEL;
+		else if (!strcmp(argv[i], "--refspec-pattern"))
+			flags |= REFNAME_REFSPEC_PATTERN;
+		else
+			usage(builtin_check_ref_format_usage);
+	}
+	if (! (i == argc - 1))
 		usage(builtin_check_ref_format_usage);
-	return !!check_ref_format(argv[1]);
+
+	switch (check_ref_format(argv[i])) {
+	case CHECK_REF_FORMAT_OK:
+		break;
+	case CHECK_REF_FORMAT_ERROR:
+		return 1;
+	case CHECK_REF_FORMAT_ONELEVEL:
+		if (!(flags & REFNAME_ALLOW_ONELEVEL))
+			return 1;
+		else
+			break;
+	case CHECK_REF_FORMAT_WILDCARD:
+		if (!(flags & REFNAME_REFSPEC_PATTERN))
+			return 1;
+		else
+			break;
+	default:
+		die("internal error: unexpected value from check_ref_format()");
+	}
+
+	if (print)
+		refname_format_print(argv[i]);
+
+	return 0;
 }
diff --git a/t/t1402-check-ref-format.sh b/t/t1402-check-ref-format.sh
index dc43171..f551eef 100755
--- a/t/t1402-check-ref-format.sh
+++ b/t/t1402-check-ref-format.sh
@@ -5,25 +5,38 @@ test_description='Test git check-ref-format'
 . ./test-lib.sh
 
 valid_ref() {
-	test_expect_success "ref name '$1' is valid" \
-		"git check-ref-format '$1'"
+	if test "$#" = 1
+	then
+		test_expect_success "ref name '$1' is valid" \
+			"git check-ref-format '$1'"
+	else
+		test_expect_success "ref name '$1' is valid with options $2" \
+			"git check-ref-format $2 '$1'"
+	fi
 }
 invalid_ref() {
-	test_expect_success "ref name '$1' is not valid" \
-		"test_must_fail git check-ref-format '$1'"
+	if test "$#" = 1
+	then
+		test_expect_success "ref name '$1' is invalid" \
+			"test_must_fail git check-ref-format '$1'"
+	else
+		test_expect_success "ref name '$1' is invalid with options $2" \
+			"test_must_fail git check-ref-format $2 '$1'"
+	fi
 }
 
 invalid_ref ''
 invalid_ref '/'
-valid_ref 'heads/foo'
-invalid_ref 'foo'
+invalid_ref '/' --allow-onelevel
 valid_ref 'foo/bar/baz'
 valid_ref 'refs///heads/foo'
 invalid_ref 'heads/foo/'
 valid_ref '/heads/foo'
 valid_ref '///heads/foo'
-invalid_ref '/foo'
 invalid_ref './foo'
+invalid_ref './foo/bar'
+invalid_ref 'foo/./bar'
+invalid_ref 'foo/bar/.'
 invalid_ref '.refs/foo'
 invalid_ref 'heads/foo..bar'
 invalid_ref 'heads/foo?bar'
@@ -38,6 +51,67 @@ invalid_ref 'heads/foo\bar'
 invalid_ref "$(printf 'heads/foo\t')"
 invalid_ref "$(printf 'heads/foo\177')"
 valid_ref "$(printf 'heads/fu\303\237')"
+invalid_ref 'heads/*foo/bar' --refspec-pattern
+invalid_ref 'heads/foo*/bar' --refspec-pattern
+invalid_ref 'heads/f*o/bar' --refspec-pattern
+
+ref='foo'
+invalid_ref "$ref"
+valid_ref "$ref" --allow-onelevel
+invalid_ref "$ref" --refspec-pattern
+valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='foo/bar'
+valid_ref "$ref"
+valid_ref "$ref" --allow-onelevel
+valid_ref "$ref" --refspec-pattern
+valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='foo/*'
+invalid_ref "$ref"
+invalid_ref "$ref" --allow-onelevel
+valid_ref "$ref" --refspec-pattern
+valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='*/foo'
+invalid_ref "$ref"
+invalid_ref "$ref" --allow-onelevel
+valid_ref "$ref" --refspec-pattern
+valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='foo/*/bar'
+invalid_ref "$ref"
+invalid_ref "$ref" --allow-onelevel
+valid_ref "$ref" --refspec-pattern
+valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='*'
+invalid_ref "$ref"
+
+#invalid_ref "$ref" --allow-onelevel
+test_expect_failure "ref name '$ref' is invalid with options --allow-onelevel" \
+	"test_must_fail git check-ref-format --allow-onelevel '$ref'"
+
+invalid_ref "$ref" --refspec-pattern
+valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='foo/*/*'
+invalid_ref "$ref" --refspec-pattern
+invalid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='*/foo/*'
+invalid_ref "$ref" --refspec-pattern
+invalid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='*/*/foo'
+invalid_ref "$ref" --refspec-pattern
+invalid_ref "$ref" '--refspec-pattern --allow-onelevel'
+
+ref='/foo'
+invalid_ref "$ref"
+valid_ref "$ref" --allow-onelevel
+invalid_ref "$ref" --refspec-pattern
+valid_ref "$ref" '--refspec-pattern --allow-onelevel'
 
 test_expect_success "check-ref-format --branch @{-1}" '
 	T=$(git write-tree) &&
-- 
1.7.6.8.gd2879
Previous: Michael HaggertyNext: Michael Haggerty
Message 3 of 60 in “Clean up refname checks and normalization”
  1. 00/22 Clean up refname checks and normalizationMichael Haggerty, Sep 15, 2011
  2. 01/22 t1402: add some more testsMichael Haggerty, Sep 15, 2011
  3. 02/22 git check-ref-format: add options --allow-onelevel and --refspec-patternMichael Haggerty, Sep 15, 2011
  4. 03/22 Change bad_ref_char() to return a boolean valueMichael Haggerty, Sep 15, 2011
  5. 04/22 Change check_ref_format() to take a flags argumentMichael Haggerty, Sep 15, 2011
  6. 05/22 Refactor check_refname_format()Michael Haggerty, Sep 15, 2011
  7. 06/22 Do not allow ".lock" at the end of any refname componentMichael Haggerty, Sep 15, 2011
  8. 07/22 Make collapse_slashes() allocate memory for its resultMichael Haggerty, Sep 15, 2011
  9. 08/22 Inline function refname_format_print()Michael Haggerty, Sep 15, 2011
  10. 09/22 Change check_refname_format() to reject unnormalized refnamesMichael Haggerty, Sep 15, 2011
  11. 10/22 resolve_ref(): explicitly fail if a symlink is not readableMichael Haggerty, Sep 15, 2011
  12. 11/22 resolve_ref(): use prefixcmp()Michael Haggerty, Sep 15, 2011
  13. 12/22 resolve_ref(): only follow a symlink that contains a valid, normalized refnameMichael Haggerty, Sep 15, 2011
  14. 13/22 resolve_ref(): turn buffer into a proper string as soon as possibleMichael Haggerty, Sep 15, 2011
  15. Thomas RastSep 23, 2011
  16. Michael HaggertySep 23, 2011
  17. 1/1 get_sha1_hex(): do not read past a NUL characterMichael Haggerty, Sep 23, 2011
  18. Junio C HamanoSep 23, 2011
  19. Thomas RastOct 5, 2011
  20. Junio C HamanoOct 5, 2011
  21. 14/22 resolve_ref(): extract a function get_packed_ref()Michael Haggerty, Sep 15, 2011
  22. 15/22 resolve_ref(): do not follow incorrectly-formatted symbolic refsMichael Haggerty, Sep 15, 2011
  23. 16/22 remote: use xstrdup() instead of strdup()Michael Haggerty, Sep 15, 2011
  24. 17/22 remote: avoid passing NULL to read_ref()Michael Haggerty, Sep 15, 2011
  25. 18/22 resolve_ref(): verify that the input refname has the right formatMichael Haggerty, Sep 15, 2011
  26. 19/22 resolve_ref(): emit warnings for improperly-formatted referencesMichael Haggerty, Sep 15, 2011
  27. Jeff KingOct 11, 2011
  28. Junio C HamanoOct 11, 2011
  29. Junio C HamanoOct 11, 2011
  30. Re* [PATCH v3 19/22] resolve_ref(): emit warnings for improperly-formatted referencesJunio C Hamano, Oct 11, 2011
  31. Jeff KingOct 11, 2011
  32. Junio C HamanoOct 11, 2011
  33. Jeff KingOct 11, 2011
  34. Junio C HamanoOct 12, 2011
  35. Jeff KingOct 11, 2011
  36. Junio C HamanoOct 11, 2011
  37. Jeff KingOct 12, 2011
  38. Junio C HamanoOct 12, 2011
  39. Jeff KingOct 12, 2011
  40. 1/2 refs.c: move dwim_ref()/dwim_log() from sha1_name.cJunio C Hamano, Oct 12, 2011
  41. 2/2 Restrict ref-like names immediately below $GIT_DIRJunio C Hamano, Oct 12, 2011
  42. Michael HaggertyOct 12, 2011
  43. Junio C HamanoOct 12, 2011
  44. Michael HaggertyOct 12, 2011
  45. Junio C HamanoOct 12, 2011
  46. Junio C HamanoOct 19, 2011
  47. Junio C HamanoOct 19, 2011
  48. Michael HaggertyOct 19, 2011
  49. Junio C HamanoOct 19, 2011
  50. Junio C HamanoOct 19, 2011
  51. resolve_ref(): report breakage to the caller without warningJunio C Hamano, Oct 19, 2011
  52. Michael HaggertyOct 19, 2011
  53. Junio C HamanoOct 19, 2011
  54. Jeff KingOct 12, 2011
  55. Michael HaggertyOct 12, 2011
  56. Junio C HamanoOct 12, 2011
  57. Jeff KingOct 12, 2011
  58. 20/22 resolve_ref(): also treat a too-long SHA1 as invalidMichael Haggerty, Sep 15, 2011
  59. 21/22 resolve_ref(): expand documentationMichael Haggerty, Sep 15, 2011
  60. 22/22 add_ref(): verify that the refname is formatted correctlyMichael Haggerty, Sep 15, 2011

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.