From: Johan Herland <johan@herland.net>
To: git@vger.kernel.org
Cc: johan@herland.net, gitster@pobox.com
Subject: [PATCH 7/7] refs.c: Add rules for resolving refs using remote refspecs
Date: Sun, 5 May 2013 01:55:49 +0200 [thread overview]
Message-ID: <1367711749-8812-8-git-send-email-johan@herland.net> (raw)
In-Reply-To: <1367711749-8812-1-git-send-email-johan@herland.net>
The "$remote/$branch" expression is often used as a shorthand with the
intention of referring to the remote-tracking branch corresponding to
the given $branch in the $remote repo.
Currently, Git resolves this by prepending "refs/remotes/" to the given
"$remote/$branch" expression, resulting in "refs/remotes/$remote/$branch",
which is equivalent to the above intention only when conventional
refspecs are being used (e.g. refs/heads/*:refs/remotes/origin/*).
Correspondingly, a full remote-tracking branch name, can only be
shortened to the "$remote/$branch" form if it textually matches the
"refs/remotes/$remote/$branch" format.
If unconventional refspecs (e.g. refs/heads/*:refs/remotes/origin/heads/*)
are being used, then the current expansion ("refs/remotes/$remote/$branch")
fails to match the remote-tracking branches from the configured remotes.
Ditto for the corresponding shortening.
Instead of doing pure textual expansion (from "$remote/$branch" to
"refs/remotes/$remote/$branch"), we should expand by finding all remotes
matching "$remote", look up their fetch refspecs, and map
"refs/heads/$branch" through them to find the appropriate remote-tracking
branch name corresponding to "$remote/$branch". This would yield the
correct remote-tracking branch in all cases, both for conventional and
unconventional refspecs.
Likewise, when shortening full refnames for remote-tracking branches into
their shorthand form ("$remote/$branch"), we should find the refspec with
the RHS that matches the full remote-tracking branch name, and map
through that refspec to produce the corresponding LHS (minus the leading
"refs/heads/" part), and from that construct the corresponding
"$remote/$branch" shorthand.
This patch adds a new expansion method - ref_expand_refspec() - and a
corresponding shortening method - ref_shorten_refspec() - that implements
the remote refspec traversal and expanding/shortening logic described
above. These expand/shorten methods complement the existing
ref_expand_txtly() and ref_shorten_txtly() methods that implement the
current textual expanding/shortening logic.
Implementing the proper expanding/shortening of "$remote/$branch" is now
a simple matter of adding another entry to the ref_expand_rules list,
using the new ref_expand_refspec() and ref_shorten_refspec() functions.
Note that the existing "refs/remotes/*" textual expansion/shortening rule
is kept to preserve backwards compatibility for refs under refs/remotes/*
that are not covered by any configured refspec.
Signed-off-by: Johan Herland <johan@herland.net>
---
refs.c | 98 +++++++++++++++++++++++++-
t/t7900-working-with-namespaced-remote-refs.sh | 21 +++++-
2 files changed, 114 insertions(+), 5 deletions(-)
diff --git a/refs.c b/refs.c
index 98997c4..18d7188 100644
--- a/refs.c
+++ b/refs.c
@@ -4,6 +4,7 @@
#include "tag.h"
#include "dir.h"
#include "string-list.h"
+#include "remote.h"
/*
* Make sure "ref" is something reasonable to have under ".git/refs/";
@@ -1758,12 +1759,102 @@ static char *ref_shorten_txtly(const struct ref_expand_rule *rule,
return xstrndup(refname + pre_len, match_len);
}
+struct ref_expand_refspec_helper_data {
+ const struct ref_expand_rule *rule;
+ char *dst;
+ size_t dst_len;
+ const char *src;
+ size_t src_len;
+};
+
+static int ref_expand_refspec_helper(struct remote *remote, void *cb_data)
+{
+ struct ref_expand_refspec_helper_data *cb = cb_data;
+ struct refspec query;
+ char refspec_src[PATH_MAX];
+ size_t ref_start = strlen(remote->name) + 1;
+ if (prefixcmp(cb->src, remote->name) ||
+ cb->src_len <= ref_start ||
+ cb->src[ref_start - 1] != '/')
+ return 0;
+
+ mksnpath(refspec_src, sizeof(refspec_src), cb->rule->pattern,
+ cb->src_len - ref_start, cb->src + ref_start);
+
+ memset(&query, 0, sizeof(struct refspec));
+ query.src = refspec_src;
+ if ((!remote_find_tracking(remote, &query)) &&
+ strlen(query.dst) < cb->dst_len) {
+ strcpy(cb->dst, query.dst);
+ return 1;
+ }
+ return 0;
+}
+
+static void ref_expand_refspec(const struct ref_expand_rule *rule,
+ char *dst, size_t dst_len,
+ const char *shortname, size_t shortname_len)
+{
+ /*
+ * Given shortname of the form "$remote/$ref", see if there is a
+ * fetch refspec configured for $remote whose lhs matches
+ * rule->pattern % $ref, and use the corresponding rhs of that
+ * mapping as the expanded result of "$remote/$ref".
+ */
+ const void *has_slash = memchr(shortname, '/', shortname_len);
+ struct ref_expand_refspec_helper_data cb = {
+ rule, dst, dst_len, shortname, shortname_len };
+ dst[0] = '\0';
+ if (has_slash)
+ for_each_remote(ref_expand_refspec_helper, &cb);
+}
+
+static int ref_shorten_refspec_helper(struct remote *remote, void *cb_data)
+{
+ struct ref_expand_refspec_helper_data *cb = cb_data;
+ struct refspec query;
+ char *lhs_ref;
+ int ret = 0;
+
+ memset(&query, 0, sizeof(struct refspec));
+ query.dst = (char *) cb->src;
+ if (!remote_find_tracking(remote, &query) &&
+ (lhs_ref = ref_shorten_txtly(cb->rule, query.src))) {
+ /* refname matches rhs and rule->pattern matches lhs */
+ cb->dst_len = strlen(remote->name) + 1 + strlen(lhs_ref);
+ /* "$remote/$lhs_ref" should be shorter than src */
+ if (cb->dst_len < cb->src_len) {
+ cb->dst = xmalloc(cb->dst_len + 1);
+ snprintf(cb->dst, cb->dst_len + 1,
+ "%s/%s", remote->name, lhs_ref);
+ ret = 1;
+ }
+ free(lhs_ref);
+ }
+ return ret;
+}
+
+static char *ref_shorten_refspec(const struct ref_expand_rule *rule,
+ const char *refname)
+{
+ /*
+ * See if there is a $remote with a fetch refspec that matches the
+ * given refname on rhs, and will produce refs/heads/$ref on the
+ * lhs. If so, construct "$remote/$ref" as the shorthand.
+ */
+ struct ref_expand_refspec_helper_data cb = {
+ rule, NULL, 0, refname, strlen(refname) };
+ for_each_remote(ref_shorten_refspec_helper, &cb);
+ return cb.dst;
+}
+
const struct ref_expand_rule ref_expand_rules_local[] = {
{ ref_expand_txtly, NULL, "%.*s" },
{ ref_expand_txtly, ref_shorten_txtly, "refs/%.*s" },
{ ref_expand_txtly, ref_shorten_txtly, "refs/tags/%.*s" },
{ ref_expand_txtly, ref_shorten_txtly, "refs/heads/%.*s" },
{ ref_expand_txtly, ref_shorten_txtly, "refs/remotes/%.*s" },
+ { ref_expand_refspec, ref_shorten_refspec, "refs/heads/%.*s" },
{ ref_expand_txtly, ref_shorten_txtly, "refs/remotes/%.*s/HEAD" },
{ NULL, NULL, NULL }
};
@@ -3028,13 +3119,14 @@ char *shorten_unambiguous_ref(const char *refname, int strict)
/*
* the short name is ambiguous, if it resolves
- * (with this previous rule) to a valid ref
- * read_ref() returns 0 on success
+ * (with this previous rule) to a valid
+ * (but different) ref
*/
if (q->expand) {
q->expand(q, resolved, sizeof(resolved),
short_name, short_name_len);
- if (ref_exists(resolved))
+ if (strcmp(refname, resolved) &&
+ ref_exists(resolved))
break;
}
}
diff --git a/t/t7900-working-with-namespaced-remote-refs.sh b/t/t7900-working-with-namespaced-remote-refs.sh
index cc25e76..302083e 100755
--- a/t/t7900-working-with-namespaced-remote-refs.sh
+++ b/t/t7900-working-with-namespaced-remote-refs.sh
@@ -89,7 +89,7 @@ test_expect_success 'enter client repo' '
cd client
'
-test_expect_failure 'short-hand notation expands correctly for remote-tracking branches' '
+test_expect_success 'short-hand notation expands correctly for remote-tracking branches' '
echo refs/remotes/origin/heads/master > expect &&
git rev-parse --symbolic-full-name refs/remotes/origin/heads/master > actual &&
test_cmp expect actual &&
@@ -101,7 +101,7 @@ test_expect_failure 'short-hand notation expands correctly for remote-tracking b
test_cmp expect actual
'
-test_expect_failure 'remote-tracking branches are shortened correctly' '
+test_expect_success 'remote-tracking branches are shortened correctly' '
echo origin/master > expect &&
git rev-parse --abbrev-ref refs/remotes/origin/heads/master > actual &&
test_cmp expect actual &&
@@ -113,4 +113,21 @@ test_expect_failure 'remote-tracking branches are shortened correctly' '
test_cmp expect actual
'
+cat > expect.origin_master << EOF
+$server_master_b
+$server_master_a
+EOF
+
+cat > expect.origin_other << EOF
+$server_other_b
+$server_master_a
+EOF
+
+test_expect_success 'rev-list machinery should work with $remote/$branch' '
+ git rev-list origin/master > actual.origin_master &&
+ test_cmp expect.origin_master actual.origin_master &&
+ git rev-list origin/other > actual.origin_other &&
+ test_cmp expect.origin_other actual.origin_other
+'
+
test_done
--
1.8.1.3.704.g33f7d4f
next prev parent reply other threads:[~2013-05-04 23:56 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-05-04 23:55 [PATCH 0/7] Make "$remote/$branch" work with unconventional refspecs Johan Herland
2013-05-04 23:55 ` [PATCH 1/7] shorten_unambiguous_ref(): Allow shortening refs/remotes/origin/HEAD to origin Johan Herland
2013-05-05 11:56 ` Bert Wesarg
2013-05-06 17:52 ` Junio C Hamano
2013-05-07 18:49 ` Johan Herland
2013-05-07 18:54 ` [PATCHv2 1/3] t1514: Add tests of shortening refnames in strict/loose mode Johan Herland
2013-05-07 18:54 ` [PATCHv2 2/3] t1514: Demonstrate failure to correctly shorten "refs/remotes/origin/HEAD" Johan Herland
2013-05-07 18:54 ` [PATCHv2 3/3] shorten_unambiguous_ref(): Fix shortening refs/remotes/origin/HEAD to origin Johan Herland
2013-05-07 21:03 ` [PATCH 1/7] shorten_unambiguous_ref(): Allow " Junio C Hamano
2013-05-07 21:31 ` Junio C Hamano
2013-05-07 22:03 ` Johan Herland
2013-05-07 22:06 ` Junio C Hamano
2013-05-07 22:37 ` Johan Herland
2013-05-04 23:55 ` [PATCH 2/7] t7900: Start testing usability of namespaced remote refs Johan Herland
2013-05-07 1:29 ` Junio C Hamano
2013-05-07 21:52 ` Johan Herland
2013-05-07 22:20 ` Junio C Hamano
2013-05-04 23:55 ` [PATCH 3/7] t7900: Demonstrate failure to expand "$remote/$branch" according to refspecs Johan Herland
2013-05-07 1:30 ` Junio C Hamano
2013-05-04 23:55 ` [PATCH 4/7] refs.c: Refactor rules for expanding shorthand names into full refnames Johan Herland
2013-05-07 1:36 ` Junio C Hamano
2013-05-04 23:55 ` [PATCH 5/7] refs.c: Refactor code for shortening full refnames into shorthand names Johan Herland
2013-05-07 1:44 ` Junio C Hamano
2013-05-04 23:55 ` [PATCH 6/7] refname_match(): Caller must declare if we're matching local or remote refs Johan Herland
2013-05-07 1:48 ` Junio C Hamano
2013-05-04 23:55 ` Johan Herland [this message]
2013-05-05 4:28 ` [PATCH 0/7] Make "$remote/$branch" work with unconventional refspecs Junio C Hamano
2013-05-05 9:59 ` Johan Herland
2013-05-05 19:02 ` Junio C Hamano
2013-05-05 22:26 ` Johan Herland
2013-05-05 22:36 ` Junio C Hamano
2013-05-06 1:02 ` Santi Béjar
2013-05-06 1:04 ` Santi Béjar
2013-05-06 17:11 ` Junio C Hamano
2013-05-06 19:17 ` Santi Béjar
2013-05-06 17:06 ` Junio C Hamano
2013-05-06 17:20 ` Junio C Hamano
2013-05-06 23:42 ` Johan Herland
2013-05-07 2:11 ` Junio C Hamano
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=1367711749-8812-8-git-send-email-johan@herland.net \
--to=johan@herland.net \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
/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).