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>
This commit is contained in:
Michael Haggerty 2011-09-15 23:10:30 +02:00 committed by Junio C Hamano
parent a5e4ec063a
commit a40e6fb67a
5 changed files with 49 additions and 28 deletions

View File

@ -8,8 +8,9 @@ git-check-ref-format - Ensures that a reference name is well formed
SYNOPSIS SYNOPSIS
-------- --------
[verse] [verse]
'git check-ref-format' [--print] 'git check-ref-format' [--normalize]
[--[no-]allow-onelevel] [--refspec-pattern] <refname> [--[no-]allow-onelevel] [--refspec-pattern]
<refname>
'git check-ref-format' --branch <branchname-shorthand> 'git check-ref-format' --branch <branchname-shorthand>
DESCRIPTION DESCRIPTION
@ -45,7 +46,11 @@ git imposes the following rules on how references are named:
bracket `[` anywhere. See the `--refspec-pattern` option below for bracket `[` anywhere. See the `--refspec-pattern` option below for
an exception to this rule. 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 `@{`. . 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. . 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'' With the `--branch` option, it expands the ``previous branch syntax''
`@{-n}`. For example, `@{-1}` is a way to refer the last branch you `@{-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 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., in place of a one full pathname component (e.g.,
`foo/{asterisk}/bar` but not `foo/bar{asterisk}`). `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 EXAMPLES
-------- --------
@ -107,7 +117,7 @@ $ git check-ref-format --branch @{-1}
* Determine the reference name to use for a new branch: * 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." die "we do not like '$newbranch' as a branch name."
------------ ------------

View File

