Skip to content

Commit 548719f

Browse files
jonathantanmygitster
authored andcommitted
clone: partial clone
Signed-off-by: Jonathan Tan <[email protected]> Signed-off-by: Jeff Hostetler <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 1e1e39b commit 548719f

File tree

2 files changed

+69
-2
lines changed

2 files changed

+69
-2
lines changed

builtin/clone.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "run-command.h"
2727
#include "connected.h"
2828
#include "packfile.h"
29+
#include "list-objects-filter-options.h"
2930

3031
/*
3132
* Overall FIXMEs:
@@ -60,6 +61,7 @@ static struct string_list option_optional_reference = STRING_LIST_INIT_NODUP;
6061
static int option_dissociate;
6162
static int max_jobs = -1;
6263
static struct string_list option_recurse_submodules = STRING_LIST_INIT_NODUP;
64+
static struct list_objects_filter_options filter_options;
6365

6466
static int recurse_submodules_cb(const struct option *opt,
6567
const char *arg, int unset)
@@ -135,6 +137,7 @@ static struct option builtin_clone_options[] = {
135137
TRANSPORT_FAMILY_IPV4),
136138
OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
137139
TRANSPORT_FAMILY_IPV6),
140+
OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
138141
OPT_END()
139142
};
140143

@@ -886,6 +889,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
886889
struct refspec *refspec;
887890
const char *fetch_pattern;
888891

892+
fetch_if_missing = 0;
893+
889894
packet_trace_identity("clone");
890895
argc = parse_options(argc, argv, prefix, builtin_clone_options,
891896
builtin_clone_usage, 0);
@@ -1073,6 +1078,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
10731078
warning(_("--shallow-since is ignored in local clones; use file:// instead."));
10741079
if (option_not.nr)
10751080
warning(_("--shallow-exclude is ignored in local clones; use file:// instead."));
1081+
if (filter_options.choice)
1082+
warning(_("--filter is ignored in local clones; use file:// instead."));
10761083
if (!access(mkpath("%s/shallow", path), F_OK)) {
10771084
if (option_local > 0)
10781085
warning(_("source repository is shallow, ignoring --local"));
@@ -1104,7 +1111,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
11041111
transport_set_option(transport, TRANS_OPT_UPLOADPACK,
11051112
option_upload_pack);
11061113

1107-
if (transport->smart_options && !deepen)
1114+
if (filter_options.choice) {
1115+
transport_set_option(transport, TRANS_OPT_LIST_OBJECTS_FILTER,
1116+
filter_options.filter_spec);
1117+
transport_set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
1118+
}
1119+
1120+
if (transport->smart_options && !deepen && !filter_options.choice)
11081121
transport->smart_options->check_self_contained_and_connected = 1;
11091122

11101123
refs = transport_get_remote_refs(transport);
@@ -1164,13 +1177,17 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
11641177
write_refspec_config(src_ref_prefix, our_head_points_at,
11651178
remote_head_points_at, &branch_top);
11661179

1180+
if (filter_options.choice)
1181+
partial_clone_register("origin", &filter_options);
1182+
11671183
if (is_local)
11681184
clone_local(path, git_dir);
11691185
else if (refs && complete_refs_before_fetch)
11701186
transport_fetch_refs(transport, mapped_refs);
11711187

11721188
update_remote_refs(refs, mapped_refs, remote_head_points_at,
1173-
branch_top.buf, reflog_msg.buf, transport, !is_local);
1189+
branch_top.buf, reflog_msg.buf, transport,
1190+
!is_local && !filter_options.choice);
11741191

11751192
update_head(our_head_points_at, remote_head, reflog_msg.buf);
11761193

@@ -1191,6 +1208,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
11911208
}
11921209

11931210
junk_mode = JUNK_LEAVE_REPO;
1211+
fetch_if_missing = 1;
11941212
err = checkout(submodule_progress);
11951213

11961214
strbuf_release(&reflog_msg);

t/t5601-clone.sh

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,4 +571,53 @@ test_expect_success 'GIT_TRACE_PACKFILE produces a usable pack' '
571571
git -C replay.git index-pack -v --stdin <tmp.pack
572572
'
573573

574+
partial_clone () {
575+
SERVER="$1" &&
576+
URL="$2" &&
577+
578+
rm -rf "$SERVER" client &&
579+
test_create_repo "$SERVER" &&
580+
test_commit -C "$SERVER" one &&
581+
HASH1=$(git hash-object "$SERVER/one.t") &&
582+
git -C "$SERVER" revert HEAD &&
583+
test_commit -C "$SERVER" two &&
584+
HASH2=$(git hash-object "$SERVER/two.t") &&
585+
test_config -C "$SERVER" uploadpack.allowfilter 1 &&
586+
test_config -C "$SERVER" uploadpack.allowanysha1inwant 1 &&
587+
588+
git clone --filter=blob:limit=0 "$URL" client &&
589+
590+
git -C client fsck &&
591+
592+
# Ensure that unneeded blobs are not inadvertently fetched.
593+
test_config -C client extensions.partialclone "not a remote" &&
594+
test_must_fail git -C client cat-file -e "$HASH1" &&
595+
596+
# But this blob was fetched, because clone performs an initial checkout
597+
git -C client cat-file -e "$HASH2"
598+
}
599+
600+
test_expect_success 'partial clone' '
601+
partial_clone server "file://$(pwd)/server"
602+
'
603+
604+
test_expect_success 'partial clone: warn if server does not support object filtering' '
605+
rm -rf server client &&
606+
test_create_repo server &&
607+
test_commit -C server one &&
608+
609+
git clone --filter=blob:limit=0 "file://$(pwd)/server" client 2> err &&
610+
611+
test_i18ngrep "filtering not recognized by server" err
612+
'
613+
614+
. "$TEST_DIRECTORY"/lib-httpd.sh
615+
start_httpd
616+
617+
test_expect_success 'partial clone using HTTP' '
618+
partial_clone "$HTTPD_DOCUMENT_ROOT_PATH/server" "$HTTPD_URL/smart/server"
619+
'
620+
621+
stop_httpd
622+
574623
test_done

0 commit comments

Comments
 (0)