From: Junio C Hamano Date: Mon, 6 Apr 2009 07:43:44 +0000 (-0700) Subject: Merge branch 'jc/name-branch' X-Git-Tag: v1.6.3-rc0~29 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/fbdc05661d9b732d06c47ccb3d5836d0d1b563e5?ds=inline;hp=-c 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 --- fbdc05661d9b732d06c47ccb3d5836d0d1b563e5 diff --combined Documentation/git-check-ref-format.txt index 171b68377d,9b707a7030..c1ce26884e --- a/Documentation/git-check-ref-format.txt +++ b/Documentation/git-check-ref-format.txt @@@ -3,52 -3,70 +3,70 @@@ git-check-ref-format(1 NAME ---- -git-check-ref-format - Make sure ref name is well formed +git-check-ref-format - Ensures that a reference name is well formed SYNOPSIS -------- + [verse] 'git check-ref-format' + 'git check-ref-format' [--branch] DESCRIPTION ----------- -Checks if a given 'refname' is acceptable, and exits non-zero if -it is not. +Checks if a given 'refname' is acceptable, and exits with a non-zero +status if it is not. A reference is used in git to specify branches and tags. A -branch head is stored under `$GIT_DIR/refs/heads` directory, and -a tag is stored under `$GIT_DIR/refs/tags` directory. git -imposes the following rules on how refs are named: +branch head is stored under the `$GIT_DIR/refs/heads` directory, and +a tag is stored under the `$GIT_DIR/refs/tags` directory. git +imposes the following rules on how references are named: -. It can include slash `/` for hierarchical (directory) +. They can include slash `/` for hierarchical (directory) grouping, but no slash-separated component can begin with a - dot `.`; + dot `.`. -. It cannot have two consecutive dots `..` anywhere; +. They cannot have two consecutive dots `..` anywhere. -. It cannot have ASCII control character (i.e. bytes whose +. They cannot have ASCII control characters (i.e. bytes whose values are lower than \040, or \177 `DEL`), space, tilde `~`, 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 makes it easy for shell script based tools to parse -refnames, pathname expansion by the shell when a refname is used +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 unquoted (by mistake), and also avoids ambiguities in certain -refname expressions (see linkgit:git-rev-parse[1]). Namely: +reference name expressions (see linkgit:git-rev-parse[1]): -. double-dot `..` are often used as in `ref1..ref2`, and in some - context this notation means `{caret}ref1 ref2` (i.e. not in - ref1 and in ref2). +. A double-dot `..` is often used as in `ref1..ref2`, and in some + contexts this notation means `{caret}ref1 ref2` (i.e. not in + `ref1` and in `ref2`). -. tilde `~` and caret `{caret}` are used to introduce postfix +. A tilde `~` and caret `{caret}` are used to introduce the postfix 'nth parent' and 'peel onion' operation. -. colon `:` is used as in `srcref:dstref` to mean "use srcref\'s +. A colon `:` is used as in `srcref:dstref` to mean "use srcref\'s value and store it in dstref" in fetch and push operations. 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. + + EXAMPLE + ------- + + git check-ref-format --branch @{-1}:: + + Print the name of the previous branch. + GIT --- diff --combined builtin-branch.c index 07a440eeba,330e0c3f16..ca81d725cb --- a/builtin-branch.c +++ b/builtin-branch.c @@@ -121,11 -121,7 +121,7 @@@ static int delete_branches(int argc, co die("Couldn't look up commit object for HEAD"); } for (i = 0; i < argc; i++, strbuf_release(&bname)) { - int len = strlen(argv[i]); - - if (interpret_nth_last_branch(argv[i], &bname) != len) - strbuf_add(&bname, argv[i], len); - + strbuf_branchname(&bname, argv[i]); if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) { error("Cannot delete the branch '%s' " "which you are currently on.", bname.buf); @@@ -171,7 -167,7 +167,7 @@@ ret = 1; } else { struct strbuf buf = STRBUF_INIT; - printf("Deleted %sbranch %s (%s).\n", remote, + printf("Deleted %sbranch %s (was %s).\n", remote, bname.buf, find_unique_abbrev(sha1, DEFAULT_ABBREV)); strbuf_addf(&buf, "branch.%s", bname.buf); @@@ -468,22 -464,27 +464,27 @@@ static void rename_branch(const char *o 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."); - strbuf_addf(&oldref, "refs/heads/%s", oldname); - - if (check_ref_format(oldref.buf)) - die("Invalid branch name: %s", oldref.buf); - - strbuf_addf(&newref, "refs/heads/%s", newname); + 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(newref.buf)) - die("Invalid branch name: %s", newref.buf); + if (strbuf_check_branch_ref(&newref, newname)) + die("Invalid branch name: '%s'", newname); 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", oldref.buf, newref.buf); @@@ -492,6 -493,9 +493,9 @@@ 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); diff --combined builtin-checkout.c index fc55bbe14d,66df0c072c..33d1fecb62 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@@ -353,16 -353,11 +353,11 @@@ struct branch_info static void setup_branch_path(struct branch_info *branch) { struct strbuf buf = STRBUF_INIT; - int ret; - if ((ret = interpret_nth_last_branch(branch->name, &buf)) - && ret == strlen(branch->name)) { + strbuf_branchname(&buf, branch->name); + if (strcmp(buf.buf, branch->name)) branch->name = xstrdup(buf.buf); - strbuf_splice(&buf, 0, 0, "refs/heads/", 11); - } else { - strbuf_addstr(&buf, "refs/heads/"); - strbuf_addstr(&buf, branch->name); - } + strbuf_splice(&buf, 0, 0, "refs/heads/", 11); branch->path = strbuf_detach(&buf, NULL); } @@@ -558,8 -553,8 +553,8 @@@ static int switch_branches(struct check if (!old.commit && !opts->force) { if (!opts->quiet) { - fprintf(stderr, "warning: You appear to be on a branch yet to be born.\n"); - fprintf(stderr, "warning: Forcing checkout of %s.\n", new->name); + warning("You appear to be on a branch yet to be born."); + warning("Forcing checkout of %s.", new->name); } opts->force = 1; } @@@ -738,12 -733,11 +733,11 @@@ no_reference if (opts.new_branch) { struct strbuf buf = STRBUF_INIT; - strbuf_addstr(&buf, "refs/heads/"); - strbuf_addstr(&buf, opts.new_branch); + if (strbuf_check_branch_ref(&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)) 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); } diff --combined cache.h index 61664addd7,d28fd74880..ab1294d6fb --- a/cache.h +++ b/cache.h @@@ -542,17 -542,8 +542,17 @@@ enum rebase_setup_type AUTOREBASE_ALWAYS, }; +enum push_default_type { + PUSH_DEFAULT_UNSPECIFIED = -1, + PUSH_DEFAULT_NOTHING = 0, + PUSH_DEFAULT_MATCHING, + PUSH_DEFAULT_TRACKING, + PUSH_DEFAULT_CURRENT, +}; + extern enum branch_track git_branch_track; extern enum rebase_setup_type autorebase; +extern enum push_default_type push_default; #define GIT_REPO_VERSION 0 extern int repository_format_version; @@@ -623,8 -614,7 +623,8 @@@ enum sharedrepo PERM_EVERYBODY = 0664, }; int git_config_perm(const char *var, const char *value); -int adjust_shared_perm(const char *path); +int set_shared_perm(const char *path, int mode); +#define adjust_shared_perm(path) set_shared_perm((path), 0) int safe_create_leading_directories(char *path); int safe_create_leading_directories_const(const char *path); char *enter_repo(char *path, int strict); @@@ -656,6 -646,7 +656,6 @@@ extern int check_sha1_signature(const u extern int move_temp_to_file(const char *tmpfile, const char *filename); extern int has_sha1_pack(const unsigned char *sha1); -extern int has_sha1_kept_pack(const unsigned char *sha1); extern int has_sha1_file(const unsigned char *sha1); extern int has_loose_object_nonlocal(const unsigned char *sha1); @@@ -680,7 -671,7 +680,7 @@@ extern int read_ref(const char *filenam 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_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 const char *ref_rev_parse_rules[]; diff --combined refs.c index 26b001453b,f3fdcbd202..59c373fc6d --- a/refs.c +++ b/refs.c @@@ -676,6 -676,7 +676,7 @@@ int for_each_rawref(each_ref_fn fn, voi * - it has double dots "..", or * - it has ASCII control character, "~", "^", ":" or SP, anywhere, or * - it ends with a "/". + * - it ends with ".lock" */ static inline int bad_ref_char(int ch) @@@ -693,7 -694,7 +694,7 @@@ 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,36 -718,33 +718,43 @@@ 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; + if (has_extension(ref, ".lock")) + return CHECK_REF_FORMAT_ERROR; return ret; } } } +const char *prettify_ref(const struct ref *ref) +{ + const char *name = ref->name; + return name + ( + !prefixcmp(name, "refs/heads/") ? 11 : + !prefixcmp(name, "refs/tags/") ? 10 : + !prefixcmp(name, "refs/remotes/") ? 13 : + 0); +} + const char *ref_rev_parse_rules[] = { "%.*s", "refs/%.*s", @@@ -1006,7 -1004,7 +1014,7 @@@ int delete_ref(const char *refname, con err = unlink(git_path("logs/%s", lock->ref_name)); if (err && errno != ENOENT) - fprintf(stderr, "warning: unlink(%s) failed: %s", + warning("unlink(%s) failed: %s", git_path("logs/%s", lock->ref_name), strerror(errno)); invalidate_cached_refs(); unlock_ref(lock); @@@ -1448,7 -1446,8 +1456,7 @@@ int read_ref_at(const char *ref, unsign if (get_sha1_hex(rec + 41, sha1)) die("Log %s is corrupt.", logfile); if (hashcmp(logged_sha1, sha1)) { - fprintf(stderr, - "warning: Log %s has gap after %s.\n", + warning("Log %s has gap after %s.", logfile, show_date(date, tz, DATE_RFC2822)); } } @@@ -1460,7 -1459,8 +1468,7 @@@ if (get_sha1_hex(rec + 41, logged_sha1)) die("Log %s is corrupt.", logfile); if (hashcmp(logged_sha1, sha1)) { - fprintf(stderr, - "warning: Log %s unexpectedly ended on %s.\n", + warning("Log %s unexpectedly ended on %s.", logfile, show_date(date, tz, DATE_RFC2822)); } }