@ -8,7 +8,7 @@
#include "strbuf.h" #include "strbuf.h"
static const char builtin_check_ref_format_usage[] = 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>"; " 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 cmd_check_ref_format(int argc, const char **argv, const char *prefix)
{ {
int i; int i;
int print = 0; int normalize = 0;
int flags = 0; int flags = 0;
const char *refname; 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]); return check_ref_format_branch(argv[2]);
for (i = 1; i < argc && argv[i][0] == '-'; i++) { for (i = 1; i < argc && argv[i][0] == '-'; i++) {
if (!strcmp(argv[i], "--print")) if (!strcmp(argv[i], "--normalize") || !strcmp(argv[i], "--print"))
print = 1; normalize = 1;
else if (!strcmp(argv[i], "--allow-onelevel")) else if (!strcmp(argv[i], "--allow-onelevel"))
flags |= REFNAME_ALLOW_ONELEVEL; flags |= REFNAME_ALLOW_ONELEVEL;
else if (!strcmp(argv[i], "--no-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); usage(builtin_check_ref_format_usage);
refname = argv[i]; refname = argv[i];
if (normalize)
refname = collapse_slashes(refname);
if (check_refname_format(refname, flags)) if (check_refname_format(refname, flags))
return 1; return 1;
if (normalize)
if (print) {
refname = collapse_slashes(refname);
printf("%s\n", refname); printf("%s\n", refname);
}
return 0; return 0;
} }

3
refs.c
View File

@ -908,9 +908,6 @@ int check_refname_format(const char *ref, int flags)
int component_len, component_count = 0; int component_len, component_count = 0;
while (1) { while (1) {
while (*ref == '/')
ref++; /* tolerate leading and repeated slashes */
/* We are at the start of a path component. */ /* We are at the start of a path component. */
component_len = check_refname_component(ref); component_len = check_refname_component(ref);
if (component_len < 0) { if (component_len < 0) {

2
refs.h
View File

@ -106,7 +106,7 @@ extern int for_each_reflog(each_ref_fn, void *);
* REFNAME_ALLOW_ONELEVEL is set in flags, then accept one-level * REFNAME_ALLOW_ONELEVEL is set in flags, then accept one-level
* reference names. If REFNAME_REFSPEC_PATTERN is set in flags, then * reference names. If REFNAME_REFSPEC_PATTERN is set in flags, then
* allow a "*" wildcard character in place of one of the name * 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); extern int check_refname_format(const char *ref, int flags);

View File

@ -28,11 +28,17 @@ invalid_ref() {
invalid_ref '' invalid_ref ''
invalid_ref '/' invalid_ref '/'
invalid_ref '/' --allow-onelevel invalid_ref '/' --allow-onelevel
invalid_ref '/' --normalize
invalid_ref '/' '--allow-onelevel --normalize'
valid_ref 'foo/bar/baz' 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/' invalid_ref 'heads/foo/'
valid_ref '/heads/foo' invalid_ref '/heads/foo'
valid_ref '///heads/foo' valid_ref '/heads/foo' --normalize
invalid_ref '///heads/foo'
valid_ref '///heads/foo' --normalize
invalid_ref './foo' invalid_ref './foo'
invalid_ref './foo/bar' invalid_ref './foo/bar'
invalid_ref 'foo/./bar' invalid_ref 'foo/./bar'
@ -60,12 +66,15 @@ invalid_ref "$ref"
valid_ref "$ref" --allow-onelevel valid_ref "$ref" --allow-onelevel
invalid_ref "$ref" --refspec-pattern invalid_ref "$ref" --refspec-pattern
valid_ref "$ref" '--refspec-pattern --allow-onelevel' valid_ref "$ref" '--refspec-pattern --allow-onelevel'
invalid_ref "$ref" --normalize
valid_ref "$ref" '--allow-onelevel --normalize'
ref='foo/bar' ref='foo/bar'
valid_ref "$ref" valid_ref "$ref"
valid_ref "$ref" --allow-onelevel valid_ref "$ref" --allow-onelevel
valid_ref "$ref" --refspec-pattern valid_ref "$ref" --refspec-pattern
valid_ref "$ref" '--refspec-pattern --allow-onelevel' valid_ref "$ref" '--refspec-pattern --allow-onelevel'
valid_ref "$ref" --normalize
ref='foo/*' ref='foo/*'
invalid_ref "$ref" invalid_ref "$ref"
@ -78,6 +87,8 @@ invalid_ref "$ref"
invalid_ref "$ref" --allow-onelevel invalid_ref "$ref" --allow-onelevel
valid_ref "$ref" --refspec-pattern valid_ref "$ref" --refspec-pattern
valid_ref "$ref" '--refspec-pattern --allow-onelevel' valid_ref "$ref" '--refspec-pattern --allow-onelevel'
invalid_ref "$ref" --normalize
valid_ref "$ref" '--refspec-pattern --normalize'
ref='foo/*/bar' ref='foo/*/bar'
invalid_ref "$ref" invalid_ref "$ref"
@ -105,9 +116,13 @@ invalid_ref "$ref" '--refspec-pattern --allow-onelevel'
ref='/foo' ref='/foo'
invalid_ref "$ref" invalid_ref "$ref"
valid_ref "$ref" --allow-onelevel invalid_ref "$ref" --allow-onelevel
invalid_ref "$ref" --refspec-pattern 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}" ' test_expect_success "check-ref-format --branch @{-1}" '
T=$(git write-tree) && T=$(git write-tree) &&
@ -141,12 +156,12 @@ test_expect_success 'check-ref-format --branch from subdir' '
valid_ref_normalized() { valid_ref_normalized() {
test_expect_success "ref name '$1' simplifies to '$2'" " 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'" test \"\$refname\" = '$2'"
} }
invalid_ref_normalized() { invalid_ref_normalized() {
test_expect_success "check-ref-format --print rejects '$1'" " test_expect_success "check-ref-format --normalize rejects '$1'" "
test_must_fail git check-ref-format --print '$1'" test_must_fail git check-ref-format --normalize '$1'"
} }
valid_ref_normalized 'heads/foo' 'heads/foo' valid_ref_normalized 'heads/foo' 'heads/foo'