Skip to content

Commit fbdc056

Browse files
committed
Merge branch 'jc/name-branch'
* jc/name-branch: Don't permit ref/branch names to end with ".lock" check_ref_format(): tighten refname rules strbuf_check_branch_ref(): a helper to check a refname for a branch Fix branch -m @{-1} newname check-ref-format --branch: give Porcelain a way to grok branch shorthand strbuf_branchname(): a wrapper for branch name shorthands Rename interpret/substitute nth_last_branch functions Conflicts: Documentation/git-check-ref-format.txt
2 parents 03a39a9 + 3e262b9 commit fbdc056

File tree

11 files changed

+94
-50
lines changed

11 files changed

+94
-50
lines changed

Documentation/git-check-ref-format.txt

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ git-check-ref-format - Ensures that a reference name is well formed
77

88
SYNOPSIS
99
--------
10+
[verse]
1011
'git check-ref-format' <refname>
12+
'git check-ref-format' [--branch] <branchname-shorthand>
1113

1214
DESCRIPTION
1315
-----------
@@ -30,7 +32,11 @@ imposes the following rules on how references are named:
3032
caret `{caret}`, colon `:`, question-mark `?`, asterisk `*`,
3133
or open bracket `[` anywhere.
3234

33-
. They cannot end with a slash `/`.
35+
. They cannot end with a slash `/` nor a dot `.`.
36+
37+
. They cannot end with the sequence `.lock`.
38+
39+
. They cannot contain a sequence `@{`.
3440

3541
These rules make it easy for shell script based tools to parse
3642
reference names, pathname expansion by the shell when a reference name is used
@@ -49,6 +55,18 @@ reference name expressions (see linkgit:git-rev-parse[1]):
4955
It may also be used to select a specific object such as with
5056
'git-cat-file': "git cat-file blob v1.3.3:refs.c".
5157

58+
. at-open-brace `@{` is used as a notation to access a reflog entry.
59+
60+
With the `--branch` option, it expands a branch name shorthand and
61+
prints the name of the branch the shorthand refers to.
62+
63+
EXAMPLE
64+
-------
65+
66+
git check-ref-format --branch @{-1}::
67+
68+
Print the name of the previous branch.
69+
5270

5371
GIT
5472
---

