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

[PATCH v3 09/22] Change check_refname_format() to reject unnormalized refnames

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

Since much of the infrastructure does not work correctly with unnormalized refnames, change check_refname_format() to reject them.

Similarly, change "git check-ref-format" to reject unnormalized refnames by default. But add an option --normalize, which causes "git check-ref-format" to normalize the refname before checking its format, and print the normalized refname. This is exactly the behavior of the old --print option, which is retained but deprecated.

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
 Documentation/git-check-ref-format.txt |   26 ++++++++++++++++++--------
 builtin/check-ref-format.c             |   15 +++++++--------
 refs.c                                 |    3 ---
 refs.h                                 |    2 +-
 t/t1402-check-ref-format.sh            |   31 +++++++++++++++++++++++--------
 5 files changed, 49 insertions(+), 28 deletions(-)
diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt
index 9114751..103e7b1 100644
--- a/Documentation/git-check-ref-format.txt
+++ b/Documentation/git-check-ref-format.txt
@@ -8,8 +8,9 @@ git-check-ref-format - Ensures that a reference name is well formed
 SYNOPSIS
 --------
 [verse]
-'git check-ref-format' [--print]
-       [--[no-]allow-onelevel] [--refspec-pattern] <refname>
+'git check-ref-format' [--normalize]
+       [--[no-]allow-onelevel] [--refspec-pattern]
+       <refname>
 'git check-ref-format' --branch <branchname-shorthand>
 
 DESCRIPTION
@@ -45,7 +46,11 @@ git imposes the following rules on how references are named:
   bracket `[` anywhere.  See the `--refspec-pattern` option below for
   an exception to this rule.
 
-. They cannot end with a slash `/` nor a dot `.`.
+. They cannot begin or end with a slash `/` or contain multiple
+  consecutive slashes (see the `--normalize` option below for an
+  exception to this rule)
+
+. They cannot end with a dot `.`.
 
 . They cannot contain a sequence `@{`.
 
@@ -70,10 +75,6 @@ reference name expressions (see linkgit:gitrevisions[7]):
 
 . at-open-brace `@{` is used as a notation to access a reflog entry.
 
-With the `--print` option, if 'refname' is acceptable, it prints the
-canonicalized name of a hypothetical reference with that name.  That is,
-it prints 'refname' with any extra `/` characters removed.
-
 With the `--branch` option, it expands the ``previous branch syntax''
 `@{-n}`.  For example, `@{-1}` is a way to refer the last branch you
 were on.  This option should be used by porcelains to accept this
@@ -95,6 +96,15 @@ OPTIONS
 	in place of a one full pathname component (e.g.,
 	`foo/{asterisk}/bar` but not `foo/bar{asterisk}`).
 
+--normalize::
+	Normalize 'refname' by removing any leading slash (`/`)
+	characters and collapsing runs of adjacent slashes between
+	name components into a single slash.  Iff the normalized
+	refname is valid then print it to standard output and exit
+	with a status of 0.  (`--print` is a deprecated way to spell
+	`--normalize`.)
+
+
 EXAMPLES
 --------
 
@@ -107,7 +117,7 @@ $ git check-ref-format --branch @{-1}
 * Determine the reference name to use for a new branch:
 +
 ------------
-$ ref=$(git check-ref-format --print "refs/heads/$newbranch") ||
+$ ref=$(git check-ref-format --normalize "refs/heads/$newbranch") ||
 die "we do not like '$newbranch' as a branch name."
 ------------
 
