Skip to content

Commit 9bd5000

Browse files
committed
Merge branch 'mh/check-ref-format-3'
* mh/check-ref-format-3: (23 commits) add_ref(): verify that the refname is formatted correctly resolve_ref(): expand documentation resolve_ref(): also treat a too-long SHA1 as invalid resolve_ref(): emit warnings for improperly-formatted references resolve_ref(): verify that the input refname has the right format remote: avoid passing NULL to read_ref() remote: use xstrdup() instead of strdup() resolve_ref(): do not follow incorrectly-formatted symbolic refs resolve_ref(): extract a function get_packed_ref() resolve_ref(): turn buffer into a proper string as soon as possible resolve_ref(): only follow a symlink that contains a valid, normalized refname resolve_ref(): use prefixcmp() resolve_ref(): explicitly fail if a symlink is not readable Change check_refname_format() to reject unnormalized refnames Inline function refname_format_print() Make collapse_slashes() allocate memory for its result Do not allow ".lock" at the end of any refname component Refactor check_refname_format() Change check_ref_format() to take a flags argument Change bad_ref_char() to return a boolean value ...
2 parents 11fa509 + dce4bab commit 9bd5000

24 files changed

+426
-225
lines changed

Documentation/git-check-ref-format.txt

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ git-check-ref-format - Ensures that a reference name is well formed
88
SYNOPSIS
99
--------
1010
[verse]
11-
'git check-ref-format' <refname>
12-
'git check-ref-format' --print <refname>
11+
'git check-ref-format' [--normalize]
12+
[--[no-]allow-onelevel] [--refspec-pattern]
13+
<refname>
1314
'git check-ref-format' --branch <branchname-shorthand>
1415

1516
DESCRIPTION
@@ -28,22 +29,28 @@ git imposes the following rules on how references are named:
2829

2930
. They can include slash `/` for hierarchical (directory)
3031
grouping, but no slash-separated component can begin with a
31-
dot `.`.
32+
dot `.` or end with the sequence `.lock`.
3233

3334
. They must contain at least one `/`. This enforces the presence of a
3435
category like `heads/`, `tags/` etc. but the actual names are not
35-
restricted.
36+
restricted. If the `--allow-onelevel` option is used, this rule
37+
is waived.
3638

3739
. They cannot have two consecutive dots `..` anywhere.
3840

3941
. They cannot have ASCII control characters (i.e. bytes whose
4042
values are lower than \040, or \177 `DEL`), space, tilde `~`,
41-
caret `{caret}`, colon `:`, question-mark `?`, asterisk `*`,
42-
or open bracket `[` anywhere.
43+
caret `{caret}`, or colon `:` anywhere.
4344

44-
. They cannot end with a slash `/` nor a dot `.`.
45+
. They cannot have question-mark `?`, asterisk `{asterisk}`, or open
46+
bracket `[` anywhere. See the `--refspec-pattern` option below for
47+
an exception to this rule.
4548

46-
. They cannot end with the sequence `.lock`.
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 `.`.
4754

4855
. They cannot contain a sequence `@{`.
4956

@@ -68,16 +75,36 @@ reference name expressions (see linkgit:gitrevisions[7]):
6875

6976
. at-open-brace `@{` is used as a notation to access a reflog entry.
7077

71-
With the `--print` option, if 'refname' is acceptable, it prints the
72-
canonicalized name of a hypothetical reference with that name. That is,
73-
it prints 'refname' with any extra `/` characters removed.
74-
7578
With the `--branch` option, it expands the ``previous branch syntax''
7679
`@{-n}`. For example, `@{-1}` is a way to refer the last branch you
7780
were on. This option should be used by porcelains to accept this
7881
syntax anywhere a branch name is expected, so they can act as if you
7982
typed the branch name.
8083

84+
OPTIONS
85+
-------
86+
--allow-onelevel::
87+
--no-allow-onelevel::
88+
Controls whether one-level refnames are accepted (i.e.,
89+
refnames that do not contain multiple `/`-separated
90+
components). The default is `--no-allow-onelevel`.
91+
92+
--refspec-pattern::
93+
Interpret <refname> as a reference name pattern for a refspec
94+
(as used with remote repositories). If this option is
95+
enabled, <refname> is allowed to contain a single `{asterisk}`
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+
81108
EXAMPLES
82109
--------
83110