branch.c

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -134,16 +134,8 @@ void create_branch(const char *head,
134134
char *real_ref, msg[PATH_MAX + 20];
135135
struct strbuf ref = STRBUF_INIT;
136136
int forcing = 0;
137-
int len;
138137

139-
len = strlen(name);
140-
if (interpret_nth_last_branch(name, &ref) != len) {
141-
strbuf_reset(&ref);
142-
strbuf_add(&ref, name, len);
143-
}
144-
strbuf_splice(&ref, 0, 0, "refs/heads/", 11);
145-
146-
if (check_ref_format(ref.buf))
138+
if (strbuf_check_branch_ref(&ref, name))
147139
die("'%s' is not a valid branch name.", name);
148140

149141
if (resolve_ref(ref.buf, sha1, 1, NULL)) {

builtin-branch.c

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
121121
die("Couldn't look up commit object for HEAD");
122122
}
123123
for (i = 0; i < argc; i++, strbuf_release(&bname)) {
124-
int len = strlen(argv[i]);
125-
126-
if (interpret_nth_last_branch(argv[i], &bname) != len)
127-
strbuf_add(&bname, argv[i], len);
128-
124+
strbuf_branchname(&bname, argv[i]);
129125
if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) {
130126
error("Cannot delete the branch '%s' "
131127
"which you are currently on.", bname.buf);
@@ -468,22 +464,27 @@ static void rename_branch(const char *oldname, const char *newname, int force)
468464
struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT;
469465
unsigned char sha1[20];
470466
struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT;
467+
int recovery = 0;
471468

472469
if (!oldname)
473470
die("cannot rename the current branch while not on any.");
474471

475-
strbuf_addf(&oldref, "refs/heads/%s", oldname);
476-
477-
if (check_ref_format(oldref.buf))
478-
die("Invalid branch name: %s", oldref.buf);
479-
480-
strbuf_addf(&newref, "refs/heads/%s", newname);
472+
if (strbuf_check_branch_ref(&oldref, oldname)) {
473+
/*
474+
* Bad name --- this could be an attempt to rename a
475+
* ref that we used to allow to be created by accident.
476+
*/
477+
if (resolve_ref(oldref.buf, sha1, 1, NULL))
478+
recovery = 1;
479+
else
480+
die("Invalid branch name: '%s'", oldname);
481+
}
481482

482-
if (check_ref_format(newref.buf))
483-
die("Invalid branch name: %s", newref.buf);
483+
if (strbuf_check_branch_ref(&newref, newname))
484+
die("Invalid branch name: '%s'", newname);
484485

485486
if (resolve_ref(newref.buf, sha1, 1, NULL) && !force)
486-
die("A branch named '%s' already exists.", newname);
487+
die("A branch named '%s' already exists.", newref.buf + 11);
487488

488489
strbuf_addf(&logmsg, "Branch: renamed %s to %s",
489490
oldref.buf, newref.buf);
@@ -492,6 +493,9 @@ static void rename_branch(const char *oldname, const char *newname, int force)
492493
die("Branch rename failed");
493494
strbuf_release(&logmsg);
494495

496+
if (recovery)
497+
warning("Renamed a misnamed branch '%s' away", oldref.buf + 11);
498+
495499
/* no need to pass logmsg here as HEAD didn't really move */
496500
if (!strcmp(oldname, head) && create_symref("HEAD", newref.buf, NULL))
497501
die("Branch renamed to %s, but HEAD is not updated!", newname);

builtin-check-ref-format.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,18 @@
55
#include "cache.h"
66
#include "refs.h"
77
#include "builtin.h"
8+
#include "strbuf.h"
89

910
int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
1011
{
12+
if (argc == 3 && !strcmp(argv[1], "--branch")) {
13+
struct strbuf sb = STRBUF_INIT;
14+
15+
if (strbuf_check_branch_ref(&sb, argv[2]))
16+
die("'%s' is not a valid branch name", argv[2]);
17+
printf("%s\n", sb.buf + 11);
18+
exit(0);
19+
}
1120
if (argc != 2)
1221
usage("git check-ref-format refname");
1322
return !!check_ref_format(argv[1]);

builtin-checkout.c

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -353,16 +353,11 @@ struct branch_info {
353353
static void setup_branch_path(struct branch_info *branch)
354354
{
355355
struct strbuf buf = STRBUF_INIT;
356-
int ret;
357356

358-
if ((ret = interpret_nth_last_branch(branch->name, &buf))
359-
&& ret == strlen(branch->name)) {
357+
strbuf_branchname(&buf, branch->name);
358+
if (strcmp(buf.buf, branch->name))
360359
branch->name = xstrdup(buf.buf);
361-
strbuf_splice(&buf, 0, 0, "refs/heads/", 11);
362-
} else {
363-
strbuf_addstr(&buf, "refs/heads/");
364-
strbuf_addstr(&buf, branch->name);
365-
}
360+
strbuf_splice(&buf, 0, 0, "refs/heads/", 11);
366361
branch->path = strbuf_detach(&buf, NULL);
367362
}
368363

@@ -738,12 +733,11 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
738733

739734
if (opts.new_branch) {
740735
struct strbuf buf = STRBUF_INIT;
741-
strbuf_addstr(&buf, "refs/heads/");
742-
strbuf_addstr(&buf, opts.new_branch);
736+
if (strbuf_check_branch_ref(&buf, opts.new_branch))
737+
die("git checkout: we do not like '%s' as a branch name.",
738+
opts.new_branch);
743739
if (!get_sha1(buf.buf, rev))
744740
die("git checkout: branch %s already exists", opts.new_branch);
745-
if (check_ref_format(buf.buf))
746-
die("git checkout: we do not like '%s' as a branch name.", opts.new_branch);
747741
strbuf_release(&buf);
748742
}
749743

builtin-merge.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -360,9 +360,8 @@ static void merge_name(const char *remote, struct strbuf *msg)
360360
const char *ptr;
361361
int len, early;
362362

363-
len = strlen(remote);
364-
if (interpret_nth_last_branch(remote, &bname) == len)
365-
remote = bname.buf;
363+
strbuf_branchname(&bname, remote);
364+
remote = bname.buf;
366365

367366
memset(branch_head, 0, sizeof(branch_head));
368367
remote_head = peel_to_type(remote, 0, NULL, OBJ_COMMIT);

cache.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,7 @@ extern int read_ref(const char *filename, unsigned char *sha1);
680680
extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *);
681681
extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
682682
extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
683-
extern int interpret_nth_last_branch(const char *str, struct strbuf *);
683+
extern int interpret_branch_name(const char *str, struct strbuf *);
684684

685685
extern int refname_match(const char *abbrev_name, const char *full_name, const char **rules);
686686
extern const char *ref_rev_parse_rules[];

refs.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,7 @@ int for_each_rawref(each_ref_fn fn, void *cb_data)
676676
* - it has double dots "..", or
677677
* - it has ASCII control character, "~", "^", ":" or SP, anywhere, or
678678
* - it ends with a "/".
679+
* - it ends with ".lock"
679680
*/
680681

681682
static inline int bad_ref_char(int ch)
@@ -693,7 +694,7 @@ static inline int bad_ref_char(int ch)
693694

694695
int check_ref_format(const char *ref)
695696
{
696-
int ch, level, bad_type;
697+
int ch, level, bad_type, last;
697698
int ret = CHECK_REF_FORMAT_OK;
698699
const char *cp = ref;
699700

@@ -717,21 +718,28 @@ int check_ref_format(const char *ref)
717718
return CHECK_REF_FORMAT_ERROR;
718719
}
719720

721+
last = ch;
720722
/* scan the rest of the path component */
721723
while ((ch = *cp++) != 0) {
722724
bad_type = bad_ref_char(ch);
723-
if (bad_type) {
725+
if (bad_type)
724726
return CHECK_REF_FORMAT_ERROR;
725-
}
726727
if (ch == '/')
727728
break;
728-
if (ch == '.' && *cp == '.')
729+
if (last == '.' && ch == '.')
730+
return CHECK_REF_FORMAT_ERROR;
731+
if (last == '@' && ch == '{')
729732
return CHECK_REF_FORMAT_ERROR;
733+
last = ch;
730734
}
731735
level++;
732736
if (!ch) {
737+
if (ref <= cp - 2 && cp[-2] == '.')
738+
return CHECK_REF_FORMAT_ERROR;
733739
if (level < 2)
734740
return CHECK_REF_FORMAT_ONELEVEL;
741+
if (has_extension(ref, ".lock"))
742+
return CHECK_REF_FORMAT_ERROR;
735743
return ret;
736744
}
737745
}

sha1_name.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -242,10 +242,10 @@ static int ambiguous_path(const char *path, int len)
242242
* *string and *len will only be substituted, and *string returned (for
243243
* later free()ing) if the string passed in is of the form @{-<n>}.
244244
*/
245-
static char *substitute_nth_last_branch(const char **string, int *len)
245+
static char *substitute_branch_name(const char **string, int *len)
246246
{
247247
struct strbuf buf = STRBUF_INIT;
248-
int ret = interpret_nth_last_branch(*string, &buf);
248+
int ret = interpret_branch_name(*string, &buf);
249249

250250
if (ret == *len) {
251251
size_t size;
@@ -259,7 +259,7 @@ static char *substitute_nth_last_branch(const char **string, int *len)
259259

260260
int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)
261261
{
262-
char *last_branch = substitute_nth_last_branch(&str, &len);
262+
char *last_branch = substitute_branch_name(&str, &len);
263263
const char **p, *r;
264264
int refs_found = 0;
265265

@@ -288,7 +288,7 @@ int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)
288288

289289
int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
290290
{
291-
char *last_branch = substitute_nth_last_branch(&str, &len);
291+
char *last_branch = substitute_branch_name(&str, &len);
292292
const char **p;
293293
int logs_found = 0;
294294

@@ -355,7 +355,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
355355
struct strbuf buf = STRBUF_INIT;
356356
int ret;
357357
/* try the @{-N} syntax for n-th checkout */
358-
ret = interpret_nth_last_branch(str+at, &buf);
358+
ret = interpret_branch_name(str+at, &buf);
359359
if (ret > 0) {
360360
/* substitute this branch name and restart */
361361
return get_sha1_1(buf.buf, buf.len, sha1);
@@ -750,7 +750,7 @@ static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
750750
* If the input was ok but there are not N branch switches in the
751751
* reflog, it returns 0.
752752
*/
753-
int interpret_nth_last_branch(const char *name, struct strbuf *buf)
753+
int interpret_branch_name(const char *name, struct strbuf *buf)
754754
{
755755
long nth;
756756
int i, retval;

strbuf.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "cache.h"
2+
#include "refs.h"
23

34
int prefixcmp(const char *str, const char *prefix)
45
{
@@ -357,3 +358,19 @@ int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
357358

358359
return len;
359360
}
361+
362+
int strbuf_branchname(struct strbuf *sb, const char *name)
363+
{
364+
int len = strlen(name);
365+
if (interpret_branch_name(name, sb) == len)
366+
return 0;
367+
strbuf_add(sb, name, len);
368+
return len;
369+
}
370+
371+
int strbuf_check_branch_ref(struct strbuf *sb, const char *name)
372+
{
373+
strbuf_branchname(sb, name);
374+
strbuf_splice(sb, 0, 0, "refs/heads/", 11);
375+
return check_ref_format(sb->buf);
376+
}

0 commit comments

Comments
 (0)