Skip to content

Commit 87cd689

Browse files
committed
clone: set fetch.bundleURI if bundle.forFetch is advertised
TODO: change forFetch local to a 'flags' value. NEEDSWORK: we are downloading too many bundles. Signed-off-by: Derrick Stolee <[email protected]>
1 parent 03f4176 commit 87cd689

File tree

6 files changed

+206
-3
lines changed

6 files changed

+206
-3
lines changed

Documentation/config/fetch.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,11 @@ fetch.writeCommitGraph::
9696
merge and the write may take longer. Having an updated commit-graph
9797
file helps performance of many Git commands, including `git merge-base`,
9898
`git push -f`, and `git log --graph`. Defaults to false.
99+
100+
fetch.bundleURI::
101+
This value stores a URI for fetching Git object data from a bundle URI
102+
before performing an incremental fetch from the origin Git server. If
103+
the value is `<uri>` then running `git fetch <args>` is equivalent to
104+
first running `git fetch --bundle-uri=<uri>` immediately before
105+
`git fetch <args>`. See details of the `--bundle-uri` option in
106+
linkgit:git-fetch[1].

builtin/clone.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1245,11 +1245,15 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
12451245
* data from the --bundle-uri option.
12461246
*/
12471247
if (bundle_uri) {
1248+
enum bundle_list_flags flags = 0;
1249+
12481250
/* At this point, we need the_repository to match the cloned repo. */
12491251
repo_init(the_repository, git_dir, work_tree);
1250-
if (fetch_bundle_uri(the_repository, bundle_uri))
1252+
if (fetch_bundle_uri(the_repository, bundle_uri, &flags))
12511253
warning(_("failed to fetch objects from bundle URI '%s'"),
12521254
bundle_uri);
1255+
else if (flags & BUNDLE_FLAG_FOR_FETCH)
1256+
git_config_set_gently("fetch.bundleuri", bundle_uri);
12531257
}
12541258

12551259
strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");

builtin/fetch.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "commit-graph.h"
3030
#include "shallow.h"
3131
#include "worktree.h"
32+
#include "bundle-uri.h"
3233

3334
#define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
3435

