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
This commit is contained in:
@ -7,7 +7,9 @@ git-check-ref-format - Ensures that a reference name is well formed
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
|
[verse]
|
||||||
'git check-ref-format' <refname>
|
'git check-ref-format' <refname>
|
||||||
|
'git check-ref-format' [--branch] <branchname-shorthand>
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -30,7 +32,11 @@ imposes the following rules on how references are named:
|
|||||||
caret `{caret}`, colon `:`, question-mark `?`, asterisk `*`,
|
caret `{caret}`, colon `:`, question-mark `?`, asterisk `*`,
|
||||||
or open bracket `[` anywhere.
|
or open bracket `[` anywhere.
|
||||||
|
|
||||||
. They cannot end with a slash `/`.
|
. They cannot end with a slash `/` nor a dot `.`.
|
||||||
|
|
||||||
|
. They cannot end with the sequence `.lock`.
|
||||||
|
|
||||||
|
. They cannot contain a sequence `@{`.
|
||||||
|
|
||||||
These rules make it easy for shell script based tools to parse
|
These rules make it easy for shell script based tools to parse
|
||||||
reference names, pathname expansion by the shell when a reference name is used
|
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]):
|
|||||||
It may also be used to select a specific object such as with
|
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".
|
'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.
|
||||||
|
|
||||||
|
EXAMPLE
|
||||||
|
-------
|
||||||
|
|
||||||
|
git check-ref-format --branch @{-1}::
|
||||||
|
|
||||||
|
Print the name of the previous branch.
|
||||||
|
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
---
|
---
|
||||||
|
10
branch.c
10
branch.c
@ -134,16 +134,8 @@ void create_branch(const char *head,
|
|||||||
char *real_ref, msg[PATH_MAX + 20];
|
char *real_ref, msg[PATH_MAX + 20];
|
||||||
struct strbuf ref = STRBUF_INIT;
|
struct strbuf ref = STRBUF_INIT;
|
||||||
int forcing = 0;
|
int forcing = 0;
|
||||||
int len;
|
|
||||||
|
|
||||||
len = strlen(name);
|
if (strbuf_check_branch_ref(&ref, name))
|
||||||
if (interpret_nth_last_branch(name, &ref) != len) {
|
|
||||||
strbuf_reset(&ref);
|
|
||||||
strbuf_add(&ref, name, len);
|
|
||||||
}
|
|
||||||
strbuf_splice(&ref, 0, 0, "refs/heads/", 11);
|
|
||||||
|
|
||||||
if (check_ref_format(ref.buf))
|
|
||||||
die("'%s' is not a valid branch name.", name);
|
die("'%s' is not a valid branch name.", name);
|
||||||
|
|
||||||
if (resolve_ref(ref.buf, sha1, 1, NULL)) {
|
if (resolve_ref(ref.buf, sha1, 1, NULL)) {
|
||||||
|
@ -121,11 +121,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
|
|||||||
die("Couldn't look up commit object for HEAD");
|
die("Couldn't look up commit object for HEAD");
|
||||||
}
|
}
|
||||||
for (i = 0; i < argc; i++, strbuf_release(&bname)) {
|
for (i = 0; i < argc; i++, strbuf_release(&bname)) {
|
||||||
int len = strlen(argv[i]);
|
strbuf_branchname(&bname, argv[i]);
|
||||||
|
|
||||||
if (interpret_nth_last_branch(argv[i], &bname) != len)
|
|
||||||
strbuf_add(&bname, argv[i], len);
|
|
||||||
|
|
||||||
if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) {
|
if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) {
|
||||||
error("Cannot delete the branch '%s' "
|
error("Cannot delete the branch '%s' "
|
||||||
"which you are currently on.", bname.buf);
|
"which you are currently on.", bname.buf);
|
||||||
@ -468,22 +464,27 @@ static void rename_branch(const char *oldname, const char *newname, int force)
|
|||||||
struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT;
|
struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT;
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT;
|
struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT;
|
||||||
|
int recovery = 0;
|
||||||
|
|
||||||
if (!oldname)
|
if (!oldname)
|
||||||
die("cannot rename the current branch while not on any.");
|
die("cannot rename the current branch while not on any.");
|
||||||
|
|
||||||
strbuf_addf(&oldref, "refs/heads/%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 (check_ref_format(oldref.buf))
|
if (strbuf_check_branch_ref(&newref, newname))
|
||||||
die("Invalid branch name: %s", oldref.buf);
|
die("Invalid branch name: '%s'", newname);
|
||||||
|
|
||||||
strbuf_addf(&newref, "refs/heads/%s", newname);
|
|
||||||
|
|
||||||
if (check_ref_format(newref.buf))
|
|
||||||
die("Invalid branch name: %s", newref.buf);
|
|
||||||
|
|
||||||
if (resolve_ref(newref.buf, sha1, 1, NULL) && !force)
|
if (resolve_ref(newref.buf, sha1, 1, NULL) && !force)
|
||||||
die("A branch named '%s' already exists.", newname);
|
die("A branch named '%s' already exists.", newref.buf + 11);
|
||||||
|
|
||||||
strbuf_addf(&logmsg, "Branch: renamed %s to %s",
|
strbuf_addf(&logmsg, "Branch: renamed %s to %s",
|
||||||
oldref.buf, newref.buf);
|
oldref.buf, newref.buf);
|
||||||
@ -492,6 +493,9 @@ static void rename_branch(const char *oldname, const char *newname, int force)
|
|||||||
die("Branch rename failed");
|
die("Branch rename failed");
|
||||||
strbuf_release(&logmsg);
|
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 */
|
/* no need to pass logmsg here as HEAD didn't really move */
|
||||||
if (!strcmp(oldname, head) && create_symref("HEAD", newref.buf, NULL))
|
if (!strcmp(oldname, head) && create_symref("HEAD", newref.buf, NULL))
|
||||||
die("Branch renamed to %s, but HEAD is not updated!", newname);
|
die("Branch renamed to %s, but HEAD is not updated!", newname);
|
||||||
|
@ -5,9 +5,18 @@
|
|||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
|
#include "strbuf.h"
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
if (argc == 3 && !strcmp(argv[1], "--branch")) {
|
||||||
|
struct strbuf sb = STRBUF_INIT;
|
||||||
|
|
||||||
|
if (strbuf_check_branch_ref(&sb, argv[2]))
|
||||||
|
die("'%s' is not a valid branch name", argv[2]);
|
||||||
|
printf("%s\n", sb.buf + 11);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
if (argc != 2)
|
if (argc != 2)
|
||||||
usage("git check-ref-format refname");
|
usage("git check-ref-format refname");
|
||||||
return !!check_ref_format(argv[1]);
|
return !!check_ref_format(argv[1]);
|
||||||
|
@ -353,16 +353,11 @@ struct branch_info {
|
|||||||
static void setup_branch_path(struct branch_info *branch)
|
static void setup_branch_path(struct branch_info *branch)
|
||||||
{
|
{
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
int ret;
|
|
||||||
|
|
||||||
if ((ret = interpret_nth_last_branch(branch->name, &buf))
|
strbuf_branchname(&buf, branch->name);
|
||||||
&& ret == strlen(branch->name)) {
|
if (strcmp(buf.buf, branch->name))
|
||||||
branch->name = xstrdup(buf.buf);
|
branch->name = xstrdup(buf.buf);
|
||||||
strbuf_splice(&buf, 0, 0, "refs/heads/", 11);
|
strbuf_splice(&buf, 0, 0, "refs/heads/", 11);
|
||||||
} else {
|
|
||||||
strbuf_addstr(&buf, "refs/heads/");
|
|
||||||
strbuf_addstr(&buf, branch->name);
|
|
||||||
}
|
|
||||||
branch->path = strbuf_detach(&buf, NULL);
|
branch->path = strbuf_detach(&buf, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -738,12 +733,11 @@ no_reference:
|
|||||||
|
|
||||||
if (opts.new_branch) {
|
if (opts.new_branch) {
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
strbuf_addstr(&buf, "refs/heads/");
|
if (strbuf_check_branch_ref(&buf, opts.new_branch))
|
||||||
strbuf_addstr(&buf, opts.new_branch);
|
die("git checkout: we do not like '%s' as a branch name.",
|
||||||
|
opts.new_branch);
|
||||||
if (!get_sha1(buf.buf, rev))
|
if (!get_sha1(buf.buf, rev))
|
||||||
die("git checkout: branch %s already exists", opts.new_branch);
|
die("git checkout: branch %s already exists", opts.new_branch);
|
||||||
if (check_ref_format(buf.buf))
|
|
||||||
die("git checkout: we do not like '%s' as a branch name.", opts.new_branch);
|
|
||||||
strbuf_release(&buf);
|
strbuf_release(&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,9 +360,8 @@ static void merge_name(const char *remote, struct strbuf *msg)
|
|||||||
const char *ptr;
|
const char *ptr;
|
||||||
int len, early;
|
int len, early;
|
||||||
|
|
||||||
len = strlen(remote);
|
strbuf_branchname(&bname, remote);
|
||||||
if (interpret_nth_last_branch(remote, &bname) == len)
|
remote = bname.buf;
|
||||||
remote = bname.buf;
|
|
||||||
|
|
||||||
memset(branch_head, 0, sizeof(branch_head));
|
memset(branch_head, 0, sizeof(branch_head));
|
||||||
remote_head = peel_to_type(remote, 0, NULL, OBJ_COMMIT);
|
remote_head = peel_to_type(remote, 0, NULL, OBJ_COMMIT);
|
||||||
|
2
cache.h
2
cache.h
@ -680,7 +680,7 @@ extern int read_ref(const char *filename, unsigned char *sha1);
|
|||||||
extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *);
|
extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *);
|
||||||
extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
|
extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
|
||||||
extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
|
extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
|
||||||
extern int interpret_nth_last_branch(const char *str, struct strbuf *);
|
extern int interpret_branch_name(const char *str, struct strbuf *);
|
||||||
|
|
||||||
extern int refname_match(const char *abbrev_name, const char *full_name, const char **rules);
|
extern int refname_match(const char *abbrev_name, const char *full_name, const char **rules);
|
||||||
extern const char *ref_rev_parse_rules[];
|
extern const char *ref_rev_parse_rules[];
|
||||||
|
16
refs.c
16
refs.c
@ -676,6 +676,7 @@ int for_each_rawref(each_ref_fn fn, void *cb_data)
|
|||||||
* - it has double dots "..", or
|
* - it has double dots "..", or
|
||||||
* - it has ASCII control character, "~", "^", ":" or SP, anywhere, or
|
* - it has ASCII control character, "~", "^", ":" or SP, anywhere, or
|
||||||
* - it ends with a "/".
|
* - it ends with a "/".
|
||||||
|
* - it ends with ".lock"
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static inline int bad_ref_char(int ch)
|
static inline int bad_ref_char(int ch)
|
||||||
@ -693,7 +694,7 @@ static inline int bad_ref_char(int ch)
|
|||||||
|
|
||||||
int check_ref_format(const char *ref)
|
int check_ref_format(const char *ref)
|
||||||
{
|
{
|
||||||
int ch, level, bad_type;
|
int ch, level, bad_type, last;
|
||||||
int ret = CHECK_REF_FORMAT_OK;
|
int ret = CHECK_REF_FORMAT_OK;
|
||||||
const char *cp = ref;
|
const char *cp = ref;
|
||||||
|
|
||||||
@ -717,21 +718,28 @@ int check_ref_format(const char *ref)
|
|||||||
return CHECK_REF_FORMAT_ERROR;
|
return CHECK_REF_FORMAT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
last = ch;
|
||||||
/* scan the rest of the path component */
|
/* scan the rest of the path component */
|
||||||
while ((ch = *cp++) != 0) {
|
while ((ch = *cp++) != 0) {
|
||||||
bad_type = bad_ref_char(ch);
|
bad_type = bad_ref_char(ch);
|
||||||
if (bad_type) {
|
if (bad_type)
|
||||||
return CHECK_REF_FORMAT_ERROR;
|
return CHECK_REF_FORMAT_ERROR;
|
||||||
}
|
|
||||||
if (ch == '/')
|
if (ch == '/')
|
||||||
break;
|
break;
|
||||||
if (ch == '.' && *cp == '.')
|
if (last == '.' && ch == '.')
|
||||||
return CHECK_REF_FORMAT_ERROR;
|
return CHECK_REF_FORMAT_ERROR;
|
||||||
|
if (last == '@' && ch == '{')
|
||||||
|
return CHECK_REF_FORMAT_ERROR;
|
||||||
|
last = ch;
|
||||||
}
|
}
|
||||||
level++;
|
level++;
|
||||||
if (!ch) {
|
if (!ch) {
|
||||||
|
if (ref <= cp - 2 && cp[-2] == '.')
|
||||||
|
return CHECK_REF_FORMAT_ERROR;
|
||||||
if (level < 2)
|
if (level < 2)
|
||||||
return CHECK_REF_FORMAT_ONELEVEL;
|
return CHECK_REF_FORMAT_ONELEVEL;
|
||||||
|
if (has_extension(ref, ".lock"))
|
||||||
|
return CHECK_REF_FORMAT_ERROR;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
sha1_name.c
12
sha1_name.c
@ -242,10 +242,10 @@ static int ambiguous_path(const char *path, int len)
|
|||||||
* *string and *len will only be substituted, and *string returned (for
|
* *string and *len will only be substituted, and *string returned (for
|
||||||
* later free()ing) if the string passed in is of the form @{-<n>}.
|
* later free()ing) if the string passed in is of the form @{-<n>}.
|
||||||
*/
|
*/
|
||||||
static char *substitute_nth_last_branch(const char **string, int *len)
|
static char *substitute_branch_name(const char **string, int *len)
|
||||||
{
|
{
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
int ret = interpret_nth_last_branch(*string, &buf);
|
int ret = interpret_branch_name(*string, &buf);
|
||||||
|
|
||||||
if (ret == *len) {
|
if (ret == *len) {
|
||||||
size_t size;
|
size_t size;
|
||||||
@ -259,7 +259,7 @@ static char *substitute_nth_last_branch(const char **string, int *len)
|
|||||||
|
|
||||||
int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)
|
int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)
|
||||||
{
|
{
|
||||||
char *last_branch = substitute_nth_last_branch(&str, &len);
|
char *last_branch = substitute_branch_name(&str, &len);
|
||||||
const char **p, *r;
|
const char **p, *r;
|
||||||
int refs_found = 0;
|
int refs_found = 0;
|
||||||
|
|
||||||
@ -288,7 +288,7 @@ int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)
|
|||||||
|
|
||||||
int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
|
int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
|
||||||
{
|
{
|
||||||
char *last_branch = substitute_nth_last_branch(&str, &len);
|
char *last_branch = substitute_branch_name(&str, &len);
|
||||||
const char **p;
|
const char **p;
|
||||||
int logs_found = 0;
|
int logs_found = 0;
|
||||||
|
|
||||||
@ -355,7 +355,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
|
|||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
int ret;
|
int ret;
|
||||||
/* try the @{-N} syntax for n-th checkout */
|
/* try the @{-N} syntax for n-th checkout */
|
||||||
ret = interpret_nth_last_branch(str+at, &buf);
|
ret = interpret_branch_name(str+at, &buf);
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
/* substitute this branch name and restart */
|
/* substitute this branch name and restart */
|
||||||
return get_sha1_1(buf.buf, buf.len, sha1);
|
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,
|
|||||||
* If the input was ok but there are not N branch switches in the
|
* If the input was ok but there are not N branch switches in the
|
||||||
* reflog, it returns 0.
|
* reflog, it returns 0.
|
||||||
*/
|
*/
|
||||||
int interpret_nth_last_branch(const char *name, struct strbuf *buf)
|
int interpret_branch_name(const char *name, struct strbuf *buf)
|
||||||
{
|
{
|
||||||
long nth;
|
long nth;
|
||||||
int i, retval;
|
int i, retval;
|
||||||
|
17
strbuf.c
17
strbuf.c
@ -1,4 +1,5 @@
|
|||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
#include "refs.h"
|
||||||
|
|
||||||
int prefixcmp(const char *str, const char *prefix)
|
int prefixcmp(const char *str, const char *prefix)
|
||||||
{
|
{
|
||||||
@ -357,3 +358,19 @@ int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
|
|||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int strbuf_branchname(struct strbuf *sb, const char *name)
|
||||||
|
{
|
||||||
|
int len = strlen(name);
|
||||||
|
if (interpret_branch_name(name, sb) == len)
|
||||||
|
return 0;
|
||||||
|
strbuf_add(sb, name, len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int strbuf_check_branch_ref(struct strbuf *sb, const char *name)
|
||||||
|
{
|
||||||
|
strbuf_branchname(sb, name);
|
||||||
|
strbuf_splice(sb, 0, 0, "refs/heads/", 11);
|
||||||
|
return check_ref_format(sb->buf);
|
||||||
|
}
|
||||||
|
3
strbuf.h
3
strbuf.h
@ -131,4 +131,7 @@ extern int strbuf_getline(struct strbuf *, FILE *, int);
|
|||||||
extern void stripspace(struct strbuf *buf, int skip_comments);
|
extern void stripspace(struct strbuf *buf, int skip_comments);
|
||||||
extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env);
|
extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env);
|
||||||
|
|
||||||
|
extern int strbuf_branchname(struct strbuf *sb, const char *name);
|
||||||
|
extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
|
||||||
|
|
||||||
#endif /* STRBUF_H */
|
#endif /* STRBUF_H */
|
||||||
|
Reference in New Issue
Block a user