提交 54db5c0e 编写于 作者: J Junio C Hamano

Merge branch 'jt/partial-clone-proto-v2'

Transfer protocol v2 learned to support the partial clone.

* jt/partial-clone-proto-v2:
  {fetch,upload}-pack: support filter in protocol v2
  upload-pack: read config when serving protocol v2
  upload-pack: fix error message typo
...@@ -290,6 +290,15 @@ included in the clients request as well as the potential addition of the ...@@ -290,6 +290,15 @@ included in the clients request as well as the potential addition of the
Cannot be used with "deepen", but can be used with Cannot be used with "deepen", but can be used with
"deepen-since". "deepen-since".
If the 'filter' feature is advertised, the following argument can be
included in the client's request:
filter <filter-spec>
Request that various objects from the packfile be omitted
using one of several filtering techniques. These are intended
for use with partial clone and partial fetch operations. See
`rev-list` for possible "filter-spec" values.
The response of `fetch` is broken into a number of sections separated by The response of `fetch` is broken into a number of sections separated by
delimiter packets (0001), with each section beginning with its section delimiter packets (0001), with each section beginning with its section
header. header.
......
...@@ -1198,14 +1198,29 @@ static int send_fetch_request(int fd_out, const struct fetch_pack_args *args, ...@@ -1198,14 +1198,29 @@ static int send_fetch_request(int fd_out, const struct fetch_pack_args *args,
else if (is_repository_shallow() || args->deepen) else if (is_repository_shallow() || args->deepen)
die(_("Server does not support shallow requests")); die(_("Server does not support shallow requests"));
/* Add filter */
if (server_supports_feature("fetch", "filter", 0) &&
args->filter_options.choice) {
print_verbose(args, _("Server supports filter"));
packet_buf_write(&req_buf, "filter %s",
args->filter_options.filter_spec);
} else if (args->filter_options.choice) {
warning("filtering not recognized by server, ignoring");
}
/* add wants */ /* add wants */
add_wants(wants, &req_buf); add_wants(wants, &req_buf);
if (args->no_dependents) {
packet_buf_write(&req_buf, "done");
ret = 1;
} else {
/* Add all of the common commits we've found in previous rounds */ /* Add all of the common commits we've found in previous rounds */
add_common(&req_buf, common); add_common(&req_buf, common);
/* Add initial haves */ /* Add initial haves */
ret = add_haves(&req_buf, haves_to_send, in_vain); ret = add_haves(&req_buf, haves_to_send, in_vain);
}
/* Send request */ /* Send request */
packet_buf_flush(&req_buf); packet_buf_flush(&req_buf);
......
...@@ -194,4 +194,18 @@ test_expect_success 'sending server-options' ' ...@@ -194,4 +194,18 @@ test_expect_success 'sending server-options' '
test_cmp actual expect test_cmp actual expect
' '
test_expect_success 'unexpected lines are not allowed in fetch request' '
git init server &&
test-pkt-line pack >in <<-EOF &&
command=fetch
0001
this-is-not-a-command
0000
EOF
test_must_fail git -C server serve --stateless-rpc <in >/dev/null 2>err &&
grep "unexpected line: .this-is-not-a-command." err
'
test_done test_done
...@@ -233,6 +233,118 @@ test_expect_success 'server-options are sent when fetching' ' ...@@ -233,6 +233,118 @@ test_expect_success 'server-options are sent when fetching' '
grep "server-option=world" log grep "server-option=world" log
' '
test_expect_success 'upload-pack respects config using protocol v2' '
git init server &&
write_script server/.git/hook <<-\EOF &&
touch hookout
"$@"
EOF
test_commit -C server one &&
test_config_global uploadpack.packobjectshook ./hook &&
test_path_is_missing server/.git/hookout &&
git -c protocol.version=2 clone "file://$(pwd)/server" client &&
test_path_is_file server/.git/hookout
'
test_expect_success 'setup filter tests' '
rm -rf server client &&
git init server &&
# 1 commit to create a file, and 1 commit to modify it
test_commit -C server message1 a.txt &&
test_commit -C server message2 a.txt &&
git -C server config protocol.version 2 &&
git -C server config uploadpack.allowfilter 1 &&
git -C server config uploadpack.allowanysha1inwant 1 &&
git -C server config protocol.version 2
'
test_expect_success 'partial clone' '
GIT_TRACE_PACKET="$(pwd)/trace" git -c protocol.version=2 \
clone --filter=blob:none "file://$(pwd)/server" client &&
grep "version 2" trace &&
# Ensure that the old version of the file is missing
git -C client rev-list master --quiet --objects --missing=print \
>observed.oids &&
grep "$(git -C server rev-parse message1:a.txt)" observed.oids &&
# Ensure that client passes fsck
git -C client fsck
'
test_expect_success 'dynamically fetch missing object' '
rm "$(pwd)/trace" &&
GIT_TRACE_PACKET="$(pwd)/trace" git -C client -c protocol.version=2 \
cat-file -p $(git -C server rev-parse message1:a.txt) &&
grep "version 2" trace
'
test_expect_success 'partial fetch' '
rm -rf client "$(pwd)/trace" &&
git init client &&
SERVER="file://$(pwd)/server" &&
test_config -C client extensions.partialClone "$SERVER" &&
GIT_TRACE_PACKET="$(pwd)/trace" git -C client -c protocol.version=2 \
fetch --filter=blob:none "$SERVER" master:refs/heads/other &&
grep "version 2" trace &&
# Ensure that the old version of the file is missing
git -C client rev-list other --quiet --objects --missing=print \
>observed.oids &&
grep "$(git -C server rev-parse message1:a.txt)" observed.oids &&
# Ensure that client passes fsck
git -C client fsck
'
test_expect_success 'do not advertise filter if not configured to do so' '
SERVER="file://$(pwd)/server" &&
rm "$(pwd)/trace" &&
git -C server config uploadpack.allowfilter 1 &&
GIT_TRACE_PACKET="$(pwd)/trace" git -c protocol.version=2 \
ls-remote "$SERVER" &&
grep "fetch=.*filter" trace &&
rm "$(pwd)/trace" &&
git -C server config uploadpack.allowfilter 0 &&
GIT_TRACE_PACKET="$(pwd)/trace" git -c protocol.version=2 \
ls-remote "$SERVER" &&
grep "fetch=" trace >fetch_capabilities &&
! grep filter fetch_capabilities
'
test_expect_success 'partial clone warns if filter is not advertised' '
rm -rf client &&
git -C server config uploadpack.allowfilter 0 &&
git -c protocol.version=2 \
clone --filter=blob:none "file://$(pwd)/server" client 2>err &&
test_i18ngrep "filtering not recognized by server, ignoring" err
'
test_expect_success 'even with handcrafted request, filter does not work if not advertised' '
git -C server config uploadpack.allowfilter 0 &&
# Custom request that tries to filter even though it is not advertised.
test-pkt-line pack >in <<-EOF &&
command=fetch
0001
want $(git -C server rev-parse master)
filter blob:none
0000
EOF
test_must_fail git -C server serve --stateless-rpc <in >/dev/null 2>err &&
grep "unexpected line: .filter blob:none." err &&
# Exercise to ensure that if advertised, filter works
git -C server config uploadpack.allowfilter 1 &&
git -C server serve --stateless-rpc <in >/dev/null
'
# Test protocol v2 with 'http://' transport # Test protocol v2 with 'http://' transport
# #
. "$TEST_DIRECTORY"/lib-httpd.sh . "$TEST_DIRECTORY"/lib-httpd.sh
......
...@@ -1205,6 +1205,7 @@ static void process_args(struct packet_reader *request, ...@@ -1205,6 +1205,7 @@ static void process_args(struct packet_reader *request,
{ {
while (packet_reader_read(request) != PACKET_READ_FLUSH) { while (packet_reader_read(request) != PACKET_READ_FLUSH) {
const char *arg = request->line; const char *arg = request->line;
const char *p;
/* process want */ /* process want */
if (parse_want(arg)) if (parse_want(arg))
...@@ -1251,8 +1252,13 @@ static void process_args(struct packet_reader *request, ...@@ -1251,8 +1252,13 @@ static void process_args(struct packet_reader *request,
continue; continue;
} }
if (allow_filter && skip_prefix(arg, "filter ", &p)) {
parse_list_objects_filter(&filter_options, p);
continue;
}
/* ignore unknown lines maybe? */ /* ignore unknown lines maybe? */
die("unexpect line: '%s'", arg); die("unexpected line: '%s'", arg);
} }
} }
...@@ -1376,6 +1382,8 @@ int upload_pack_v2(struct repository *r, struct argv_array *keys, ...@@ -1376,6 +1382,8 @@ int upload_pack_v2(struct repository *r, struct argv_array *keys,
enum fetch_state state = FETCH_PROCESS_ARGS; enum fetch_state state = FETCH_PROCESS_ARGS;
struct upload_pack_data data; struct upload_pack_data data;
git_config(upload_pack_config, NULL);
upload_pack_data_init(&data); upload_pack_data_init(&data);
use_sideband = LARGE_PACKET_MAX; use_sideband = LARGE_PACKET_MAX;
...@@ -1428,7 +1436,14 @@ int upload_pack_v2(struct repository *r, struct argv_array *keys, ...@@ -1428,7 +1436,14 @@ int upload_pack_v2(struct repository *r, struct argv_array *keys,
int upload_pack_advertise(struct repository *r, int upload_pack_advertise(struct repository *r,
struct strbuf *value) struct strbuf *value)
{ {
if (value) if (value) {
int allow_filter_value;
strbuf_addstr(value, "shallow"); strbuf_addstr(value, "shallow");
if (!repo_config_get_bool(the_repository,
"uploadpack.allowfilter",
&allow_filter_value) &&
allow_filter_value)
strbuf_addstr(value, " filter");
}
return 1; return 1;
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册