@@ -2084,6 +2085,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
20842085
int cmd_fetch(int argc, const char **argv, const char *prefix)
20852086
{
20862087
int i;
2088+
const char *bundle_uri;
20872089
struct string_list list = STRING_LIST_INIT_DUP;
20882090
struct remote *remote = NULL;
20892091
int result = 0;
@@ -2169,6 +2171,9 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
21692171
if (dry_run)
21702172
write_fetch_head = 0;
21712173

2174+
if (!git_config_get_string_tmp("fetch.bundleuri", &bundle_uri))
2175+
result = fetch_bundle_uri(the_repository, bundle_uri, NULL);
2176+
21722177
if (all) {
21732178
if (argc == 1)
21742179
die(_("fetch --all does not take a repository argument"));

bundle-uri.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,12 @@ static int bundle_list_update(const char *key, const char *value,
153153
return 0;
154154
}
155155

156+
if (!strcmp(subkey, "flag")) {
157+
if (!strcmp("forFetch", value))
158+
list->flags |= BUNDLE_FLAG_FOR_FETCH;
159+
return 0;
160+
}
161+
156162
if (!strcmp(subkey, "heuristic")) {
157163
int i;
158164
for (i = 0; i < BUNDLE_HEURISTIC_COUNT; i++) {
@@ -574,6 +580,8 @@ static int fetch_bundle_list_in_config_format(struct repository *r,
574580
goto cleanup;
575581

576582
cleanup:
583+
/* Copy results from the local list to the global list. */
584+
global_list->flags |= list_from_bundle.flags;
577585
clear_bundle_list(&list_from_bundle);
578586
return result;
579587
}
@@ -699,7 +707,8 @@ static int unlink_bundle(struct remote_bundle_info *info, void *data)
699707
return 0;
700708
}
701709

702-
int fetch_bundle_uri(struct repository *r, const char *uri)
710+
int fetch_bundle_uri(struct repository *r, const char *uri,
711+
enum bundle_list_flags *flags)
703712
{
704713
int result;
705714
struct bundle_list list;
@@ -719,6 +728,8 @@ int fetch_bundle_uri(struct repository *r, const char *uri)
719728
result = unbundle_all_bundles(r, &list);
720729

721730
cleanup:
731+
if (flags)
732+
*flags = list.flags;
722733
for_all_bundles_in_list(&list, unlink_bundle, NULL);
723734
clear_bundle_list(&list);
724735
clear_remote_bundle_info(&bundle, NULL);

bundle-uri.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ enum bundle_list_heuristic {
6666
BUNDLE_HEURISTIC_COUNT,
6767
};
6868

69+
enum bundle_list_flags {
70+
BUNDLE_FLAG_FOR_FETCH = (1 << 0),
71+
};
72+
6973
/**
7074
* A bundle_list contains an unordered set of remote_bundle_info structs,
7175
* as well as information about the bundle listing, such as version and
@@ -74,6 +78,7 @@ enum bundle_list_heuristic {
7478
struct bundle_list {
7579
int version;
7680
enum bundle_list_mode mode;
81+
enum bundle_list_flags flags;
7782
struct hashmap bundles;
7883

7984
/**
@@ -119,8 +124,12 @@ int bundle_uri_parse_config_format(const char *uri,
119124
* based on that information.
120125
*
121126
* Returns non-zero if no bundle information is found at the given 'uri'.
127+
*
128+
* The enum at 'flags' (if non-NULL) is populated with the flags found at
129+
* the bundle URI.
122130
*/
123-
int fetch_bundle_uri(struct repository *r, const char *uri);
131+
int fetch_bundle_uri(struct repository *r, const char *uri,
132+
enum bundle_list_flags *flags);
124133

125134
/**
126135
* Given a bundle list that was already advertised (likely by the

t/t5558-clone-bundle-uri.sh

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,89 @@ test_expect_success 'clone bundle list (file, creationToken)' '
137137
done
138138
'
139139

140+
test_expect_success 'clone with bundle.flag=forFetch creates fetch.bundleURI' '
141+
test_when_finished rm -rf fetch-file-3 trace1.txt trace2.txt &&
142+
cat >bundle-list <<-EOF &&
143+
[bundle]
144+
version = 1
145+
mode = all
146+
heuristic = creationToken
147+
flag = forFetch
148+
149+
[bundle "bundle-1"]
150+
uri = clone-from/bundle-1.bundle
151+
creationToken = 1
152+
EOF
153+
154+
git clone --no-local --single-branch --branch=base \
155+
--bundle-uri="file://$(pwd)/bundle-list" \
156+
clone-from fetch-file-3 &&
157+
158+
test_cmp_config -C fetch-file-3 "file://$(pwd)/bundle-list" fetch.bundleuri &&
159+
160+
# only received base ref from bundle-1
161+
git -C fetch-file-3 for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
162+
cat >expect <<-\EOF &&
163+
refs/bundles/base
164+
EOF
165+
test_cmp expect refs &&
166+
167+
cat >>bundle-list <<-EOF &&
168+
[bundle "bundle-2"]
169+
uri = clone-from/bundle-2.bundle
170+
creationToken = 2
171+
EOF
172+
173+
GIT_TRACE2_EVENT="$(pwd)/trace1.txt" \
174+
git -C fetch-file-3 fetch origin --no-tags \
175+
refs/heads/left:refs/heads/left &&
176+
177+
# This fetch should copy two files: the list and bundle-2.
178+
grep "region_enter.*bundle-uri.*copy_file" trace1.txt >copies &&
179+
180+
# NEEDSWORK: This should only copy two files, not three.
181+
test_line_count = 3 copies &&
182+
183+
# received left from bundle-2
184+
git -C fetch-file-3 for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
185+
cat >expect <<-\EOF &&
186+
refs/bundles/base
187+
refs/bundles/left
188+
EOF
189+
test_cmp expect refs &&
190+
191+
cat >>bundle-list <<-EOF &&
192+
[bundle "bundle-3"]
193+
uri = clone-from/bundle-3.bundle
194+
creationToken = 3
195+
196+
[bundle "bundle-4"]
197+
uri = clone-from/bundle-4.bundle
198+
creationToken = 4
199+
EOF
200+
201+
GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
202+
git -C fetch-file-3 fetch origin --no-tags \
203+
refs/heads/right:refs/heads/right &&
204+
205+
# This fetch should copy three files: the list, bundle-4, and bundle-3.
206+
grep "region_enter.*bundle-uri.*copy_file" trace2.txt >copies &&
207+
208+
# NEEDSWORK: this is re-downloading all the bundles!
209+
test_line_count = 5 copies &&
210+
211+
# received right and merge from bundle-3 and bundle-4.
212+
git -C fetch-file-3 for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
213+
214+
# NEEDS WORK: why not refs/bundle/merge ???
215+
cat >expect <<-\EOF &&
216+
refs/bundles/base
217+
refs/bundles/left
218+
refs/bundles/right
219+
EOF
220+
test_cmp expect refs
221+
'
222+
140223
#########################################################################
141224
# HTTP tests begin here
142225

@@ -248,6 +331,89 @@ test_expect_success 'fetch bundle list (http, creationToken, incremental)' '
248331
test_cmp expect refs
249332
'
250333

334+
test_expect_success 'http clone with bundle.flag=forFetch creates fetch.bundleURI' '
335+
test_when_finished rm -rf fetch-http-4 trace1.txt trace2.txt &&
336+
cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
337+
[bundle]
338+
version = 1
339+
mode = all
340+
heuristic = creationToken
341+
flag = forFetch
342+
343+
[bundle "bundle-1"]
344+
uri = bundle-1.bundle
345+
creationToken = 1
346+
EOF
347+
348+
git clone --single-branch --branch=base \
349+
--bundle-uri="$HTTPD_URL/bundle-list" \
350+
"$HTTPD_URL/smart/fetch.git" fetch-http-4 &&
351+
352+
test_cmp_config -C fetch-http-4 "$HTTPD_URL/bundle-list" fetch.bundleuri &&
353+
354+
# only received base ref from bundle-1
355+
git -C fetch-http-4 for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
356+
cat >expect <<-\EOF &&
357+
refs/bundles/base
358+
EOF
359+
test_cmp expect refs &&
360+
361+
cat >>"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
362+
[bundle "bundle-2"]
363+
uri = bundle-2.bundle
364+
creationToken = 2
365+
EOF
366+
367+
GIT_TRACE2_EVENT="$(pwd)/trace1.txt" \
368+
git -C fetch-http-4 fetch origin --no-tags \
369+
refs/heads/left:refs/heads/left &&
370+
371+
# This fetch should copy two files: the list and bundle-2.
372+
grep "region_enter.*bundle-uri.*download_https_uri_to_file" trace1.txt >copies &&
373+
374+
# NEEDSWORK: Currently downloading three copies instead of two!
375+
test_line_count = 3 copies &&
376+
377+
# received left from bundle-2
378+
git -C fetch-http-4 for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
379+
cat >expect <<-\EOF &&
380+
refs/bundles/base
381+
refs/bundles/left
382+
EOF
383+
test_cmp expect refs &&
384+
385+
cat >>"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
386+
[bundle "bundle-3"]
387+
uri = bundle-3.bundle
388+
creationToken = 3
389+
390+
[bundle "bundle-4"]
391+
uri = bundle-4.bundle
392+
creationToken = 4
393+
EOF
394+
395+
GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
396+
git -C fetch-http-4 fetch origin --no-tags \
397+
refs/heads/right:refs/heads/right &&
398+
399+
# This fetch should copy three files: the list, bundle-4, and bundle-3.
400+
grep "region_enter.*bundle-uri.*download_https_uri_to_file" trace2.txt >copies &&
401+
402+
# NEEDSWORK: this is re-downloading everything!
403+
test_line_count = 5 copies &&
404+
405+
# received right and merge from bundle-3 and bundle-4.
406+
git -C fetch-http-4 for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
407+
408+
# NEEDSWORK: Why not refs/bundles/merge?
409+
cat >expect <<-\EOF &&
410+
refs/bundles/base
411+
refs/bundles/left
412+
refs/bundles/right
413+
EOF
414+
test_cmp expect refs
415+
'
416+
251417
# Do not add tests here unless they use the HTTP server, as they will
252418
# not run unless the HTTP dependencies exist.
253419

0 commit comments

Comments
 (0)