summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sha1_name.c116
-rwxr-xr-xt/t1506-rev-parse-upstream.sh6
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} &&