@@ -90,7 +117,7 @@ $ git check-ref-format --branch @{-1}
90117
* Determine the reference name to use for a new branch:
91118
+
92119
------------
93-
$ ref=$(git check-ref-format --print "refs/heads/$newbranch") ||
120+
$ ref=$(git check-ref-format --normalize "refs/heads/$newbranch") ||
94121
die "we do not like '$newbranch' as a branch name."
95122
------------
96123

builtin/check-ref-format.c

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,32 @@
88
#include "strbuf.h"
99

1010
static const char builtin_check_ref_format_usage[] =
11-
"git check-ref-format [--print] <refname>\n"
11+
"git check-ref-format [--normalize] [options] <refname>\n"
1212
" or: git check-ref-format --branch <branchname-shorthand>";
1313

1414
/*
15-
* Remove leading slashes and replace each run of adjacent slashes in
16-
* src with a single slash, and write the result to dst.
15+
* Return a copy of refname but with leading slashes removed and runs
16+
* of adjacent slashes replaced with single slashes.
1717
*
1818
* This function is similar to normalize_path_copy(), but stripped down
1919
* to meet check_ref_format's simpler needs.
2020
*/
21-
static void collapse_slashes(char *dst, const char *src)
21+
static char *collapse_slashes(const char *refname)
2222
{
23+
char *ret = xmalloc(strlen(refname) + 1);
2324
char ch;
2425
char prev = '/';
26+
char *cp = ret;
2527

26-
while ((ch = *src++) != '\0') {
28+
while ((ch = *refname++) != '\0') {
2729
if (prev == '/' && ch == prev)
2830
continue;
2931

30-
*dst++ = ch;
32+
*cp++ = ch;
3133
prev = ch;
3234
}
33-
*dst = '\0';
35+
*cp = '\0';
36+
return ret;
3437
}
3538

3639
static int check_ref_format_branch(const char *arg)
@@ -45,27 +48,41 @@ static int check_ref_format_branch(const char *arg)
4548
return 0;
4649
}
4750

48-
static int check_ref_format_print(const char *arg)
49-
{
50-
char *refname = xmalloc(strlen(arg) + 1);
51-
52-
if (check_ref_format(arg))
53-
return 1;
54-
collapse_slashes(refname, arg);
55-
printf("%s\n", refname);
56-
return 0;
57-
}
58-
5951
int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
6052
{
53+
int i;
54+
int normalize = 0;
55+
int flags = 0;
56+
const char *refname;
57+
6158
if (argc == 2 && !strcmp(argv[1], "-h"))
6259
usage(builtin_check_ref_format_usage);
6360

6461
if (argc == 3 && !strcmp(argv[1], "--branch"))
6562
return check_ref_format_branch(argv[2]);
66-
if (argc == 3 && !strcmp(argv[1], "--print"))
67-
return check_ref_format_print(argv[2]);
68-
if (argc != 2)
63+
64+
for (i = 1; i < argc && argv[i][0] == '-'; i++) {
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"))
70+
flags &= ~REFNAME_ALLOW_ONELEVEL;
71+
else if (!strcmp(argv[i], "--refspec-pattern"))
72+
flags |= REFNAME_REFSPEC_PATTERN;
73+
else
74+
usage(builtin_check_ref_format_usage);
75+
}
76+
if (! (i == argc - 1))
6977
usage(builtin_check_ref_format_usage);
70-
return !!check_ref_format(argv[1]);
78+
79+
refname = argv[i];
80+
if (normalize)
81+
refname = collapse_slashes(refname);
82+
if (check_refname_format(refname, flags))
83+
return 1;
84+
if (normalize)
85+
printf("%s\n", refname);
86+
87+
return 0;
7188
}

