Skip to content

Commit 5556891

Browse files
derrickstoleegitster
authored andcommitted
clone: add --bundle-uri option
Cloning a remote repository is one of the most expensive operations in Git. The server can spend a lot of CPU time generating a pack-file for the client's request. The amount of data can clog the network for a long time, and the Git protocol is not resumable. For users with poor network connections or are located far away from the origin server, this can be especially painful. Add a new '--bundle-uri' option to 'git clone' to bootstrap a clone from a bundle. If the user is aware of a bundle server, then they can tell Git to bootstrap the new repository with these bundles before fetching the remaining objects from the origin server. Reviewed-by: Josh Steadmon <[email protected]> Signed-off-by: Derrick Stolee <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 53a5089 commit 5556891

File tree

3 files changed

+57
-0
lines changed

3 files changed

+57
-0
lines changed

Documentation/git-clone.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,12 @@ or `--mirror` is given)
323323
for `host.xz:foo/.git`). Cloning into an existing directory
324324
is only allowed if the directory is empty.
325325

326+
--bundle-uri=<uri>::
327+
Before fetching from the remote, fetch a bundle from the given
328+
`<uri>` and unbundle the data into the local repository. The refs
329+
in the bundle will be stored under the hidden `refs/bundle/*`
330+
namespace.
331+
326332
:git-clone: 1
327333
include::urls.txt[]
328334

builtin/clone.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "list-objects-filter-options.h"
3535
#include "hook.h"
3636
#include "bundle.h"
37+
#include "bundle-uri.h"
3738

3839
/*
3940
* Overall FIXMEs:
@@ -77,6 +78,7 @@ static int option_filter_submodules = -1; /* unspecified */
7778
static int config_filter_submodules = -1; /* unspecified */
7879
static struct string_list server_options = STRING_LIST_INIT_NODUP;
7980
static int option_remote_submodules;
81+
static const char *bundle_uri;
8082

8183
static int recurse_submodules_cb(const struct option *opt,
8284
const char *arg, int unset)
@@ -160,6 +162,8 @@ static struct option builtin_clone_options[] = {
160162
N_("any cloned submodules will use their remote-tracking branch")),
161163
OPT_BOOL(0, "sparse", &option_sparse_checkout,
162164
N_("initialize sparse-checkout file to include only files at root")),
165+
OPT_STRING(0, "bundle-uri", &bundle_uri,
166+
N_("uri"), N_("a URI for downloading bundles before fetching from origin remote")),
163167
OPT_END()
164168
};
165169

@@ -1232,6 +1236,17 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
12321236
if (transport->smart_options && !deepen && !filter_options.choice)
12331237
transport->smart_options->check_self_contained_and_connected = 1;
12341238

1239+
/*
1240+
* Before fetching from the remote, download and install bundle
1241+
* data from the --bundle-uri option.
1242+
*/
1243+
if (bundle_uri) {
1244+
/* At this point, we need the_repository to match the cloned repo. */
1245+
repo_init(the_repository, git_dir, work_tree);
1246+
if (fetch_bundle_uri(the_repository, bundle_uri))
1247+
warning(_("failed to fetch objects from bundle URI '%s'"),
1248+
bundle_uri);
1249+
}
12351250

12361251
strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
12371252
refspec_ref_prefixes(&remote->fetch,

t/t5558-clone-bundle-uri.sh

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/bin/sh
2+
3+
test_description='test fetching bundles with --bundle-uri'
4+
5+
. ./test-lib.sh
6+
7+
test_expect_success 'fail to clone from non-existent file' '
8+
test_when_finished rm -rf test &&
9+
git clone --bundle-uri="$(pwd)/does-not-exist" . test 2>err &&
10+
grep "failed to download bundle from URI" err
11+
'
12+
13+
test_expect_success 'fail to clone from non-bundle file' '
14+
test_when_finished rm -rf test &&
15+
echo bogus >bogus &&
16+
git clone --bundle-uri="$(pwd)/bogus" . test 2>err &&
17+
grep "is not a bundle" err
18+
'
19+
20+
test_expect_success 'create bundle' '
21+
git init clone-from &&
22+
git -C clone-from checkout -b topic &&
23+
test_commit -C clone-from A &&
24+
test_commit -C clone-from B &&
25+
git -C clone-from bundle create B.bundle topic
26+
'
27+
28+
test_expect_success 'clone with path bundle' '
29+
git clone --bundle-uri="clone-from/B.bundle" \
30+
clone-from clone-path &&
31+
git -C clone-path rev-parse refs/bundles/topic >actual &&
32+
git -C clone-from rev-parse topic >expect &&
33+
test_cmp expect actual
34+
'
35+
36+
test_done

0 commit comments

Comments
 (0)