git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Junio C Hamano <gitster@pobox.com>
To: git@vger.kernel.org
Cc: Jeff King <peff@peff.net>,
	Johannes Schindelin <Johannes.Schindelin@gmx.de>
Subject: [PATCH 2/2] Teach @{upstream} syntax to strbuf_branchanme()
Date: Wed, 20 Jan 2010 01:38:42 -0800	[thread overview]
Message-ID: <1263980322-4142-3-git-send-email-gitster@pobox.com> (raw)
In-Reply-To: <1263980322-4142-1-git-send-email-gitster@pobox.com>

This teaches @{upstream} syntax to interpret_branch_name(), instead
of dwim_ref() machinery.

There are places in git UI that behaves differently when you give a local
branch name and when you give an extended SHA-1 expression that evaluates
to the commit object name at the tip of the branch.  The intent is that
the special syntax such as @{-1} can stand in as if the user spelled the
name of the branch in such places.

The name of the branch "frotz" to switch to ("git checkout frotz"), and
the name of the branch "nitfol" to fork a new branch "frotz" from ("git
checkout -b frotz nitfol"), are examples of such places.  These places
take only the name of the branch (e.g. "frotz"), and they are supposed to
act differently to an equivalent refname (e.g. "refs/heads/frotz"), so
hooking the @{upstream} and @{-N} syntax to dwim_ref() is insufficient
when we want to deal with cases a local branch is forked from another
local branch and use "forked@{upstream}" to name the forkee branch.

The "upstream" syntax "forked@{u}" is to specify the ref that "forked" is
configured to merge with, and most often the forkee is a remote tracking
branch, not a local branch.  We cannot simply return a local branch name,
but that does not necessarily mean we have to returns the full refname
(e.g. refs/remotes/origin/frotz, when returning origin/frotz is enough).
This update calls shorten_unambiguous_ref() to do so.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 sha1_name.c                   |  116 ++++++++++++++++++++++++++---------------
 t/t1506-rev-parse-upstream.sh |    6 +-
 2 files changed, 77 insertions(+), 45 deletions(-)

diff --git a/sha1_name.c b/sha1_name.c
index fb4e214..2376c6d 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -239,24 +239,10 @@ static int ambiguous_path(const char *path, int len)
 	return slash;
 }
 
-static inline int tracked_suffix(const char *string, int len)
-{
-	const char *suffix[] = { "@{upstream}", "@{u}" };
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(suffix); i++) {
-		int suffix_len = strlen(suffix[i]);
-		if (len >= suffix_len && !memcmp(string + len - suffix_len,
-					suffix[i], suffix_len))
-			return suffix_len;
-	}
-	return 0;
-}
-
 /*
  * *string and *len will only be substituted, and *string returned (for
- * later free()ing) if the string passed in is of the form @{-<n>} or
- * of the form <branch>@{upstream}.
+ * later free()ing) if the string passed in is a magic short-hand form
+ * to name a branch.
  */
 static char *substitute_branch_name(const char **string, int *len)
 {
@@ -270,21 +256,6 @@ static char *substitute_branch_name(const char **string, int *len)
 		return (char *)*string;
 	}
 
-	ret = tracked_suffix(*string, *len);
-	if (ret) {
-		char *ref = xstrndup(*string, *len - ret);
-		struct branch *tracking = branch_get(*ref ? ref : NULL);
-
-		if (!tracking)
-			die ("No tracking branch found for '%s'", ref);
-		free(ref);
-		if (tracking->merge && tracking->merge[0]->dst) {
-			*string = xstrdup(tracking->merge[0]->dst);
-			*len = strlen(*string);
-			return (char *)*string;
-		}
-	}
-
 	return NULL;
 }
 
@@ -354,6 +325,20 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
 	return logs_found;
 }
 
+static inline int upstream_mark(const char *string, int len)
+{
+	const char *suffix[] = { "@{upstream}", "@{u}" };
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(suffix); i++) {
+		int suffix_len = strlen(suffix[i]);
+		if (suffix_len <= len
+		    && !memcmp(string, suffix[i], suffix_len))
+			return suffix_len;
+	}
+	return 0;
+}
+
 static int get_sha1_1(const char *name, int len, unsigned char *sha1);
 
 static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
