git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/7] Clean up interpret_nth_last_branch feature
@ 2009-03-23  7:58 Junio C Hamano
  2009-03-23  7:58 ` [PATCH v2 1/7] Rename interpret/substitute nth_last_branch functions Junio C Hamano
  2009-03-23  8:10 ` [PATCH v2 0/7] Clean up interpret_nth_last_branch feature Junio C Hamano
  0 siblings, 2 replies; 11+ messages in thread
From: Junio C Hamano @ 2009-03-23  7:58 UTC (permalink / raw)
  To: git

The changes since the previous round are:

 - Tightening of the refname rule comes very late in the series, so that
   we can optionally drop it;

 - In addition to allowing "git branch -d bad@{name}ref.", we also allow
   "git branch -d bad@{name}ref. good-one" as another escape hatch;

 - Update documentation to git-check-ref-format to describe the tightened
   rules.

Junio C Hamano (7):
  Rename interpret/substitute nth_last_branch functions
  strbuf_branchname(): a wrapper for branch name shorthands
  check-ref-format --branch: give Porcelain a way to grok branch
    shorthand
  Fix branch -m @{-1} newname
  strbuf_check_branch_ref(): a helper to check a refname for a branch
  check_ref_format(): tighten refname rules
  checkout -: make "-" to mean "previous branch" everywhere

 Documentation/git-check-ref-format.txt |   18 ++++++++++++++++-
 branch.c                               |   10 +--------
 builtin-branch.c                       |   32 +++++++++++++++++-------------
 builtin-check-ref-format.c             |    9 ++++++++
 builtin-checkout.c                     |   26 ++++++++++--------------
 builtin-merge.c                        |    5 +--
 cache.h                                |    2 +-
 refs.c                                 |   16 +++++++++++---
 sha1_name.c                            |   33 ++++++++++++++++++-------------
 strbuf.c                               |   17 ++++++++++++++++
 strbuf.h                               |    3 ++
 11 files changed, 110 insertions(+), 61 deletions(-)

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2 1/7] Rename interpret/substitute nth_last_branch functions
  2009-03-23  7:58 [PATCH v2 0/7] Clean up interpret_nth_last_branch feature Junio C Hamano
