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:
Junio C Hamano 2009-04-06 00:43:44 -07:00
commit fbdc05661d
11 changed files with 94 additions and 50 deletions

View file

@ -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
--- ---

View file

@ -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)) {

View file

@ -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);

View file

@ -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]);

View file

@ -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 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
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);
} }

View file

@ -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);

View file

@ -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
View file

@ -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;
} }
} }

View file

@ -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;

View file

@ -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);
}

View file

@ -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 */