diff options
-rw-r--r-- | Documentation/git-check-ref-format.txt | 6 | ||||
-rw-r--r-- | builtin-branch.c | 16 | ||||
-rw-r--r-- | refs.c | 13 |
3 files changed, 28 insertions, 7 deletions
diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt index 51579f6776..d23fd219da 100644 --- a/Documentation/git-check-ref-format.txt +++ b/Documentation/git-check-ref-format.txt @@ -32,7 +32,9 @@ imposes the following rules on how refs are named: caret `{caret}`, colon `:`, question-mark `?`, asterisk `*`, or open bracket `[` anywhere; -. It cannot end with a slash `/`. +. They cannot end with a slash `/` nor a dot `.`. + +. They cannot contain a sequence `@{`. These rules makes it easy for shell script based tools to parse refnames, pathname expansion by the shell when a refname is used @@ -51,6 +53,8 @@ refname expressions (see linkgit:git-rev-parse[1]). Namely: It may also be used to select a specific object such as with 'git-cat-file': "git cat-file blob v1.3.3:refs.c". +. at-open-brace `@{` is used as a notation to access a reflog entry. + With the `--branch` option, it expands a branch name shorthand and prints the name of the branch the shorthand refers to. diff --git a/builtin-branch.c b/builtin-branch.c index afeed68cfd..330e0c3f16 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -464,12 +464,21 @@ static void rename_branch(const char *oldname, const char *newname, int force) struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT; unsigned char sha1[20]; struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT; + int recovery = 0; if (!oldname) die("cannot rename the current branch while not on any."); - if (strbuf_check_branch_ref(&oldref, oldname)) - die("Invalid branch name: '%s'", oldname); + if (strbuf_check_branch_ref(&oldref, oldname)) { + /* + * Bad name --- this could be an attempt to rename a + * ref that we used to allow to be created by accident. + */ + if (resolve_ref(oldref.buf, sha1, 1, NULL)) + recovery = 1; + else + die("Invalid branch name: '%s'", oldname); + } if (strbuf_check_branch_ref(&newref, newname)) die("Invalid branch name: '%s'", newname); @@ -484,6 +493,9 @@ static void rename_branch(const char *oldname, const char *newname, int force) die("Branch rename failed"); strbuf_release(&logmsg); + if (recovery) + warning("Renamed a misnamed branch '%s' away", oldref.buf + 11); + /* no need to pass logmsg here as HEAD didn't really move */ if (!strcmp(oldname, head) && create_symref("HEAD", newref.buf, NULL)) die("Branch renamed to %s, but HEAD is not updated!", newname); @@ -693,7 +693,7 @@ static inline int bad_ref_char(int ch) int check_ref_format(const char *ref) { - int ch, level, bad_type; + int ch, level, bad_type, last; int ret = CHECK_REF_FORMAT_OK; const char *cp = ref; @@ -717,19 +717,24 @@ int check_ref_format(const char *ref) return CHECK_REF_FORMAT_ERROR; } + last = ch; /* scan the rest of the path component */ while ((ch = *cp++) != 0) { bad_type = bad_ref_char(ch); - if (bad_type) { + if (bad_type) return CHECK_REF_FORMAT_ERROR; - } if (ch == '/') break; - if (ch == '.' && *cp == '.') + if (last == '.' && ch == '.') + return CHECK_REF_FORMAT_ERROR; + if (last == '@' && ch == '{') return CHECK_REF_FORMAT_ERROR; + last = ch; } level++; if (!ch) { + if (ref <= cp - 2 && cp[-2] == '.') + return CHECK_REF_FORMAT_ERROR; if (level < 2) return CHECK_REF_FORMAT_ONELEVEL; return ret; |