@ 2009-03-23  7:58 ` Junio C Hamano
  2009-03-23  7:58   ` [PATCH v2 2/7] strbuf_branchname(): a wrapper for branch name shorthands Junio C Hamano
  2009-03-23  8:10 ` [PATCH v2 0/7] Clean up interpret_nth_last_branch feature Junio C Hamano
  1 sibling, 1 reply; 11+ messages in thread
From: Junio C Hamano @ 2009-03-23  7:58 UTC (permalink / raw)
  To: git

These allow you to say "git checkout @{-2}" to switch to the branch two
"branch switching" ago by pretending as if you typed the name of that
branch.  As it is likely that we will be introducing more short-hands to
write the name of a branch without writing it explicitly, rename the
functions from "nth_last_branch" to more generic "branch_name", to prepare
for different semantics.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 branch.c           |    2 +-
 builtin-branch.c   |    2 +-
 builtin-checkout.c |    2 +-
 builtin-merge.c    |    2 +-
 cache.h            |    2 +-
 sha1_name.c        |   12 ++++++------
 6 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/branch.c b/branch.c
index 5f889fe..313bcf1 100644
--- a/branch.c
+++ b/branch.c
@@ -137,7 +137,7 @@ void create_branch(const char *head,
 	int len;
 
 	len = strlen(name);
-	if (interpret_nth_last_branch(name, &ref) != len) {
+	if (interpret_branch_name(name, &ref) != len) {
 		strbuf_reset(&ref);
 		strbuf_add(&ref, name, len);
 	}
diff --git a/builtin-branch.c b/builtin-branch.c
index 14d4b91..cacd7da 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -123,7 +123,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
 	for (i = 0; i < argc; i++, strbuf_release(&bname)) {
 		int len = strlen(argv[i]);
 
-		if (interpret_nth_last_branch(argv[i], &bname) != len)
+		if (interpret_branch_name(argv[i], &bname) != len)
 			strbuf_add(&bname, argv[i], len);
 
 		if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) {
diff --git a/builtin-checkout.c b/builtin-checkout.c
index 9fdfc58..a8d9d97 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -355,7 +355,7 @@ 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))
+	if ((ret = interpret_branch_name(branch->name, &buf))
 	    && ret == strlen(branch->name)) {
 		branch->name = xstrdup(buf.buf);
 		strbuf_splice(&buf, 0, 0, "refs/heads/", 11);
diff --git a/builtin-merge.c b/builtin-merge.c
index 4c11935..e94ea7c 100644
--- a/builtin-merge.c
+++ b/builtin-merge.c
@@ -361,7 +361,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
 	int len, early;
 
 	len = strlen(remote);
-	if (interpret_nth_last_branch(remote, &bname) == len)
+	if (interpret_branch_name(remote, &bname) == len)
 		remote = bname.buf;
 
 	memset(branch_head, 0, sizeof(branch_head));
diff --git a/cache.h b/cache.h
index 39789ee..d28fd74 100644
--- a/cache.h
+++ b/cache.h
@@ -671,7 +671,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 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 --git a/sha1_name.c b/sha1_name.c
index 2f75179..904bcd9 100644
--- a/sha1_name.c
+++ b/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
  * 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;
-	int ret = interpret_nth_last_branch(*string, &buf);
+	int ret = interpret_branch_name(*string, &buf);
 
 	if (ret == *len) {
 		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)
 {
-	char *last_branch = substitute_nth_last_branch(&str, &len);
+	char *last_branch = substitute_branch_name(&str, &len);
 	const char **p, *r;
 	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)
 {
-	char *last_branch = substitute_nth_last_branch(&str, &len);
+	char *last_branch = substitute_branch_name(&str, &len);
 	const char **p;
 	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;
 		int ret;
 		/* 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) {
 			/* substitute this branch name and restart */
 			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
  * 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;
 	int i, retval;
-- 
1.6.2.1.349.ga64c

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 2/7] strbuf_branchname(): a wrapper for branch name shorthands
  2009-03-23  7:58 ` [PATCH v2 1/7] Rename interpret/substitute nth_last_branch functions Junio C Hamano
@ 2009-03-23  7:58   ` Junio C Hamano
  2009-03-23  7:58     ` [PATCH v2 3/7] check-ref-format --branch: give Porcelain a way to grok branch shorthand Junio C Hamano
  0 siblings, 1 reply; 11+ messages in thread
From: Junio C Hamano @ 2009-03-23  7:58 UTC (permalink / raw)
  To: git

The function takes a user-supplied string that is supposed to be a branch
name, and puts it in a strbuf after expanding possible shorthand notation.

A handful of open coded sequence to do this in the existing code have been
changed to use this helper function.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 branch.c           |    7 +------
 builtin-branch.c   |    6 +-----
 builtin-checkout.c |   11 +++--------
 builtin-merge.c    |    5 ++---
 strbuf.c           |    9 +++++++++
 strbuf.h           |    2 ++
 6 files changed, 18 insertions(+), 22 deletions(-)