builtin/checkout.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -871,7 +871,7 @@ static int parse_branchname_arg(int argc, const char **argv,
871871
new->name = arg;
872872
setup_branch_path(new);
873873

874-
if (check_ref_format(new->path) == CHECK_REF_FORMAT_OK &&
874+
if (!check_refname_format(new->path, 0) &&
875875
resolve_ref(new->path, branch_rev, 1, NULL))
876876
hashcpy(rev, branch_rev);
877877
else

builtin/fetch-pack.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
546546
for (ref = *refs; ref; ref = next) {
547547
next = ref->next;
548548
if (!memcmp(ref->name, "refs/", 5) &&
549-
check_ref_format(ref->name + 5))
549+
check_refname_format(ref->name + 5, 0))
550550
; /* trash */
551551
else if (args.fetch_all &&
552552
(!args.depth || prefixcmp(ref->name, "refs/tags/") )) {

builtin/receive-pack.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ static const char *update(struct command *cmd)
396396
struct ref_lock *lock;
397397

398398
/* only refs/... are allowed */
399-
if (prefixcmp(name, "refs/") || check_ref_format(name + 5)) {
399+
if (prefixcmp(name, "refs/") || check_refname_format(name + 5, 0)) {
400400
rp_error("refusing to create funny ref '%s' remotely", name);
401401
return "funny refname";
402402
}

builtin/replace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ static int replace_object(const char *object_ref, const char *replace_ref,
9494
"refs/replace/%s",
9595
sha1_to_hex(object)) > sizeof(ref) - 1)
9696
die("replace ref name too long: %.*s...", 50, ref);
97-
if (check_ref_format(ref))
97+
if (check_refname_format(ref, 0))
9898
die("'%s' is not a valid ref name.", ref);
9999

100100
if (!resolve_ref(ref, prev, 1, NULL))

builtin/show-ref.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ static int exclude_existing(const char *match)
145145
if (strncmp(ref, match, matchlen))
146146
continue;
147147
}
148-
if (check_ref_format(ref)) {
148+
if (check_refname_format(ref, 0)) {
149149
warning("ref '%s' ignored", ref);
150150
continue;
151151
}

builtin/tag.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,12 +407,12 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
407407
static int strbuf_check_tag_ref(struct strbuf *sb, const char *name)
408408
{
409409
if (name[0] == '-')
410-
return CHECK_REF_FORMAT_ERROR;
410+
return -1;
411411

412412
strbuf_reset(sb);
413413
strbuf_addf(sb, "refs/tags/%s", name);
414414

415-
return check_ref_format(sb->buf);
415+
return check_refname_format(sb->buf, 0);
416416
}
417417

418418
int cmd_tag(int argc, const char **argv, const char *prefix)

cache.h

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -819,10 +819,51 @@ static inline int get_sha1_with_context(const char *str, unsigned char *sha1, st
819819
{
820820
return get_sha1_with_context_1(str, sha1, orc, 0, NULL);
821821
}
822+
823+
/*
824+
* Try to read a SHA1 in hexadecimal format from the 40 characters
825+
* starting at hex. Write the 20-byte result to sha1 in binary form.
826+
* Return 0 on success. Reading stops if a NUL is encountered in the
827+
* input, so it is safe to pass this function an arbitrary
828+
* null-terminated string.
829+
*/
822830
extern int get_sha1_hex(const char *hex, unsigned char *sha1);
831+
823832
extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
824833
extern int read_ref(const char *filename, unsigned char *sha1);
825-
extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *);
834+
835+
/*
836+
* Resolve a reference, recursively following symbolic refererences.
837+
*
838+
* Store the referred-to object's name in sha1 and return the name of
839+
* the non-symbolic reference that ultimately pointed at it. The
840+
* return value, if not NULL, is a pointer into either a static buffer
841+
* or the input ref.
842+
*
843+
* If the reference cannot be resolved to an object, the behavior
844+
* depends on the "reading" argument:
845+
*
846+
* - If reading is set, return NULL.
847+
*
848+
* - If reading is not set, clear sha1 and return the name of the last
849+
* reference name in the chain, which will either be a non-symbolic
850+
* reference or an undefined reference. If this is a prelude to
851+
* "writing" to the ref, the return value is the name of the ref
852+
* that will actually be created or changed.
853+
*
854+
* If flag is non-NULL, set the value that it points to the
855+
* combination of REF_ISPACKED (if the reference was found among the
856+
* packed references) and REF_ISSYMREF (if the initial reference was a
857+
* symbolic reference).
858+
*
859+
* If ref is not a properly-formatted, normalized reference, return
860+
* NULL. If more than MAXDEPTH recursive symbolic lookups are needed,
861+
* give up and return NULL.
862+
*
863+
* errno is sometimes set on errors, but not always.
864+
*/
865+
extern const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag);
866+
826867
extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
827868
extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
828869
extern int interpret_branch_name(const char *str, struct strbuf *);

connect.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ static int check_ref(const char *name, int len, unsigned int flags)
2222
len -= 5;
2323

2424
/* REF_NORMAL means that we don't want the magic fake tag refs */
25-
if ((flags & REF_NORMAL) && check_ref_format(name) < 0)
25+
if ((flags & REF_NORMAL) && check_refname_format(name, 0))
2626
return 0;
2727

2828
/* REF_HEADS means that we want regular branch heads */

0 commit comments

Comments
 (0)