From: Jonathan Tan <jonathantanmy@google.com>
To: git@vger.kernel.org
Cc: Jonathan Tan <jonathantanmy@google.com>
Subject: [RFC 10/14] fetch-pack: support partial names and globs
Date: Wed, 25 Jan 2017 14:03:03 -0800 [thread overview]
Message-ID: <8e8ff3cbd7276233e712b4d0049e709c2372cfd7.1485381677.git.jonathantanmy@google.com> (raw)
In-Reply-To: <cover.1485381677.git.jonathantanmy@google.com>
In-Reply-To: <cover.1485381677.git.jonathantanmy@google.com>
Teach fetch-pack to support partial ref names and ref patterns as input.
This does not use "want-ref" yet - support for that will be added in a
future patch.
Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
---
builtin/fetch-pack.c | 40 ++++++++++++-------------------------
remote.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++
remote.h | 16 +++++++++++++++
t/t5500-fetch-pack.sh | 38 +++++++++++++++++++++++++++++++++++
4 files changed, 122 insertions(+), 27 deletions(-)
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index a18fd0c44..5f14242ae 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -11,32 +11,12 @@ static const char fetch_pack_usage[] =
"[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] "
"[--no-progress] [--diag-url] [-v] [<host>:]<directory> [<refs>...]";
-static void add_sought_entry(const struct ref ***sought, int *nr, int *alloc,
+static void add_sought_entry(struct refspec **sought, int *nr, int *alloc,
const char *name)
{
- struct ref *ref;
- struct object_id oid;
-
- if (!get_oid_hex(name, &oid)) {
- if (name[GIT_SHA1_HEXSZ] == ' ') {
- /* <sha1> <ref>, find refname */
- name += GIT_SHA1_HEXSZ + 1;
- } else if (name[GIT_SHA1_HEXSZ] == '\0') {
- ; /* <sha1>, leave sha1 as name */
- } else {
- /* <ref>, clear cruft from oid */
- oidclr(&oid);
- }
- } else {
- /* <ref>, clear cruft from get_oid_hex */
- oidclr(&oid);
- }
-
- ref = alloc_ref(name);
- oidcpy(&ref->old_oid, &oid);
(*nr)++;
ALLOC_GROW(*sought, *nr, *alloc);
- (*sought)[*nr - 1] = ref;
+ parse_ref_or_pattern(&(*sought)[*nr - 1], name);
}
int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
@@ -44,8 +24,10 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
int i, ret;
struct ref *ref = NULL;
const char *dest = NULL;
- const struct ref **sought = NULL;
+ struct refspec *sought = NULL;
int nr_sought = 0, alloc_sought = 0;
+ const struct ref **sought_refs;
+ int nr_sought_refs;
int fd[2];
char *pack_lockfile = NULL;
char **pack_lockfile_ptr = NULL;
@@ -195,8 +177,9 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
return args.diag_url ? 0 : 1;
}
get_remote_heads(fd[0], NULL, 0, &ref, 0, NULL, &shallow);
+ get_ref_array(&sought_refs, &nr_sought_refs, ref, sought, nr_sought);
- ref = fetch_pack(&args, fd, conn, ref, dest, sought, nr_sought,
+ ref = fetch_pack(&args, fd, conn, ref, dest, sought_refs, nr_sought_refs,
&shallow, pack_lockfile_ptr);
if (pack_lockfile) {
printf("lock %s\n", pack_lockfile);
@@ -222,12 +205,15 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
*/
for (i = 0; i < nr_sought; i++) {
struct ref *r;
- for (r = ref; r; r = r->next)
- if (!sought[i] || refname_match(sought[i]->name, r->name))
+ if (sought[i].pattern)
+ continue; /* patterns do not need to match anything */
+ for (r = ref; r; r = r->next) {
+ if (refname_match(sought[i].src, r->name))
break;
+ }
if (r)
continue;
- error("no such remote ref %s", sought[i]->name);
+ error("no such remote ref %s", sought[i].src);
ret = 1;
}
diff --git a/remote.c b/remote.c
index 725a2d39a..08f3c910e 100644
--- a/remote.c
+++ b/remote.c
@@ -612,6 +612,39 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
die("Invalid refspec '%s'", refspec[i]);
}
+void parse_ref_or_pattern(struct refspec *refspec, const char *str)
+{
+ struct object_id oid;
+ memset(refspec, 0, sizeof(*refspec));
+
+ if (!get_oid_hex(str, &oid)) {
+ if (str[GIT_SHA1_HEXSZ] == ' ') {
+ struct object_id oid2;
+ /* <sha1> <ref>, find refname */
+ refspec->src = xstrdup(str + GIT_SHA1_HEXSZ + 1);
+ if (!get_oid_hex(refspec->src, &oid2)
+ && !oidcmp(&oid, &oid2))
+ /* The name is actually a SHA-1 */
+ refspec->exact_sha1 = 1;
+ } else if (str[GIT_SHA1_HEXSZ] == '\0') {
+ ; /* <sha1>, leave sha1 as name */
+ refspec->src = xstrdup(str);
+ refspec->exact_sha1 = 1;
+ } else {
+ /* <ref> */
+ refspec->src = xstrdup(str);
+ }
+ } else {
+ /* <ref> */
+ refspec->src = xstrdup(str);
+ }
+
+ if (has_glob_specials(refspec->src)) {
+ refspec->pattern = 1;
+ refspec->dst = refspec->src;
+ }
+}
+
int valid_fetch_refspec(const char *fetch_refspec_str)
{
struct refspec *refspec;
@@ -1924,6 +1957,28 @@ int get_fetch_map(const struct ref *remote_refs,
return 0;
}
+void get_ref_array(const struct ref ***refs, int *nr_ref,
+ const struct ref *remote_refs,
+ const struct refspec *refspecs, int nr_refspecs)
+{
+ struct ref *head = NULL, **tail = &head;
+ const struct ref **array = NULL;
+ int nr = 0, alloc = 0;
+
+ struct ref *r;
+ int i;
+
+ for (i = 0; i < nr_refspecs; i++)
+ get_fetch_map(remote_refs, &refspecs[i], &tail, 1);
+ for (r = head; r; r = r->next) {
+ nr++;
+ ALLOC_GROW(array, nr, alloc);
+ array[nr - 1] = r;
+ }
+ *refs = array;
+ *nr_ref = nr;
+}
+
int resolve_remote_symref(struct ref *ref, struct ref *list)
{
if (!ref->symref)
diff --git a/remote.h b/remote.h
index 2f7f23d47..daca1c65e 100644
--- a/remote.h
+++ b/remote.h
@@ -162,6 +162,13 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);
*/
struct ref *ref_remove_duplicates(struct ref *ref_map);
+/*
+ * Parse the given ref or ref pattern. If a ref, write a refspec with that ref
+ * as src, and with an empty dst. If a ref pattern, write a glob refspec with
+ * that pattern as src and dst.
+ */
+void parse_ref_or_pattern(struct refspec *refspec, const char *str);
+
int valid_fetch_refspec(const char *refspec);
struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec);
@@ -192,6 +199,15 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
int get_fetch_map(const struct ref *remote_refs, const struct refspec *refspec,
struct ref ***tail, int missing_ok);
+/*
+ * Convenience function to generate an array of refs corresponding to the given
+ * refspecs. This is equivalent to repeatedly calling get_fetch_map and
+ * rearranging the returned refs as an array.
+ */
+void get_ref_array(const struct ref ***refs, int *nr_ref,
+ const struct ref *remote_refs,
+ const struct refspec *refspecs, int nr_refspecs);
+
struct ref *get_remote_ref(const struct ref *remote_refs, const char *name);
/*
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 505e1b4a7..cb1b7d949 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -547,6 +547,44 @@ test_expect_success 'fetch-pack can fetch a raw sha1' '
git fetch-pack hidden $(git -C hidden rev-parse refs/hidden/one)
'
+test_expect_success 'fetch-pack can fetch refs using a partial name' '
+ git init server &&
+ (
+ cd server &&
+ test_commit 1 &&
+ test_commit 2 &&
+ git checkout -b one
+ ) &&
+ rm -f trace &&
+ GIT_TRACE_PACKET="$(pwd)/trace" git fetch-pack server one >actual &&
+ grep " want " trace &&
+ ! grep " want-ref " trace &&
+
+ grep "$(printf "%s refs/heads/one" $(git -C server rev-parse --verify one))" actual
+'
+
+test_expect_success 'fetch-pack can fetch refs using a glob' '
+ rm -rf server &&
+ git init server &&
+ (
+ cd server &&
+ test_commit 1 &&
+ test_commit 2 &&
+ git checkout -b ona &&
+ git checkout -b onb &&
+ test_commit 3 &&
+ git checkout -b onc
+ ) &&
+ rm -f trace &&
+ GIT_TRACE_PACKET="$(pwd)/trace" git fetch-pack server "refs/heads/on*" >actual &&
+ grep " want " trace &&
+ ! grep " want-ref " trace &&
+
+ grep "$(printf "%s refs/heads/ona" $(git -C server rev-parse --verify ona))" actual &&
+ grep "$(printf "%s refs/heads/onb" $(git -C server rev-parse --verify onb))" actual &&
+ grep "$(printf "%s refs/heads/onc" $(git -C server rev-parse --verify onc))" actual
+'
+
check_prot_path () {
cat >expected <<-EOF &&
Diag: url=$1
--
2.11.0.483.g087da7b7c-goog
next prev parent reply other threads:[~2017-01-25 22:04 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-01-25 22:02 [RFC 00/14] Allow fetch-pack to send ref names (globs allowed) Jonathan Tan
2017-01-25 22:02 ` [RFC 01/14] upload-pack: move parsing of "want" line Jonathan Tan
2017-01-25 22:02 ` [RFC 02/14] upload-pack: allow ref name and glob requests Jonathan Tan
2017-01-26 22:23 ` Junio C Hamano
2017-01-27 0:35 ` Jonathan Tan
2017-01-27 1:54 ` Junio C Hamano
2017-01-25 22:02 ` [RFC 03/14] upload-pack: test negotiation with changing repo Jonathan Tan
2017-01-26 22:33 ` Junio C Hamano
2017-01-27 0:44 ` Jonathan Tan
2017-02-22 23:36 ` Junio C Hamano
2017-02-23 18:43 ` [PATCH] upload-pack: report "not our ref" to client Jonathan Tan
2017-02-23 20:14 ` Junio C Hamano
2017-01-25 22:02 ` [RFC 04/14] fetch: refactor the population of hashes Jonathan Tan
2017-01-25 22:02 ` [RFC 05/14] fetch: refactor fetch_refs into two functions Jonathan Tan
2017-01-25 22:02 ` [RFC 06/14] fetch: refactor to make function args narrower Jonathan Tan
2017-01-25 22:03 ` [RFC 07/14] fetch-pack: put shallow info in out param Jonathan Tan
2017-01-25 22:03 ` [RFC 08/14] fetch-pack: check returned refs for matches Jonathan Tan
2017-01-25 22:03 ` [RFC 09/14] transport: put ref oid in out param Jonathan Tan
2017-01-25 22:03 ` Jonathan Tan [this message]
2017-01-25 22:03 ` [RFC 11/14] fetch-pack: support want-ref Jonathan Tan
2017-01-25 22:03 ` [RFC 12/14] fetch-pack: do not printf after closing stdout Jonathan Tan
2017-01-26 0:50 ` Stefan Beller
2017-01-26 18:18 ` Jonathan Tan
2017-01-25 22:03 ` [RFC 13/14] fetch: send want-ref and receive fetched refs Jonathan Tan
2017-01-25 22:03 ` [RFC 14/14] DONT USE advertise_ref_in_want=1 Jonathan Tan
2017-01-26 22:15 ` [RFC 00/14] Allow fetch-pack to send ref names (globs allowed) Stefan Beller
2017-01-26 23:00 ` Jeff King
2017-01-27 0:26 ` Jonathan Tan
2017-02-07 23:53 ` Jonathan Tan
2017-02-09 0:26 ` 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
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=8e8ff3cbd7276233e712b4d0049e709c2372cfd7.1485381677.git.jonathantanmy@google.com \
--to=jonathantanmy@google.com \
--cc=git@vger.kernel.org \
/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.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
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 read-only IMAP folder(s) and NNTP newsgroup(s).