diff --git a/branch.c b/branch.c
index 313bcf1..558f092 100644
--- a/branch.c
+++ b/branch.c
@@ -134,13 +134,8 @@ void create_branch(const char *head,
 	char *real_ref, msg[PATH_MAX + 20];
 	struct strbuf ref = STRBUF_INIT;
 	int forcing = 0;
-	int len;
 
-	len = strlen(name);
-	if (interpret_branch_name(name, &ref) != len) {
-		strbuf_reset(&ref);
-		strbuf_add(&ref, name, len);
-	}
+	strbuf_branchname(&ref, name);
 	strbuf_splice(&ref, 0, 0, "refs/heads/", 11);
 
 	if (check_ref_format(ref.buf))
diff --git a/builtin-branch.c b/builtin-branch.c
index cacd7da..7452db1 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -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");
 	}
 	for (i = 0; i < argc; i++, strbuf_release(&bname)) {
-		int len = strlen(argv[i]);
-
-		if (interpret_branch_name(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);
diff --git a/builtin-checkout.c b/builtin-checkout.c
index a8d9d97..b268046 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -353,16 +353,11 @@ struct branch_info {
 static void setup_branch_path(struct branch_info *branch)
 {
 	struct strbuf buf = STRBUF_INIT;
-	int ret;
 
-	if ((ret = interpret_branch_name(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);
 }
 
diff --git a/builtin-merge.c b/builtin-merge.c
index e94ea7c..6a51823 100644
--- a/builtin-merge.c
+++ b/builtin-merge.c
@@ -360,9 +360,8 @@ static void merge_name(const char *remote, struct strbuf *msg)
 	const char *ptr;
 	int len, early;
 
-	len = strlen(remote);
-	if (interpret_branch_name(remote, &bname) == len)
-		remote = bname.buf;
+	strbuf_branchname(&bname, remote);
+	remote = bname.buf;
 
 	memset(branch_head, 0, sizeof(branch_head));
 	remote_head = peel_to_type(remote, 0, NULL, OBJ_COMMIT);
diff --git a/strbuf.c b/strbuf.c
index bfbd816..a60b0ad 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -357,3 +357,12 @@ int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
 
 	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;
+}
diff --git a/strbuf.h b/strbuf.h
index 89bd36e..68923e1 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -131,4 +131,6 @@ extern int strbuf_getline(struct strbuf *, FILE *, int);
 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 strbuf_branchname(struct strbuf *sb, const char *name);
+
 #endif /* STRBUF_H */
-- 
1.6.2.1.349.ga64c

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 3/7] check-ref-format --branch: give Porcelain a way to grok branch shorthand
  2009-03-23  7:58   ` [PATCH v2 2/7] strbuf_branchname(): a wrapper for branch name shorthands Junio C Hamano
@ 2009-03-23  7:58     ` Junio C Hamano
  2009-03-23  7:58       ` [PATCH v2 4/7] Fix branch -m @{-1} newname Junio C Hamano
  0 siblings, 1 reply; 11+ messages in thread
From: Junio C Hamano @ 2009-03-23  7:58 UTC (permalink / raw)
  To: git

The command may not be the best place to add this new feature, but

    $ git check-ref-format --branch "@{-1}"

allows Porcelains to figure out what branch you were on before the last
branch switching.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 Documentation/git-check-ref-format.txt |   12 ++++++++++++
 builtin-check-ref-format.c             |   10 ++++++++++
 2 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt
index 034223c..51579f6 100644
--- a/Documentation/git-check-ref-format.txt
+++ b/Documentation/git-check-ref-format.txt
@@ -7,7 +7,9 @@ git-check-ref-format - Make sure ref name is well formed
 
 SYNOPSIS
 --------
+[verse]
 'git check-ref-format' <refname>
+'git check-ref-format' [--branch] <branchname-shorthand>
 
 DESCRIPTION
 -----------
@@ -49,6 +51,16 @@ 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".
 
+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 --git a/builtin-check-ref-format.c b/builtin-check-ref-format.c
index 701de43..39db6cb 100644
--- a/builtin-check-ref-format.c
+++ b/builtin-check-ref-format.c
@@ -5,9 +5,19 @@
 #include "cache.h"
 #include "refs.h"
 #include "builtin.h"
+#include "strbuf.h"
 
 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;
+		strbuf_branchname(&sb, argv[2]);
+		strbuf_splice(&sb, 0, 0, "refs/heads/", 11);
+		if (check_ref_format(sb.buf))
+			die("'%s' is not a valid branch name", argv[2]);
+		printf("%s\n", sb.buf + 11);
+		exit(0);
+	}
 	if (argc != 2)
 		usage("git check-ref-format refname");
 	return !!check_ref_format(argv[1]);
-- 
1.6.2.1.349.ga64c

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 4/7] Fix branch -m @{-1} newname
  2009-03-23  7:58     ` [PATCH v2 3/7] check-ref-format --branch: give Porcelain a way to grok branch shorthand Junio C Hamano
@ 2009-03-23  7:58       ` Junio C Hamano
  2009-03-23  7:58         ` [PATCH v2 5/7] strbuf_check_branch_ref(): a helper to check a refname for a branch Junio C Hamano
  0 siblings, 1 reply; 11+ messages in thread
From: Junio C Hamano @ 2009-03-23  7:58 UTC (permalink / raw)
  To: git

The command is supposed to rename the branch we were on before switched
from to a new name, but was not aware of the short-hand notation we added
recently.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin-branch.c |   14 +++++++-------
 1 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/builtin-branch.c b/builtin-branch.c
index 7452db1..0df82bf 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -468,18 +468,18 @@ static void rename_branch(const char *oldname, const char *newname, int force)
 	if (!oldname)
 		die("cannot rename the current branch while not on any.");
 
-	strbuf_addf(&oldref, "refs/heads/%s", oldname);
-
+	strbuf_branchname(&oldref, oldname);
+	strbuf_splice(&oldref, 0, 0, "refs/heads/", 11);
 	if (check_ref_format(oldref.buf))
-		die("Invalid branch name: %s", oldref.buf);
-
-	strbuf_addf(&newref, "refs/heads/%s", newname);
+		die("Invalid branch name: '%s'", oldname);
 
+	strbuf_branchname(&newref, newname);
+	strbuf_splice(&newref, 0, 0, "refs/heads/", 11);
 	if (check_ref_format(newref.buf))
-		die("Invalid branch name: %s", newref.buf);
+		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);
-- 
1.6.2.1.349.ga64c

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 5/7] strbuf_check_branch_ref(): a helper to check a refname for a branch
  2009-03-23  7:58       ` [PATCH v2 4/7] Fix branch -m @{-1} newname Junio C Hamano
@ 2009-03-23  7:58         ` Junio C Hamano
  2009-03-23  7:58           ` [PATCH v2 6/7] check_ref_format(): tighten refname rules Junio C Hamano
  0 siblings, 1 reply; 11+ messages in thread
From: Junio C Hamano @ 2009-03-23  7:58 UTC (permalink / raw)
  To: git

This allows a common calling sequence

	strbuf_branchname(&ref, name);
	strbuf_splice(&ref, 0, 0, "refs/heads/", 11);
	if (check_ref_format(ref.buf))
		die(...);

to be refactored into

	if (strbuf_check_branch_ref(&ref, name))
		die(...);

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 branch.c                   |    5 +----
 builtin-branch.c           |    8 ++------
 builtin-check-ref-format.c |    5 ++---
 builtin-checkout.c         |    7 +++----
 strbuf.c                   |    8 ++++++++
 strbuf.h                   |    1 +
 6 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/branch.c b/branch.c
index 558f092..62030af 100644
--- a/branch.c
+++ b/branch.c
@@ -135,10 +135,7 @@ void create_branch(const char *head,
 	struct strbuf ref = STRBUF_INIT;
 	int forcing = 0;
 
-	strbuf_branchname(&ref, name);
-	strbuf_splice(&ref, 0, 0, "refs/heads/", 11);
-
-	if (check_ref_format(ref.buf))
+	if (strbuf_check_branch_ref(&ref, name))
 		die("'%s' is not a valid branch name.", name);
 
 	if (resolve_ref(ref.buf, sha1, 1, NULL)) {
diff --git a/builtin-branch.c b/builtin-branch.c
index 0df82bf..afeed68 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -468,14 +468,10 @@ static void rename_branch(const char *oldname, const char *newname, int force)
 	if (!oldname)
 		die("cannot rename the current branch while not on any.");
 
-	strbuf_branchname(&oldref, oldname);
-	strbuf_splice(&oldref, 0, 0, "refs/heads/", 11);
-	if (check_ref_format(oldref.buf))
+	if (strbuf_check_branch_ref(&oldref, oldname))
 		die("Invalid branch name: '%s'", oldname);
 
-	strbuf_branchname(&newref, newname);
-	strbuf_splice(&newref, 0, 0, "refs/heads/", 11);
-	if (check_ref_format(newref.buf))
+	if (strbuf_check_branch_ref(&newref, newname))
 		die("Invalid branch name: '%s'", newname);
 
 	if (resolve_ref(newref.buf, sha1, 1, NULL) && !force)
diff --git a/builtin-check-ref-format.c b/builtin-check-ref-format.c
index 39db6cb..f9381e0 100644
--- a/builtin-check-ref-format.c
+++ b/builtin-check-ref-format.c
@@ -11,9 +11,8 @@ 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;
-		strbuf_branchname(&sb, argv[2]);
-		strbuf_splice(&sb, 0, 0, "refs/heads/", 11);
-		if (check_ref_format(sb.buf))
+
+		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);
diff --git a/builtin-checkout.c b/builtin-checkout.c
index b268046..66df0c0 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -733,12 +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 --git a/strbuf.c b/strbuf.c
index a60b0ad..a884960 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "refs.h"
 
 int prefixcmp(const char *str, const char *prefix)
 {
@@ -366,3 +367,10 @@ int strbuf_branchname(struct strbuf *sb, const char *name)
 	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);
+}
diff --git a/strbuf.h b/strbuf.h
index 68923e1..9ee908a 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -132,5 +132,6 @@ 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 strbuf_branchname(struct strbuf *sb, const char *name);
+extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
 
 #endif /* STRBUF_H */
-- 
1.6.2.1.349.ga64c

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 6/7] check_ref_format(): tighten refname rules
  2009-03-23  7:58         ` [PATCH v2 5/7] strbuf_check_branch_ref(): a helper to check a refname for a branch Junio C Hamano
@ 2009-03-23  7:58           ` Junio C Hamano
  2009-03-23  7:58             ` [PATCH v2 7/7] checkout -: make "-" to mean "previous branch" everywhere Junio C Hamano
  2009-03-23 13:59             ` [PATCH v2 6/7] check_ref_format(): tighten refname rules Shawn O. Pearce
  0 siblings, 2 replies; 11+ messages in thread
From: Junio C Hamano @ 2009-03-23  7:58 UTC (permalink / raw)
  To: git

This changes the rules for refnames to forbid:

 (1) a refname that contains "@{" in it.

     Some people and foreign SCM converter may have named their branches
     as frotz@24 and we still want to keep supporting it.

     However, "git branch frotz@{24}" is a disaster.  It cannot even
     checked out because "git checkout frotz@{24}" will interpret it as
     "detach the HEAD at twenty-fourth reflog entry of the frotz branch".

 (2) a refname that ends with a dot.

     We already reject a path component that begins with a dot, primarily
     to avoid ambiguous range interpretation.  If we allowed ".B" as a
     valid ref, it is unclear if "A...B" means "in dot-B but not in A" or
     "either in A or B but not in both".

     But for this to be complete, we need also to forbid "A." to avoid "in
     B but not in A-dot".  This was not a problem in the original range
     notation, but we should have added this restriction when three-dot
     notation was introduced.

     Unlike "no dot at the beginning of any path component" rule, this
     rule does not have to be "no dot at the end of any path component",
     because you cannot abbreviate the tail end away, similar to you can
     say "dot-B" to mean "refs/heads/dot-B".

For these reasons, it is not likely people created branches with these
names on purpose, but we have allowed such names to be used for quite some
time, and it is possible that people created such branches by mistake or
by accident.

To help people with branches with such unfortunate names to recover,
we still allow "branch -d 'bad.'" to delete such branches, and also allow
"branch -m bad. good" to rename them.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 Documentation/git-check-ref-format.txt |    6 +++++-
 builtin-branch.c                       |   16 ++++++++++++++--
 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 51579f6..58e53cc 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 `/`.
+. It cannot end with a slash `/` nor a dot `.`.
+
+. It 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 afeed68..330e0c3 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);
diff --git a/refs.c b/refs.c
index 8d3c502..e355489 100644
--- a/refs.c
+++ b/refs.c
@@ -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;
-- 
1.6.2.1.349.ga64c

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 7/7] checkout -: make "-" to mean "previous branch" everywhere
  2009-03-23  7:58           ` [PATCH v2 6/7] check_ref_format(): tighten refname rules Junio C Hamano
@ 2009-03-23  7:58             ` Junio C Hamano
  2009-03-23 13:59             ` [PATCH v2 6/7] check_ref_format(): tighten refname rules Shawn O. Pearce
  1 sibling, 0 replies; 11+ messages in thread
From: Junio C Hamano @ 2009-03-23  7:58 UTC (permalink / raw)
  To: git

This is iffy, in that it teaches the very low level machinery to interpret
it as "the tip of the previous branch" when "-" is fed to it, and has a
high risk of unintended side effects.

This makes "git log ..-" to work as expected, which is marginally useful
because the revision parameter parser misinterprets the other direction
"git log -..".  It also makes "git check-ref-format --branch -" to work,
which is not very useful because Porcelains can always ask for @{-1}.

It also makes a refname whose last component is "-" forbidden.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin-checkout.c |    8 +++++---
 refs.c             |    3 +++
 sha1_name.c        |   21 +++++++++++++--------
 3 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/builtin-checkout.c b/builtin-checkout.c
index 66df0c0..6b3b450 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -666,9 +666,11 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 		arg = argv[0];
 		has_dash_dash = (argc > 1) && !strcmp(argv[1], "--");
 
-		if (!strcmp(arg, "-"))
-			arg = "@{-1}";
-
+		{
+			struct strbuf sb = STRBUF_INIT;
+			strbuf_branchname(&sb, arg);
+			arg = strbuf_detach(&sb, NULL);
+		}
 		if (get_sha1(arg, rev)) {
 			if (has_dash_dash)          /* case (1) */
 				die("invalid reference: %s", arg);
diff --git a/refs.c b/refs.c
index e355489..7e27537 100644
--- a/refs.c
+++ b/refs.c
@@ -735,6 +735,9 @@ int check_ref_format(const char *ref)
 		if (!ch) {
 			if (ref <= cp - 2 && cp[-2] == '.')
 				return CHECK_REF_FORMAT_ERROR;
+			if (ref <= cp - 2 && cp[-2] == '-' &&
+			    (cp - 3 < ref || cp[-3] == '/'))
+				return CHECK_REF_FORMAT_ERROR;
 			if (level < 2)
 				return CHECK_REF_FORMAT_ONELEVEL;
 			return ret;
diff --git a/sha1_name.c b/sha1_name.c
index 904bcd9..3972f4c 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -758,14 +758,19 @@ int interpret_branch_name(const char *name, struct strbuf *buf)
 	const char *brace;
 	char *num_end;
 
-	if (name[0] != '@' || name[1] != '{' || name[2] != '-')
-		return -1;
-	brace = strchr(name, '}');
-	if (!brace)
-		return -1;
-	nth = strtol(name+3, &num_end, 10);
-	if (num_end != brace)
-		return -1;
+	if (name[0] == '-' && !name[1]) {
+		nth = 1;
+		brace = name; /* "end of branch name expression" */
+	} else {
+		if (name[0] != '@' || name[1] != '{' || name[2] != '-')
+			return -1;
+		brace = strchr(name, '}');
+		if (!brace)
+			return -1;
+		nth = strtol(name+3, &num_end, 10);
+		if (num_end != brace)
+			return -1;
+	}
 	if (nth <= 0)
 		return -1;
 	cb.alloc = nth;
-- 
1.6.2.1.349.ga64c

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 0/7] Clean up interpret_nth_last_branch feature
  2009-03-23  7:58 [PATCH v2 0/7] Clean up interpret_nth_last_branch feature Junio C Hamano
  2009-03-23  7:58 ` [PATCH v2 1/7] Rename interpret/substitute nth_last_branch functions Junio C Hamano
@ 2009-03-23  8:10 ` Junio C Hamano
  1 sibling, 0 replies; 11+ messages in thread
From: Junio C Hamano @ 2009-03-23  8:10 UTC (permalink / raw)
  To: git

Junio C Hamano <gitster@pobox.com> writes:

> The changes since the previous round are:
>
>  - Tightening of the refname rule comes very late in the series, so that
>    we can optionally drop it;
>
>  - In addition to allowing "git branch -d bad@{name}ref.", we also allow
>    "git branch -d bad@{name}ref. good-one" as another escape hatch;

Sorry, the "also allow" one is about renaming, i.e. "branch -m bad. good".

>  - Update documentation to git-check-ref-format to describe the tightened
>    rules.
>
> Junio C Hamano (7):
>   Rename interpret/substitute nth_last_branch functions
>   strbuf_branchname(): a wrapper for branch name shorthands
>   check-ref-format --branch: give Porcelain a way to grok branch
>     shorthand
>   Fix branch -m @{-1} newname
>   strbuf_check_branch_ref(): a helper to check a refname for a branch
>   check_ref_format(): tighten refname rules
>   checkout -: make "-" to mean "previous branch" everywhere
>
>  Documentation/git-check-ref-format.txt |   18 ++++++++++++++++-
>  branch.c                               |   10 +--------
>  builtin-branch.c                       |   32 +++++++++++++++++-------------
>  builtin-check-ref-format.c             |    9 ++++++++
>  builtin-checkout.c                     |   26 ++++++++++--------------
>  builtin-merge.c                        |    5 +--
>  cache.h                                |    2 +-
>  refs.c                                 |   16 +++++++++++---
>  sha1_name.c                            |   33 ++++++++++++++++++-------------
>  strbuf.c                               |   17 ++++++++++++++++
>  strbuf.h                               |    3 ++
>  11 files changed, 110 insertions(+), 61 deletions(-)

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 6/7] check_ref_format(): tighten refname rules
  2009-03-23  7:58           ` [PATCH v2 6/7] check_ref_format(): tighten refname rules Junio C Hamano
  2009-03-23  7:58             ` [PATCH v2 7/7] checkout -: make "-" to mean "previous branch" everywhere Junio C Hamano
@ 2009-03-23 13:59             ` Shawn O. Pearce
  2009-03-23 16:03               ` Junio C Hamano
  1 sibling, 1 reply; 11+ messages in thread
From: Shawn O. Pearce @ 2009-03-23 13:59 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Junio C Hamano <gitster@pobox.com> wrote:
> This changes the rules for refnames to forbid:
> 
>  (1) a refname that contains "@{" in it.
>  (2) a refname that ends with a dot.

How about also "that end in .lock" ?

  $ git branch foo.lock
  $ git branch foo
  fatal: Unable to create '.git/refs/heads/foo.lock': File exists.

  If no other git process is currently running, this probably means a
  git process crashed in this repository earlier. Make sure no other git
  process is running and remove the file manually to contin

Oh, apparently there is also something wrong with the error message...

$ git version
git version 1.6.2.1.433.g0cbc

-- 
Shawn.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 6/7] check_ref_format(): tighten refname rules
  2009-03-23 13:59             ` [PATCH v2 6/7] check_ref_format(): tighten refname rules Shawn O. Pearce
@ 2009-03-23 16:03               ` Junio C Hamano
  0 siblings, 0 replies; 11+ messages in thread
