From: Jonathan Tan <jonathantanmy@google.com>
To: git@vger.kernel.org
Cc: Jonathan Tan <jonathantanmy@google.com>
Subject: [RFC 11/14] fetch-pack: support want-ref
Date: Wed, 25 Jan 2017 14:03:04 -0800 [thread overview]
Message-ID: <7b01ee955db8b2d9c6c7e641f7f09436938b2af4.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 use the want-ref mechanism whenever the server
advertises it.
Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
---
builtin/fetch-pack.c | 5 +-
fetch-pack.c | 173 ++++++++++++++++++++++++++++++++++++--------------
fetch-pack.h | 2 +
t/t5500-fetch-pack.sh | 42 ++++++++++++
transport.c | 2 +-
5 files changed, 175 insertions(+), 49 deletions(-)
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index 5f14242ae..ae073ab24 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -179,8 +179,9 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
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_refs, nr_sought_refs,
- &shallow, pack_lockfile_ptr);
+ ref = fetch_pack(&args, fd, conn, ref, dest, sought, nr_sought,
+ sought_refs, nr_sought_refs, &shallow,
+ pack_lockfile_ptr);
if (pack_lockfile) {
printf("lock %s\n", pack_lockfile);
fflush(stdout);
diff --git a/fetch-pack.c b/fetch-pack.c
index 8cc85c19f..02149c930 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -219,11 +219,19 @@ static void consume_shallow_list(struct fetch_pack_args *args, int fd)
}
}
-static enum ack_type get_ack(int fd, unsigned char *result_sha1)
+/*
+ * Reads an ACK or NAK from fd. If wanted_ref_tail is not NULL, also accepts
+ * any "wanted-ref" lines before that ACK or NAK, writing them to
+ * wanted_ref_tail.
+ */
+static enum ack_type get_ack(int fd, unsigned char *result_sha1,
+ struct ref ***wanted_ref_tail)
{
int len;
- char *line = packet_read_line(fd, &len);
+ char *line;
const char *arg;
+start:
+ line = packet_read_line(fd, &len);
if (!len)
die(_("git fetch-pack: expected ACK/NAK, got EOF"));
@@ -244,7 +252,19 @@ static enum ack_type get_ack(int fd, unsigned char *result_sha1)
return ACK;
}
}
- die(_("git fetch-pack: expected ACK/NAK, got '%s'"), line);
+ if (wanted_ref_tail) {
+ struct object_id oid;
+ if (skip_prefix(line, "wanted-ref ", &arg) &&
+ !get_sha1_hex(arg, oid.hash) && arg[40] == ' ' && arg[41]) {
+ struct ref *ref = alloc_ref(arg + 41);
+ oidcpy(&ref->old_oid, &oid);
+ **wanted_ref_tail = ref;
+ *wanted_ref_tail = &ref->next;
+ goto start;
+ }
+ die(_("git fetch_pack: expected ACK/NAK or wanted-ref, got '%s'"), line);
+ }
+ die(_("git fetch_pack: expected ACK/NAK, got '%s'"), line);
}
static void send_request(struct fetch_pack_args *args,
@@ -282,29 +302,55 @@ static int next_flush(struct fetch_pack_args *args, int count)
return count;
}
-static int find_common(struct fetch_pack_args *args,
- int fd[2], unsigned char *result_sha1,
- struct ref *refs)
+static void write_capabilities(struct strbuf *sb,
+ const struct fetch_pack_args *args)
{
- int fetching;
- int count = 0, flushes = 0, flush_at = INITIAL_FLUSH, retval;
- const unsigned char *sha1;
- unsigned in_vain = 0;
- int got_continue = 0;
- int got_ready = 0;
- struct strbuf req_buf = STRBUF_INIT;
- size_t state_len = 0;
+ if (multi_ack == 2) strbuf_addstr(sb, " multi_ack_detailed");
+ if (multi_ack == 1) strbuf_addstr(sb, " multi_ack");
+ if (no_done) strbuf_addstr(sb, " no-done");
+ if (use_sideband == 2) strbuf_addstr(sb, " side-band-64k");
+ if (use_sideband == 1) strbuf_addstr(sb, " side-band");
+ if (args->deepen_relative) strbuf_addstr(sb, " deepen-relative");
+ if (args->use_thin_pack) strbuf_addstr(sb, " thin-pack");
+ if (args->no_progress) strbuf_addstr(sb, " no-progress");
+ if (args->include_tag) strbuf_addstr(sb, " include-tag");
+ if (prefer_ofs_delta) strbuf_addstr(sb, " ofs-delta");
+ if (deepen_since_ok) strbuf_addstr(sb, " deepen-since");
+ if (deepen_not_ok) strbuf_addstr(sb, " deepen-not");
+ if (agent_supported) strbuf_addf(sb, " agent=%s",
+ git_user_agent_sanitized());
+}
- if (args->stateless_rpc && multi_ack == 1)
- die(_("--stateless-rpc requires multi_ack_detailed"));
- if (marked)
- for_each_ref(clear_marks, NULL);
- marked = 1;
+static void write_wants(struct strbuf *sb, const struct fetch_pack_args *args,
+ const struct refspec *refspecs, int nr_refspec,
+ struct ref *refs)
+{
+ int capabilities_written = 0;
- for_each_ref(rev_list_insert_ref_oid, NULL);
- for_each_alternate_ref(insert_one_alternate_ref, NULL);
+ if (refspecs) {
+ int i;
+ for (i = 0; i < nr_refspec; i++) {
+ const char *to_send = (refspecs[i].src && refspecs[i].src[0])
+ ? refspecs[i].src : "HEAD";
+ if (i == 0) {
+ struct strbuf c = STRBUF_INIT;
+ write_capabilities(&c, args);
+ packet_buf_write(sb, "want-ref %s%s\n",
+ to_send, c.buf);
+ strbuf_release(&c);
+ } else
+ packet_buf_write(sb, "want-ref %s\n", to_send);
+
+ /* write everything that refname_match supports */
+ packet_buf_write(sb, "want-ref refs/%s\n", to_send);
+ packet_buf_write(sb, "want-ref refs/tags/%s\n", to_send);
+ packet_buf_write(sb, "want-ref refs/heads/%s\n", to_send);
+ packet_buf_write(sb, "want-ref refs/remotes/%s\n", to_send);
+ packet_buf_write(sb, "want-ref refs/remotes/%s/HEAD\n", to_send);
+ }
+ return;
+ }
- fetching = 0;
for ( ; refs ; refs = refs->next) {
unsigned char *remote = refs->old_oid.hash;
const char *remote_hex;
@@ -326,30 +372,41 @@ static int find_common(struct fetch_pack_args *args,
}
remote_hex = sha1_to_hex(remote);
- if (!fetching) {
+ if (!capabilities_written) {
struct strbuf c = STRBUF_INIT;
- if (multi_ack == 2) strbuf_addstr(&c, " multi_ack_detailed");
- if (multi_ack == 1) strbuf_addstr(&c, " multi_ack");
- if (no_done) strbuf_addstr(&c, " no-done");
- if (use_sideband == 2) strbuf_addstr(&c, " side-band-64k");
- if (use_sideband == 1) strbuf_addstr(&c, " side-band");
- if (args->deepen_relative) strbuf_addstr(&c, " deepen-relative");
- if (args->use_thin_pack) strbuf_addstr(&c, " thin-pack");
- if (args->no_progress) strbuf_addstr(&c, " no-progress");
- if (args->include_tag) strbuf_addstr(&c, " include-tag");
- if (prefer_ofs_delta) strbuf_addstr(&c, " ofs-delta");
- if (deepen_since_ok) strbuf_addstr(&c, " deepen-since");
- if (deepen_not_ok) strbuf_addstr(&c, " deepen-not");
- if (agent_supported) strbuf_addf(&c, " agent=%s",
- git_user_agent_sanitized());
- packet_buf_write(&req_buf, "want %s%s\n", remote_hex, c.buf);
+ write_capabilities(&c, args);
+ packet_buf_write(sb, "want %s%s\n", remote_hex, c.buf);
strbuf_release(&c);
+ capabilities_written = 1;
} else
- packet_buf_write(&req_buf, "want %s\n", remote_hex);
- fetching++;
+ packet_buf_write(sb, "want %s\n", remote_hex);
}
+}
+
+static int find_common(struct fetch_pack_args *args,
+ int fd[2], unsigned char *result_sha1,
+ struct strbuf *wants, struct ref **wanted_refs)
+{
+ int count = 0, flushes = 0, flush_at = INITIAL_FLUSH, retval;
+ const unsigned char *sha1;
+ unsigned in_vain = 0;
+ int got_continue = 0;
+ int got_ready = 0;
+ struct strbuf req_buf = STRBUF_INIT;
+ size_t state_len = 0;
+
+ if (args->stateless_rpc && multi_ack == 1)
+ die(_("--stateless-rpc requires multi_ack_detailed"));
+ if (marked)
+ for_each_ref(clear_marks, NULL);
+ marked = 1;
- if (!fetching) {
+ for_each_ref(rev_list_insert_ref_oid, NULL);
+ for_each_alternate_ref(insert_one_alternate_ref, NULL);
+
+ strbuf_swap(&req_buf, wants);
+
+ if (!req_buf.len) {
strbuf_release(&req_buf);
packet_flush(fd[1]);
return 1;
@@ -435,7 +492,7 @@ static int find_common(struct fetch_pack_args *args,
consume_shallow_list(args, fd[0]);
do {
- ack = get_ack(fd[0], result_sha1);
+ ack = get_ack(fd[0], result_sha1, NULL);
if (ack)
print_verbose(args, _("got %s %d %s"), "ack",
ack, sha1_to_hex(result_sha1));
@@ -504,7 +561,9 @@ static int find_common(struct fetch_pack_args *args,
if (!got_ready || !no_done)
consume_shallow_list(args, fd[0]);
while (flushes || multi_ack) {
- int ack = get_ack(fd[0], result_sha1);
+ struct ref *wr = NULL, **wr_tail = ≀
+ int ack = get_ack(fd[0], result_sha1, &wr_tail);
+ *wanted_refs = wr;
if (ack) {
print_verbose(args, _("got %s (%d) %s"), "ack",
ack, sha1_to_hex(result_sha1));
@@ -835,6 +894,7 @@ static int cmp_ref_by_name(const void *a_, const void *b_)
static struct ref *do_fetch_pack(struct fetch_pack_args *args,
int fd[2],
const struct ref *orig_ref,
+ const struct refspec *refspecs, int nr_refspec,
const struct ref **sought, int nr_sought,
struct shallow_info *si,
char **pack_lockfile)
@@ -843,6 +903,10 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
unsigned char sha1[20];
const char *agent_feature;
int agent_len;
+ int ref_in_want = 0;
+ struct strbuf wants = STRBUF_INIT;
+ struct ref *wanted_refs = NULL;
+ int want_ref_used = 0;
sort_ref_list(&ref, ref_compare_name);
QSORT(sought, nr_sought, cmp_ref_by_name);
@@ -907,17 +971,26 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
die(_("Server does not support --shallow-exclude"));
if (!server_supports("deepen-relative") && args->deepen_relative)
die(_("Server does not support --deepen"));
+ if (server_supports("ref-in-want"))
+ ref_in_want = 1;
if (everything_local(args, &ref, sought, nr_sought)) {
packet_flush(fd[1]);
goto all_done;
}
- if (find_common(args, fd, sha1, ref) < 0)
+
+ if (ref_in_want && refspecs) {
+ write_wants(&wants, args, refspecs, nr_refspec, NULL);
+ want_ref_used = 1;
+ } else
+ write_wants(&wants, args, NULL, 0, ref);
+ if (find_common(args, fd, sha1, &wants, &wanted_refs) < 0)
if (!args->keep_pack)
/* When cloning, it is not unusual to have
* no common commit.
*/
warning(_("no common commits"));
+ strbuf_release(&wants);
if (args->stateless_rpc)
packet_flush(fd[1]);
@@ -932,6 +1005,13 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
die(_("git fetch-pack: fetch failed."));
all_done:
+ if (want_ref_used) {
+ free_refs(ref);
+ return wanted_refs;
+ }
+
+ if (wanted_refs)
+ die("Protocol error: we are not using ref-in-want but server still sends wanted-ref");
return ref;
}
@@ -1082,6 +1162,7 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
int fd[], struct child_process *conn,
const struct ref *ref,
const char *dest,
+ const struct refspec *refspecs, int nr_refspec,
const struct ref **sought, int nr_sought,
struct sha1_array *shallow,
char **pack_lockfile)
@@ -1098,8 +1179,8 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
die(_("no matching remote head"));
}
prepare_shallow_info(&si, shallow);
- ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought,
- &si, pack_lockfile);
+ ref_cpy = do_fetch_pack(args, fd, ref, refspecs, nr_refspec,
+ sought, nr_sought, &si, pack_lockfile);
reprepare_packed_git();
update_shallow(args, ref_cpy, &si);
clear_shallow_info(&si);
diff --git a/fetch-pack.h b/fetch-pack.h
index 6e4fdbb68..06eb0fb28 100644
--- a/fetch-pack.h
+++ b/fetch-pack.h
@@ -5,6 +5,7 @@
#include "run-command.h"
struct sha1_array;
+struct refspec;
struct fetch_pack_args {
const char *uploadpack;
@@ -38,6 +39,7 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
int fd[], struct child_process *conn,
const struct ref *ref,
const char *dest,
+ const struct refspec *refspecs, int nr_refspec,
const struct ref **sought,
int nr_sought,
struct sha1_array *shallow,
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index cb1b7d949..18fe23c97 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -563,6 +563,25 @@ test_expect_success 'fetch-pack can fetch refs using a partial name' '
grep "$(printf "%s refs/heads/one" $(git -C server rev-parse --verify one))" actual
'
+test_expect_success 'fetch-pack can fetch refs using a partial name using want-ref' '
+ rm -rf server &&
+ git init server &&
+ (
+ cd server &&
+ git config uploadpack.advertiseRefInWant true
+ test_commit 1 &&
+ test_commit 2 &&
+ git checkout -b one
+ ) &&
+ rm -f trace &&
+ GIT_TRACE_PACKET="$(pwd)/trace" git fetch-pack server one >actual &&
+ echo here &&
+ grep " want-ref " trace &&
+ ! grep " want " 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 &&
@@ -585,6 +604,29 @@ test_expect_success 'fetch-pack can fetch refs using a glob' '
grep "$(printf "%s refs/heads/onc" $(git -C server rev-parse --verify onc))" actual
'
+test_expect_success 'fetch-pack can fetch refs using a glob using want-ref' '
+ rm -rf server &&
+ git init server &&
+ (
+ cd server &&
+ git config uploadpack.advertiseRefInWant true
+ 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-ref " trace &&
+ ! grep " want " 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
diff --git a/transport.c b/transport.c
index 5ed3fc68e..85a4c5369 100644
--- a/transport.c
+++ b/transport.c
@@ -239,7 +239,7 @@ static int fetch_refs_via_pack(struct transport *transport,
refs = fetch_pack(&args, data->fd, data->conn,
refs_tmp ? refs_tmp : transport->remote_refs,
- dest, to_fetch, nr_heads, &data->shallow,
+ dest, NULL, 0, to_fetch, nr_heads, &data->shallow,
&transport->pack_lockfile);
close(data->fd[0]);
close(data->fd[1]);
--
2.11.0.483.g087da7b7c-goog
next prev parent reply other threads:[~2017-01-25 22:03 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 ` [RFC 10/14] fetch-pack: support partial names and globs Jonathan Tan
2017-01-25 22:03 ` Jonathan Tan [this message]
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=7b01ee955db8b2d9c6c7e641f7f09436938b2af4.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).