Change check_refname_format() to reject unnormalized refnames

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> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Michael Haggerty committed Sep 15, 2011 at 23:10 UTC a40e6fb67a4aed2d5ffde5792bf7f1996d9666e1
5 files changed +49 -28
Documentation/git-check-ref-format.txt
+18 -8
@@ -8,8 +8,9 @@ git-check-ref-format - Ensures that a reference name is well formed
8 SYNOPSIS
9 --------
10 [verse]
11 -'git check-ref-format' [--print]
12 - [--[no-]allow-onelevel] [--refspec-pattern] <refname>
11 +'git check-ref-format' [--normalize]
12 + [--[no-]allow-onelevel] [--refspec-pattern]
13 + <refname>
14 'git check-ref-format' --branch <branchname-shorthand>
15
16 DESCRIPTION
@@ -45,7 +46,11 @@ git imposes the following rules on how references are named:
46 bracket `[` anywhere. See the `--refspec-pattern` option below for
47 an exception to this rule.
48
48 -. They cannot end with a slash `/` nor a dot `.`.
49 +. They cannot begin or end with a slash `/` or contain multiple
50 + consecutive slashes (see the `--normalize` option below for an
51 + exception to this rule)
52 +
53 +. They cannot end with a dot `.`.
54
55 . They cannot contain a sequence `@{`.
56
@@ -70,10 +75,6 @@ reference name expressions (see linkgit:gitrevisions[7]):
75
76 . at-open-brace `@{` is used as a notation to access a reflog entry.
77
73 -With the `--print` option, if 'refname' is acceptable, it prints the
74 -canonicalized name of a hypothetical reference with that name. That is,
75 -it prints 'refname' with any extra `/` characters removed.
76 -
78 With the `--branch` option, it expands the ``previous branch syntax''
79 `@{-n}`. For example, `@{-1}` is a way to refer the last branch you
80 were on. This option should be used by porcelains to accept this
@@ -95,6 +96,15 @@ OPTIONS
96 in place of a one full pathname component (e.g.,
97 `foo/{asterisk}/bar` but not `foo/bar{asterisk}`).
98
99 +--normalize::
100 + Normalize 'refname' by removing any leading slash (`/`)
101 + characters and collapsing runs of adjacent slashes between
102 + name components into a single slash. Iff the normalized
103 + refname is valid then print it to standard output and exit
104 + with a status of 0. (`--print` is a deprecated way to spell
105 + `--normalize`.)
106 +
107 +
108 EXAMPLES
109 --------
110
@@ -107,7 +117,7 @@ $ git check-ref-format --branch @{-1}
117 * Determine the reference name to use for a new branch:
118 +
119 ------------
110 -$ ref=$(git check-ref-format --print "refs/heads/$newbranch") ||
120 +$ ref=$(git check-ref-format --normalize "refs/heads/$newbranch") ||
121 die "we do not like '$newbranch' as a branch name."
122 ------------
123
builtin/check-ref-format.c
+7 -8
@@ -8,7 +8,7 @@
8 #include "strbuf.h"
9
10 static const char builtin_check_ref_format_usage[] =
11 -"git check-ref-format [--print] [options] <refname>\n"
11 +"git check-ref-format [--normalize] [options] <refname>\n"
12 " or: git check-ref-format --branch <branchname-shorthand>";
13
14 /*
@@ -51,7 +51,7 @@ static int check_ref_format_branch(const char *arg)
51 int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
52 {
53 int i;
54 - int print = 0;
54 + int normalize = 0;
55 int flags = 0;
56 const char *refname;
57
@@ -62,8 +62,8 @@ int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
62 return check_ref_format_branch(argv[2]);
63
64 for (i = 1; i < argc && argv[i][0] == '-'; i++) {
65 - if (!strcmp(argv[i], "--print"))
66 - print = 1;
65 + if (!strcmp(argv[i], "--normalize") || !strcmp(argv[i], "--print"))
66 + normalize = 1;
67 else if (!strcmp(argv[i], "--allow-onelevel"))
68 flags |= REFNAME_ALLOW_ONELEVEL;
69 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)
77 usage(builtin_check_ref_format_usage);
78
79 refname = argv[i];
80 + if (normalize)
81 + refname = collapse_slashes(refname);
82 if (check_refname_format(refname, flags))
83 return 1;
82 -
83 - if (print) {
84 - refname = collapse_slashes(refname);
84 + if (normalize)
85 printf("%s\n", refname);
86 - }
86
87 return 0;
88 }
refs.c
-3
@@ -908,9 +908,6 @@ int check_refname_format(const char *ref, int flags)
908 int component_len, component_count = 0;
909
910 while (1) {
911 - while (*ref == '/')
912 - ref++; /* tolerate leading and repeated slashes */
913 -
911 /* We are at the start of a path component. */
912 component_len = check_refname_component(ref);
913 if (component_len < 0) {
refs.h
+1 -1
@@ -106,7 +106,7 @@ extern int for_each_reflog(each_ref_fn, void *);
106 * REFNAME_ALLOW_ONELEVEL is set in flags, then accept one-level
107 * reference names. If REFNAME_REFSPEC_PATTERN is set in flags, then
108 * allow a "*" wildcard character in place of one of the name
109 - * components.
109 + * components. No leading or repeated slashes are accepted.
110 */
111 extern int check_refname_format(const char *ref, int flags);
112
t/t1402-check-ref-format.sh
+23 -8
@@ -28,11 +28,17 @@ invalid_ref() {
28 invalid_ref ''
29 invalid_ref '/'
30 invalid_ref '/' --allow-onelevel
31 +invalid_ref '/' --normalize
32 +invalid_ref '/' '--allow-onelevel --normalize'
33 valid_ref 'foo/bar/baz'
32 -valid_ref 'refs///heads/foo'
34 +valid_ref 'foo/bar/baz' --normalize
35 +invalid_ref 'refs///heads/foo'
36 +valid_ref 'refs///heads/foo' --normalize
37 invalid_ref 'heads/foo/'
34 -valid_ref '/heads/foo'
35 -valid_ref '///heads/foo'
38 +invalid_ref '/heads/foo'
39 +valid_ref '/heads/foo' --normalize
40 +invalid_ref '///heads/foo'
41 +valid_ref '///heads/foo' --normalize
42 invalid_ref './foo'
43 invalid_ref './foo/bar'
44 invalid_ref 'foo/./bar'
@@ -60,12 +66,15 @@ invalid_ref "$ref"
66 valid_ref "$ref" --allow-onelevel
67 invalid_ref "$ref" --refspec-pattern
68 valid_ref "$ref" '--refspec-pattern --allow-onelevel'
69 +invalid_ref "$ref" --normalize
70 +valid_ref "$ref" '--allow-onelevel --normalize'
71
72 ref='foo/bar'
73 valid_ref "$ref"
74 valid_ref "$ref" --allow-onelevel
75 valid_ref "$ref" --refspec-pattern
76 valid_ref "$ref" '--refspec-pattern --allow-onelevel'
77 +valid_ref "$ref" --normalize
78
79 ref='foo/*'
80 invalid_ref "$ref"
@@ -78,6 +87,8 @@ invalid_ref "$ref"
87 invalid_ref "$ref" --allow-onelevel
88 valid_ref "$ref" --refspec-pattern
89 valid_ref "$ref" '--refspec-pattern --allow-onelevel'
90 +invalid_ref "$ref" --normalize
91 +valid_ref "$ref" '--refspec-pattern --normalize'
92
93 ref='foo/*/bar'
94 invalid_ref "$ref"
@@ -105,9 +116,13 @@ invalid_ref "$ref" '--refspec-pattern --allow-onelevel'
116
117 ref='/foo'
118 invalid_ref "$ref"
108 -valid_ref "$ref" --allow-onelevel
119 +invalid_ref "$ref" --allow-onelevel
120 invalid_ref "$ref" --refspec-pattern
110 -valid_ref "$ref" '--refspec-pattern --allow-onelevel'
121 +invalid_ref "$ref" '--refspec-pattern --allow-onelevel'
122 +invalid_ref "$ref" --normalize
123 +valid_ref "$ref" '--allow-onelevel --normalize'
124 +invalid_ref "$ref" '--refspec-pattern --normalize'
125 +valid_ref "$ref" '--refspec-pattern --allow-onelevel --normalize'
126
127 test_expect_success "check-ref-format --branch @{-1}" '
128 T=$(git write-tree) &&
@@ -141,12 +156,12 @@ test_expect_success 'check-ref-format --branch from subdir' '
156
157 valid_ref_normalized() {
158 test_expect_success "ref name '$1' simplifies to '$2'" "
144 - refname=\$(git check-ref-format --print '$1') &&
159 + refname=\$(git check-ref-format --normalize '$1') &&
160 test \"\$refname\" = '$2'"
161 }
162 invalid_ref_normalized() {
148 - test_expect_success "check-ref-format --print rejects '$1'" "
149 - test_must_fail git check-ref-format --print '$1'"
163 + test_expect_success "check-ref-format --normalize rejects '$1'" "
164 + test_must_fail git check-ref-format --normalize '$1'"
165 }
166
167 valid_ref_normalized 'heads/foo' 'heads/foo'