@matheusbsbs / matheus-bagliano / commits / ae0ba8e20a
Fork 0

Teach @{upstream} syntax to strbuf_branchanme()

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>

Junio C Hamano committed Jan 19, 2010 at 23:17 UTC ae0ba8e20a2fb57299381ba2daa7c6d1863320d0
2 files changed +77 -45
sha1_name.c
+74 -42
@@ -239,24 +239,10 @@ static int ambiguous_path(const char *path, int len)
239 return slash;
240 }
241
242 -static inline int tracked_suffix(const char *string, int len)
243 -{
244 - const char *suffix[] = { "@{upstream}", "@{u}" };
245 - int i;
246 -
247 - for (i = 0; i < ARRAY_SIZE(suffix); i++) {
248 - int suffix_len = strlen(suffix[i]);
249 - if (len >= suffix_len && !memcmp(string + len - suffix_len,
250 - suffix[i], suffix_len))
251 - return suffix_len;
252 - }
253 - return 0;
254 -}
255 -
242 /*
243 * *string and *len will only be substituted, and *string returned (for
258 - * later free()ing) if the string passed in is of the form @{-<n>} or
259 - * of the form <branch>@{upstream}.
244 + * later free()ing) if the string passed in is a magic short-hand form
245 + * to name a branch.
246 */
247 static char *substitute_branch_name(const char **string, int *len)
248 {
@@ -270,21 +256,6 @@ static char *substitute_branch_name(const char **string, int *len)
256 return (char *)*string;
257 }
258
273 - ret = tracked_suffix(*string, *len);
274 - if (ret) {
275 - char *ref = xstrndup(*string, *len - ret);
276 - struct branch *tracking = branch_get(*ref ? ref : NULL);
277 -
278 - if (!tracking)
279 - die ("No tracking branch found for '%s'", ref);
280 - free(ref);
281 - if (tracking->merge && tracking->merge[0]->dst) {
282 - *string = xstrdup(tracking->merge[0]->dst);
283 - *len = strlen(*string);
284 - return (char *)*string;
285 - }
286 - }
287 -
259 return NULL;
260 }
261
@@ -354,6 +325,20 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
325 return logs_found;
326 }
327
328 +static inline int upstream_mark(const char *string, int len)
329 +{
330 + const char *suffix[] = { "@{upstream}", "@{u}" };
331 + int i;
332 +
333 + for (i = 0; i < ARRAY_SIZE(suffix); i++) {
334 + int suffix_len = strlen(suffix[i]);
335 + if (suffix_len <= len
336 + && !memcmp(string, suffix[i], suffix_len))
337 + return suffix_len;
338 + }
339 + return 0;
340 +}
341 +
342 static int get_sha1_1(const char *name, int len, unsigned char *sha1);
343
344 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)
356 if (len && str[len-1] == '}') {
357 for (at = len-2; at >= 0; at--) {
358 if (str[at] == '@' && str[at+1] == '{') {
374 - if (!tracked_suffix(str + at, len - at)) {
359 + if (!upstream_mark(str + at, len - at)) {
360 reflog_len = (len-1) - (at+2);
361 len = at;
362 }
@@ -773,17 +758,10 @@ static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
758 }
759
760 /*
776 - * This reads "@{-N}" syntax, finds the name of the Nth previous
777 - * branch we were on, and places the name of the branch in the given
778 - * buf and returns the number of characters parsed if successful.
779 - *
780 - * If the input is not of the accepted format, it returns a negative
781 - * number to signal an error.
782 - *
783 - * If the input was ok but there are not N branch switches in the
784 - * reflog, it returns 0.
761 + * Parse @{-N} syntax, return the number of characters parsed
762 + * if successful; otherwise signal an error with negative value.
763 */
786 -int interpret_branch_name(const char *name, struct strbuf *buf)
764 +static int interpret_nth_prior_checkout(const char *name, struct strbuf *buf)
765 {
766 long nth;
767 int i, retval;
@@ -827,6 +805,60 @@ release_return:
805 return retval;
806 }
807
808 +/*
809 + * This reads short-hand syntax that not only evaluates to a commit
810 + * object name, but also can act as if the end user spelled the name
811 + * of the branch from the command line.
812 + *
813 + * - "@{-N}" finds the name of the Nth previous branch we were on, and
814 + * places the name of the branch in the given buf and returns the
815 + * number of characters parsed if successful.
816 + *
817 + * - "<branch>@{upstream}" finds the name of the other ref that
818 + * <branch> is configured to merge with (missing <branch> defaults
819 + * to the current branch), and places the name of the branch in the
820 + * given buf and returns the number of characters parsed if
821 + * successful.
822 + *
823 + * If the input is not of the accepted format, it returns a negative
824 + * number to signal an error.
825 + *
826 + * If the input was ok but there are not N branch switches in the
827 + * reflog, it returns 0.
828 + */
829 +int interpret_branch_name(const char *name, struct strbuf *buf)
830 +{
831 + char *cp;
832 + struct branch *upstream;
833 + int namelen = strlen(name);
834 + int len = interpret_nth_prior_checkout(name, buf);
835 + int tmp_len;
836 +
837 + if (!len)
838 + return len; /* syntax Ok, not enough switches */
839 + if (0 < len)
840 + return len; /* consumed from the front */
841 + cp = strchr(name, '@');
842 + if (!cp)
843 + return -1;
844 + tmp_len = upstream_mark(cp, namelen - (cp - name));
845 + if (!tmp_len)
846 + return -1;
847 + len = cp + tmp_len - name;
848 + cp = xstrndup(name, cp - name);
849 + upstream = branch_get(*cp ? cp : NULL);
850 + if (!upstream
851 + || !upstream->merge
852 + || !upstream->merge[0]->dst)
853 + return error("No upstream branch found for '%s'", cp);
854 + free(cp);
855 + cp = shorten_unambiguous_ref(upstream->merge[0]->dst, 0);
856 + strbuf_reset(buf);
857 + strbuf_addstr(buf, cp);
858 + free(cp);
859 + return len;
860 +}
861 +
862 /*
863 * This is like "get_sha1_basic()", except it allows "sha1 expressions",
864 * notably "xyz^" for "parent of xyz"
t/t1506-rev-parse-upstream.sh
+3 -3
@@ -76,7 +76,7 @@ test_expect_success 'checkout -b new my-side@{u} forks from the same' '
76 )
77 '
78
79 -test_expect_failure 'merge my-side@{u} records the correct name' '
79 +test_expect_success 'merge my-side@{u} records the correct name' '
80 (
81 sq="'\''" &&
82 cd clone || exit
@@ -90,7 +90,7 @@ test_expect_failure 'merge my-side@{u} records the correct name' '
90 )
91 '
92
93 -test_expect_failure 'branch -d other@{u}' '
93 +test_expect_success 'branch -d other@{u}' '
94 git checkout -t -b other master &&
95 git branch -d @{u} &&
96 git for-each-ref refs/heads/master >actual &&
@@ -98,7 +98,7 @@ test_expect_failure 'branch -d other@{u}' '
98 test_cmp expect actual
99 '
100
101 -test_expect_failure 'checkout other@{u}' '
101 +test_expect_success 'checkout other@{u}' '
102 git branch -f master HEAD &&
103 git checkout -t -b another master &&
104 git checkout @{u} &&