diff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c
index f5df9aa..28a7320 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] [options] <refname>\n"
+"git check-ref-format [--normalize] [options] <refname>\n"
 "   or: git check-ref-format --branch <branchname-shorthand>";
 
 /*
@@ -51,7 +51,7 @@ static int check_ref_format_branch(const char *arg)
 int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
 {
 	int i;
-	int print = 0;
+	int normalize = 0;
 	int flags = 0;
 	const char *refname;
 
@@ -62,8 +62,8 @@ int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
 		return check_ref_format_branch(argv[2]);
 
 	for (i = 1; i < argc && argv[i][0] == '-'; i++) {
-		if (!strcmp(argv[i], "--print"))
-			print = 1;
+		if (!strcmp(argv[i], "--normalize") || !strcmp(argv[i], "--print"))
+			normalize = 1;
 		else if (!strcmp(argv[i], "--allow-onelevel"))
 			flags |= REFNAME_ALLOW_ONELEVEL;
 		else if (!strcmp(argv[i], "--no-allow-onelevel"))
@@ -77,13 +77,12 @@ int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
 		usage(builtin_check_ref_format_usage);
 
 	refname = argv[i];
+	if (normalize)
+		refname = collapse_slashes(refname);
 	if (check_refname_format(refname, flags))
 		return 1;
-
-	if (print) {
-		refname = collapse_slashes(refname);
+	if (normalize)
 		printf("%s\n", refname);
-	}
 
 	return 0;
 }
diff --git a/refs.c b/refs.c
index 5a0bd0f..d2aac24 100644
--- a/refs.c
+++ b/refs.c
@@ -908,9 +908,6 @@ int check_refname_format(const char *ref, int flags)
 	int component_len, component_count = 0;
 
 	while (1) {
-		while (*ref == '/')
-			ref++; /* tolerate leading and repeated slashes */
-
 		/* We are at the start of a path component. */
 		component_len = check_refname_component(ref);
 		if (component_len < 0) {
diff --git a/refs.h b/refs.h
index 48540c0..b0da5fc 100644
--- a/refs.h
+++ b/refs.h
@@ -106,7 +106,7 @@ extern int for_each_reflog(each_ref_fn, void *);
  * REFNAME_ALLOW_ONELEVEL is set in flags, then accept one-level
  * reference names.  If REFNAME_REFSPEC_PATTERN is set in flags, then
  * allow a "*" wildcard character in place of one of the name
- * components.
+ * components.  No leading or repeated slashes are accepted.
  */
 extern int check_refname_format(const char *ref, int flags);
 
diff --git a/t/t1402-check-ref-format.sh b/t/t1402-check-ref-format.sh
index 419788f..710fcca 100755
--- a/t/t1402-check-ref-format.sh
+++ b/t/t1402-check-ref-format.sh
@@ -28,11 +28,17 @@ invalid_ref() {
 invalid_ref ''
 invalid_ref '/'
 invalid_ref '/' --allow-onelevel
+invalid_ref '/' --normalize
+invalid_ref '/' '--allow-onelevel --normalize'
 valid_ref 'foo/bar/baz'
-valid_ref 'refs///heads/foo'
+valid_ref 'foo/bar/baz' --normalize
+invalid_ref 'refs///heads/foo'
+valid_ref 'refs///heads/foo' --normalize
 invalid_ref 'heads/foo/'
-valid_ref '/heads/foo'
-valid_ref '///heads/foo'
+invalid_ref '/heads/foo'
+valid_ref '/heads/foo' --normalize
+invalid_ref '///heads/foo'
+valid_ref '///heads/foo' --normalize
 invalid_ref './foo'
 invalid_ref './foo/bar'
 invalid_ref 'foo/./bar'
@@ -60,12 +66,15 @@ invalid_ref "$ref"
 valid_ref "$ref" --allow-onelevel
 invalid_ref "$ref" --refspec-pattern
 valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+invalid_ref "$ref" --normalize
+valid_ref "$ref" '--allow-onelevel --normalize'
 
 ref='foo/bar'
 valid_ref "$ref"
 valid_ref "$ref" --allow-onelevel
 valid_ref "$ref" --refspec-pattern
 valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+valid_ref "$ref" --normalize
 
 ref='foo/*'
 invalid_ref "$ref"
@@ -78,6 +87,8 @@ invalid_ref "$ref"
 invalid_ref "$ref" --allow-onelevel
 valid_ref "$ref" --refspec-pattern
 valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+invalid_ref "$ref" --normalize
+valid_ref "$ref" '--refspec-pattern --normalize'
 
 ref='foo/*/bar'
 invalid_ref "$ref"
@@ -105,9 +116,13 @@ invalid_ref "$ref" '--refspec-pattern --allow-onelevel'
 
 ref='/foo'
 invalid_ref "$ref"
-valid_ref "$ref" --allow-onelevel
+invalid_ref "$ref" --allow-onelevel
 invalid_ref "$ref" --refspec-pattern
-valid_ref "$ref" '--refspec-pattern --allow-onelevel'
+invalid_ref "$ref" '--refspec-pattern --allow-onelevel'
+invalid_ref "$ref" --normalize
+valid_ref "$ref" '--allow-onelevel --normalize'
+invalid_ref "$ref" '--refspec-pattern --normalize'
+valid_ref "$ref" '--refspec-pattern --allow-onelevel --normalize'
 
 test_expect_success "check-ref-format --branch @{-1}" '
 	T=$(git write-tree) &&
@@ -141,12 +156,12 @@ test_expect_success 'check-ref-format --branch from subdir' '
 
 valid_ref_normalized() {
 	test_expect_success "ref name '$1' simplifies to '$2'" "
-		refname=\$(git check-ref-format --print '$1') &&
+		refname=\$(git check-ref-format --normalize '$1') &&
 		test \"\$refname\" = '$2'"
 }
 invalid_ref_normalized() {
-	test_expect_success "check-ref-format --print rejects '$1'" "
-		test_must_fail git check-ref-format --print '$1'"
+	test_expect_success "check-ref-format --normalize rejects '$1'" "
+		test_must_fail git check-ref-format --normalize '$1'"
 }
 
 valid_ref_normalized 'heads/foo' 'heads/foo'
-- 
1.7.6.8.gd2879
Previous: Michael HaggertyNext: Michael Haggerty
Message 10 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.