Skip to content

Commit 082b70b

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 d25661b commit 082b70b

File tree

6 files changed

+209
-5
lines changed

6 files changed

+209
-5
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
@@ -1234,11 +1234,15 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
12341234
* data from the --bundle-uri option.
12351235
*/
12361236
if (bundle_uri) {
1237+
enum bundle_list_flags flags = 0;
1238+
12371239
/* At this point, we need the_repository to match the cloned repo. */
12381240
repo_init(the_repository, git_dir, work_tree);
1239-
if (fetch_bundle_uri(the_repository, bundle_uri))
1241+
if (fetch_bundle_uri(the_repository, bundle_uri, &flags))
12401242
warning(_("failed to fetch objects from bundle URI '%s'"),
12411243
bundle_uri);
1244+
else if (flags & BUNDLE_FLAG_FOR_FETCH)
1245+
git_config_set_gently("fetch.bundleuri", bundle_uri);
12421246
}
12431247

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

builtin/fetch.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2102,11 +2102,15 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
21022102
int cmd_fetch(int argc, const char **argv, const char *prefix)
21032103
{
21042104
int i;
2105+
int bundle_uri_from_config;
21052106
struct string_list list = STRING_LIST_INIT_DUP;
21062107
struct remote *remote = NULL;
21072108
int result = 0;
21082109
int prune_tags_ok = 1;
21092110

2111+
bundle_uri_from_config = !bundle_uri &&
2112+
!git_config_get_string_tmp("fetch.bundleuri", &bundle_uri);
2113+
21102114
packet_trace_identity("fetch");
21112115

21122116
/* Record the command line for the reflog */
@@ -2188,8 +2192,10 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
21882192
write_fetch_head = 0;
21892193

21902194
if (bundle_uri) {
2191-
result = fetch_bundle_uri(the_repository, bundle_uri);
2192-
goto cleanup;
2195+
result = fetch_bundle_uri(the_repository, bundle_uri, NULL);
2196+
2197+
if (!bundle_uri_from_config)
2198+
goto cleanup;
21932199
}
21942200

21952201
if (all) {

bundle-uri.c

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

154+
if (!strcmp(pkey, "flag")) {
155+
if (!strcmp("forFetch", value))
156+
list->flags |= BUNDLE_FLAG_FOR_FETCH;
157+
return 0;
158+
}
159+
154160
if (!strcmp(pkey, "heuristic")) {
155161
int i;
156162
for (i = 0; i < BUNDLE_HEURISTIC_COUNT; i++) {
@@ -560,6 +566,8 @@ static int fetch_bundle_list_in_config_format(struct repository *r,
560566
goto cleanup;
561567

562568
cleanup:
569+
/* Copy results from the local list to the global list. */
570+
global_list->flags |= list_from_bundle.flags;
563571
clear_bundle_list(&list_from_bundle);
564572
return result;
565573
}
@@ -682,7 +690,8 @@ static int unlink_bundle(struct remote_bundle_info *info, void *data)
682690
return 0;
683691
}
684692

685-
int fetch_bundle_uri(struct repository *r, const char *uri)
693+
int fetch_bundle_uri(struct repository *r, const char *uri,
694+
enum bundle_list_flags *flags)
686695
{
687696
int result;
688697
struct bundle_list list;
@@ -703,6 +712,8 @@ int fetch_bundle_uri(struct repository *r, const char *uri)
703712
result = unbundle_all_bundles(r, &list);
704713

705714
cleanup:
715+
if (flags)
716+
*flags = list.flags;
706717
for_all_bundles_in_list(&list, unlink_bundle, NULL);
707718
clear_bundle_list(&list);
708719
clear_remote_bundle_info(&bundle, NULL);

bundle-uri.h

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

71+
enum bundle_list_flags {
72+
BUNDLE_FLAG_FOR_FETCH = (1 << 0),
73+
};
74+
7175
/**
7276
* A bundle_list contains an unordered set of remote_bundle_info structs,
7377
* as well as information about the bundle listing, such as version and
@@ -76,6 +80,7 @@ enum bundle_list_heuristic {
7680
struct bundle_list {
7781
int version;
7882
enum bundle_list_mode mode;
83+
enum bundle_list_flags flags;
7984
struct hashmap bundles;
8085

8186
/**
@@ -122,8 +127,12 @@ int parse_bundle_list_in_config_format(const char *uri,
122127
* based on that information.
123128
*
124129
* Returns non-zero if no bundle information is found at the given 'uri'.
130+
*
131+
* The enum at 'flags' (if non-NULL) is populated with the flags found at
132+
* the bundle URI.
125133
*/
126-
int fetch_bundle_uri(struct repository *r, const char *uri);
134+
int fetch_bundle_uri(struct repository *r, const char *uri,
135+
enum bundle_list_flags *flags);
127136

128137
/**
129138
* Given a bundle list that was already advertised (likely by the

t/t5558-fetch-bundle-uri.sh

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,89 @@ test_expect_success 'fetch bundle list (file, creationToken)' '
161161
done
162162
'
163163

164+
test_expect_success 'clone with bundle.flag=forFetch creates fetch.bundleURI' '
165+
test_when_finished rm -rf fetch-file-3 trace1.txt trace2.txt &&
166+
cat >bundle-list <<-EOF &&
167+
[bundle]
168+
version = 1
169+
mode = all
170+
heuristic = creationToken
171+
flag = forFetch
172+
173+
[bundle "bundle-1"]
174+
uri = fetch-from/bundle-1.bundle
175+
creationToken = 1
176+
EOF
177+
178+
git clone --no-local --single-branch --branch=base \
179+
--bundle-uri="file://$(pwd)/bundle-list" \
180+
fetch-from fetch-file-3 &&
181+
182+
test_cmp_config -C fetch-file-3 "file://$(pwd)/bundle-list" fetch.bundleuri &&
183+
184+
# only received base ref from bundle-1
185+
git -C fetch-file-3 for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
186+
cat >expect <<-\EOF &&
187+
refs/bundles/base
188+
EOF
189+
test_cmp expect refs &&
190+
191+
cat >>bundle-list <<-EOF &&
192+
[bundle "bundle-2"]
193+
uri = fetch-from/bundle-2.bundle
194+
creationToken = 2
195+
EOF
196+
197+
GIT_TRACE2_EVENT="$(pwd)/trace1.txt" \
198+
git -C fetch-file-3 fetch origin --no-tags \
199+
refs/heads/left:refs/heads/left &&
200+
201+
# This fetch should copy two files: the list and bundle-2.
202+
grep "region_enter.*bundle-uri.*copy_file" trace1.txt >copies &&
203+
204+
# NEEDSWORK: This should only copy two files, not three.
205+
test_line_count = 3 copies &&
206+
207+
# received left from bundle-2
208+
git -C fetch-file-3 for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
209+
cat >expect <<-\EOF &&
210+
refs/bundles/base
211+
refs/bundles/left
212+
EOF
213+
test_cmp expect refs &&
214+
215+
cat >>bundle-list <<-EOF &&
216+
[bundle "bundle-3"]
217+
uri = fetch-from/bundle-3.bundle
218+
creationToken = 3
219+
220+
[bundle "bundle-4"]
221+
uri = fetch-from/bundle-4.bundle
222+
creationToken = 4
223+
EOF
224+
225+
GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
226+
git -C fetch-file-3 fetch origin --no-tags \
227+
refs/heads/right:refs/heads/right &&
228+
229+
# This fetch should copy three files: the list, bundle-4, and bundle-3.
230+
grep "region_enter.*bundle-uri.*copy_file" trace2.txt >copies &&
231+
232+
# NEEDSWORK: this is re-downloading all the bundles!
233+
test_line_count = 5 copies &&
234+
235+
# received right and merge from bundle-3 and bundle-4.
236+
git -C fetch-file-3 for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
237+
238+
# NEEDS WORK: why not refs/bundle/merge ???
239+
cat >expect <<-\EOF &&
240+
refs/bundles/base
241+
refs/bundles/left
242+
refs/bundles/right
243+
EOF
244+
test_cmp expect refs
245+
'
246+
164247
#########################################################################
165248
# HTTP tests begin here
166249

@@ -285,6 +368,89 @@ test_expect_success 'fetch bundle list (http, creationToken, incremental)' '
285368
test_cmp expect refs
286369
'
287370

371+
test_expect_success 'http clone with bundle.flag=forFetch creates fetch.bundleURI' '
372+
test_when_finished rm -rf fetch-http-4 trace1.txt trace2.txt &&
373+
cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
374+
[bundle]
375+
version = 1
376+
mode = all
377+
heuristic = creationToken
378+
flag = forFetch
379+
380+
[bundle "bundle-1"]
381+
uri = bundle-1.bundle
382+
creationToken = 1
383+
EOF
384+
385+
git clone --single-branch --branch=base \
386+
--bundle-uri="$HTTPD_URL/bundle-list" \
387+
"$HTTPD_URL/smart/fetch.git" fetch-http-4 &&
388+
389+
test_cmp_config -C fetch-http-4 "$HTTPD_URL/bundle-list" fetch.bundleuri &&
390+
391+
# only received base ref from bundle-1
392+
git -C fetch-http-4 for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
393+
cat >expect <<-\EOF &&
394+
refs/bundles/base
395+
EOF
396+
test_cmp expect refs &&
397+
398+
cat >>"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
399+
[bundle "bundle-2"]
400+
uri = bundle-2.bundle
401+
creationToken = 2
402+
EOF
403+
404+
GIT_TRACE2_EVENT="$(pwd)/trace1.txt" \
405+
git -C fetch-http-4 fetch origin --no-tags \
406+
refs/heads/left:refs/heads/left &&
407+
408+
# This fetch should copy two files: the list and bundle-2.
409+
grep "region_enter.*bundle-uri.*download_https_uri_to_file" trace1.txt >copies &&
410+
411+
# NEEDSWORK: Currently downloading three copies instead of two!
412+
test_line_count = 3 copies &&
413+
414+
# received left from bundle-2
415+
git -C fetch-http-4 for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
416+
cat >expect <<-\EOF &&
417+
refs/bundles/base
418+
refs/bundles/left
419+
EOF
420+
test_cmp expect refs &&
421+
422+
cat >>"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
423+
[bundle "bundle-3"]
424+
uri = bundle-3.bundle
425+
creationToken = 3
426+
427+
[bundle "bundle-4"]
428+
uri = bundle-4.bundle
429+
creationToken = 4
430+
EOF
431+
432+
GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
433+
git -C fetch-http-4 fetch origin --no-tags \
434+
refs/heads/right:refs/heads/right &&
435+
436+
# This fetch should copy three files: the list, bundle-4, and bundle-3.
437+
grep "region_enter.*bundle-uri.*download_https_uri_to_file" trace2.txt >copies &&
438+
439+
# NEEDSWORK: this is re-downloading everything!
440+
test_line_count = 5 copies &&
441+
442+
# received right and merge from bundle-3 and bundle-4.
443+
git -C fetch-http-4 for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
444+
445+
# NEEDSWORK: Why not refs/bundles/merge?
446+
cat >expect <<-\EOF &&
447+
refs/bundles/base
448+
refs/bundles/left
449+
refs/bundles/right
450+
EOF
451+
test_cmp expect refs
452+
'
453+
288454
# Do not add tests here unless they use the HTTP server, as they will
289455
# not run unless the HTTP dependencies exist.
290456

0 commit comments

Comments
 (0)