@@ -371,7 +356,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
 	if (len && str[len-1] == '}') {
 		for (at = len-2; at >= 0; at--) {
 			if (str[at] == '@' && str[at+1] == '{') {
-				if (!tracked_suffix(str + at, len - at)) {
+				if (!upstream_mark(str + at, len - at)) {
 					reflog_len = (len-1) - (at+2);
 					len = at;
 				}
@@ -773,17 +758,10 @@ static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
 }
 
 /*
- * This reads "@{-N}" syntax, finds the name of the Nth previous
- * branch we were on, and places the name of the branch in the given
- * buf and returns the number of characters parsed if successful.
- *
- * If the input is not of the accepted format, it returns a negative
- * number to signal an error.
- *
- * If the input was ok but there are not N branch switches in the
- * reflog, it returns 0.
+ * Parse @{-N} syntax, return the number of characters parsed
+ * if successful; otherwise signal an error with negative value.
  */
-int interpret_branch_name(const char *name, struct strbuf *buf)
+static int interpret_nth_prior_checkout(const char *name, struct strbuf *buf)
 {
 	long nth;
 	int i, retval;
@@ -828,6 +806,60 @@ release_return:
 }
 
 /*
+ * This reads short-hand syntax that not only evaluates to a commit
+ * object name, but also can act as if the end user spelled the name
+ * of the branch from the command line.
+ *
+ * - "@{-N}" finds the name of the Nth previous branch we were on, and
+ *   places the name of the branch in the given buf and returns the
+ *   number of characters parsed if successful.
+ *
+ * - "<branch>@{upstream}" finds the name of the other ref that
+ *   <branch> is configured to merge with (missing <branch> defaults
+ *   to the current branch), and places the name of the branch in the
+ *   given buf and returns the number of characters parsed if
+ *   successful.
+ *
+ * If the input is not of the accepted format, it returns a negative
+ * number to signal an error.
+ *
+ * If the input was ok but there are not N branch switches in the
+ * reflog, it returns 0.
+ */
+int interpret_branch_name(const char *name, struct strbuf *buf)
+{
+	char *cp;
+	struct branch *upstream;
+	int namelen = strlen(name);
+	int len = interpret_nth_prior_checkout(name, buf);
+	int tmp_len;
+
+	if (!len)
+		return len; /* syntax Ok, not enough switches */
+	if (0 < len)
+		return len; /* consumed from the front */
+	cp = strchr(name, '@');
+	if (!cp)
+		return -1;
+	tmp_len = upstream_mark(cp, namelen - (cp - name));
+	if (!tmp_len)
+		return -1;
+	len = cp + tmp_len - name;
+	cp = xstrndup(name, cp - name);
+	upstream = branch_get(*cp ? cp : NULL);
+	if (!upstream
+	    || !upstream->merge
+	    || !upstream->merge[0]->dst)
+		return error("No upstream branch found for '%s'", cp);
+	free(cp);
+	cp = shorten_unambiguous_ref(upstream->merge[0]->dst, 0);
+	strbuf_reset(buf);
+	strbuf_addstr(buf, cp);
+	free(cp);
+	return len;
+}
+
+/*
  * This is like "get_sha1_basic()", except it allows "sha1 expressions",
  * notably "xyz^" for "parent of xyz"
  */
diff --git a/t/t1506-rev-parse-upstream.sh b/t/t1506-rev-parse-upstream.sh
index a2c7f92..95c9b09 100755
--- a/t/t1506-rev-parse-upstream.sh
+++ b/t/t1506-rev-parse-upstream.sh
@@ -76,7 +76,7 @@ test_expect_success 'checkout -b new my-side@{u} forks from the same' '
 )
 '
 
-test_expect_failure 'merge my-side@{u} records the correct name' '
+test_expect_success 'merge my-side@{u} records the correct name' '
 (
 	sq="'\''" &&
 	cd clone || exit
@@ -90,7 +90,7 @@ test_expect_failure 'merge my-side@{u} records the correct name' '
 )
 '
 
-test_expect_failure 'branch -d other@{u}' '
+test_expect_success 'branch -d other@{u}' '
 	git checkout -t -b other master &&
 	git branch -d @{u} &&
 	git for-each-ref refs/heads/master >actual &&
@@ -98,7 +98,7 @@ test_expect_failure 'branch -d other@{u}' '
 	test_cmp expect actual
 '
 
-test_expect_failure 'checkout other@{u}' '
+test_expect_success 'checkout other@{u}' '
 	git branch -f master HEAD &&
 	git checkout -t -b another master &&
 	git checkout @{u} &&
-- 
1.6.6.513.g63f4c

  parent reply	other threads:[~2010-01-20  9:39 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-01-11 18:49 default behaviour for `gitmerge` (no arguments) Gareth Adams
2010-01-11 19:43 ` Junio C Hamano
2010-01-12 16:23   ` Jeff King
2010-01-12 18:11     ` Junio C Hamano
2010-01-12 18:25       ` Jeff King
2010-01-13  6:57         ` Junio C Hamano
2010-01-13  9:26           ` Johannes Schindelin
2010-01-13  9:47             ` Junio C Hamano
2010-01-13 11:04               ` Johannes Schindelin
2010-01-13 19:48                 ` Junio C Hamano
2010-01-13 22:49                   ` Johannes Schindelin
2010-01-13 23:13                     ` Junio C Hamano
2010-01-20  9:38           ` [PATCH 0/2] @{u} updates Junio C Hamano
2010-01-20  9:38             ` [PATCH 1/2] t1506: more test for @{upstream} syntax Junio C Hamano
2010-01-26 13:07               ` Jeff King
2010-01-26 19:58                 ` Junio C Hamano
2010-01-27 10:24                   ` Jeff King
2010-01-27 18:50                     ` Junio C Hamano
2010-01-28  8:52                       ` Jeff King
2010-01-26 21:32                 ` Junio C Hamano
2010-01-27 11:40                   ` Jeff King
2010-01-27 19:10                     ` Junio C Hamano
2010-01-28  9:44                       ` Jeff King
2010-01-28  9:50                         ` [PATCH 1/3] test combinations of @{} syntax Jeff King
2010-01-28  9:52                         ` [PATCH 2/3] fix parsing of @{-1}@{u} combination Jeff King
2010-01-28  9:56                         ` [PATCH 3/3] reject @{-1} not at beginning of object name Jeff King
2010-01-28 20:02                           ` Junio C Hamano
2010-01-29 11:22                             ` Jeff King
2010-01-20  9:38             ` Junio C Hamano [this message]
2010-01-20 13:08             ` [PATCH 0/2] @{u} updates Johannes Schindelin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1263980322-4142-3-git-send-email-gitster@pobox.com \
    --to=gitster@pobox.com \
    --cc=Johannes.Schindelin@gmx.de \
    --cc=git@vger.kernel.org \
    --cc=peff@peff.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).