Skip to content

Commit ec346b2

Browse files
committed
send-pack: pass --must-have for push negotiation
When push.negotiate is enabled, send-pack spawns a 'git fetch --negotiate-only' subprocess to discover common commits. Previously this subprocess had no way to include must-have refs in the negotiation. Add a must_have field to send_pack_args, set it from the transport layer where the remote struct is available, and pass explicit --must-have arguments to the negotiation subprocess. This approach directly passes the resolved config values rather than relying on the subprocess to read remote config, which is more robust when the URL alone is used as the remote identifier. Signed-off-by: Derrick Stolee <stolee@gmail.com>
1 parent 44d026d commit ec346b2

File tree

4 files changed

+28
-1
lines changed

4 files changed

+28
-1
lines changed

send-pack.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,7 @@ static void reject_invalid_nonce(const char *nonce, int len)
433433

434434
static void get_commons_through_negotiation(struct repository *r,
435435
const char *url,
436+
const struct string_list *must_have,
436437
const struct ref *remote_refs,
437438
struct oid_array *commons)
438439
{
@@ -452,6 +453,14 @@ static void get_commons_through_negotiation(struct repository *r,
452453
nr_negotiation_tip++;
453454
}
454455
}
456+
457+
if (must_have) {
458+
struct string_list_item *item;
459+
for_each_string_list_item(item, must_have)
460+
strvec_pushf(&child.args, "--must-have=%s",
461+
item->string);
462+
}
463+
455464
strvec_push(&child.args, url);
456465

457466
if (!nr_negotiation_tip) {
@@ -528,7 +537,8 @@ int send_pack(struct repository *r,
528537
repo_config_get_bool(r, "push.negotiate", &push_negotiate);
529538
if (push_negotiate) {
530539
trace2_region_enter("send_pack", "push_negotiate", r);
531-
get_commons_through_negotiation(r, args->url, remote_refs, &commons);
540+
get_commons_through_negotiation(r, args->url, args->must_have,
541+
remote_refs, &commons);
532542
trace2_region_leave("send_pack", "push_negotiate", r);
533543
}
534544

send-pack.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ struct repository;
1818

1919
struct send_pack_args {
2020
const char *url;
21+
const struct string_list *must_have;
2122
unsigned verbose:1,
2223
quiet:1,
2324
porcelain:1,

t/t5516-fetch-push.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,21 @@ test_expect_success 'push with negotiation does not attempt to fetch submodules'
254254
! grep "Fetching submodule" err
255255
'
256256

257+
test_expect_success 'push with negotiation and remote.<name>.mustHave' '
258+
test_when_finished rm -rf musthave &&
259+
mk_empty musthave &&
260+
git push musthave $the_first_commit:refs/remotes/origin/first_commit &&
261+
test_commit -C musthave unrelated_commit &&
262+
git -C musthave config receive.hideRefs refs/remotes/origin/first_commit &&
263+
test_when_finished "rm event" &&
264+
GIT_TRACE2_EVENT="$(pwd)/event" \
265+
git -c protocol.version=2 -c push.negotiate=1 \
266+
-c remote.musthave.mustHave=refs/heads/main \
267+
push musthave refs/heads/main:refs/remotes/origin/main &&
268+
test_grep \"key\":\"total_rounds\" event &&
269+
grep_wrote 2 event # 1 commit, 1 tree
270+
'
271+
257272
test_expect_success 'push without wildcard' '
258273
mk_empty testrepo &&
259274

transport.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
921921
args.atomic = !!(flags & TRANSPORT_PUSH_ATOMIC);
922922
args.push_options = transport->push_options;
923923
args.url = transport->url;
924+
args.must_have = &transport->remote->must_have;
924925

925926
if (flags & TRANSPORT_PUSH_CERT_ALWAYS)
926927
args.push_cert = SEND_PACK_PUSH_CERT_ALWAYS;

0 commit comments

Comments
 (0)