From: Junio C Hamano @ 2009-03-23 16:03 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git

"Shawn O. Pearce" <spearce@spearce.org> writes:

> Junio C Hamano <gitster@pobox.com> wrote:
>> This changes the rules for refnames to forbid:
>> 
>>  (1) a refname that contains "@{" in it.
>>  (2) a refname that ends with a dot.
>
> How about also "that end in .lock" ?

Yeah, people can add more as follow-up patches.  The primary purpose of
this series is to clean-up places that the new %name notation (or ~name or
whatever) needs to hook into.

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2009-03-23 16:08 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-03-23  7:58 [PATCH v2 0/7] Clean up interpret_nth_last_branch feature Junio C Hamano
2009-03-23  7:58 ` [PATCH v2 1/7] Rename interpret/substitute nth_last_branch functions Junio C Hamano
2009-03-23  7:58   ` [PATCH v2 2/7] strbuf_branchname(): a wrapper for branch name shorthands Junio C Hamano
2009-03-23  7:58     ` [PATCH v2 3/7] check-ref-format --branch: give Porcelain a way to grok branch shorthand Junio C Hamano
2009-03-23  7:58       ` [PATCH v2 4/7] Fix branch -m @{-1} newname Junio C Hamano
2009-03-23  7:58         ` [PATCH v2 5/7] strbuf_check_branch_ref(): a helper to check a refname for a branch Junio C Hamano
2009-03-23  7:58           ` [PATCH v2 6/7] check_ref_format(): tighten refname rules Junio C Hamano
2009-03-23  7:58             ` [PATCH v2 7/7] checkout -: make "-" to mean "previous branch" everywhere Junio C Hamano
2009-03-23 13:59             ` [PATCH v2 6/7] check_ref_format(): tighten refname rules Shawn O. Pearce
2009-03-23 16:03               ` Junio C Hamano
2009-03-23  8:10 ` [PATCH v2 0/7] Clean up interpret_nth_last_branch feature Junio C Hamano

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).