fetch: add --negotiation-include option for negotiation

Add a new --negotiation-include option to 'git fetch', which ensures that certain ref tips are always sent as 'have' lines during fetch negotiation, regardless of what the negotiation algorithm selects. This is useful when the repository has a large number of references, so the normal negotiation algorithm truncates the list. This is especially important in repositories with long parallel commit histories. For example, a repo could have a 'dev' branch for development and a 'release' branch for released versions. If the 'dev' branch isn't selected for negotiation, then it's not a big deal because there are many in-progress development branches with a shared history. However, if 'release' is not selected for negotiation, then the server may think that this is the first time the client has asked for that reference, causing a full download of its parallel commit history (and any extra data that may be unique to that branch). This is based on a real example where certain fetches would grow to 60+ GB when a release branch updated. This option is a complement to --negotiation-restrict, which reduces the negotiation ref set to a specific list. In the earlier example, using --negotiation-restrict to focus the negotiation to 'dev' and 'release' would avoid those problematic downloads, but would still not allow advertising potentially-relevant user branches. In this way, the 'include' version solves the problem I mention while allowing negotiation to pick other references opportunistically. The two options can also be combined to allow the best of both worlds. The argument may be an exact ref name or a glob pattern. Non-existent refs are silently ignored. This behavior is also updated in the ref matching logic for the related --negotiation-restrict option to match. The implementation outputs the requested objects as haves before the negotiator performs its own algorithm to choose the next haves. Use the new have_sent() interface to signal these have commits were sent before engaging with the negotiator's next() iterator. Also add --negotiation-include to 'git pull' passthrough options. Reviewed-by: Matthew John Cheetham <mjcheetham@outlook.com> Signed-off-by: Derrick Stolee <stolee@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed May 19, 2026 at 16:24 UTC e2164742c9ceb60ac9ddd2114f49304fd73df1f3
8 files changed +232 -19
Documentation/fetch-options.adoc
+19
@@ -73,6 +73,25 @@ See also the `fetch.negotiationAlgorithm` and `push.negotiate`
73 configuration variables documented in linkgit:git-config[1], and the
74 `--negotiate-only` option below.
75
76 +`--negotiation-include=(<commit>|<glob>)`::
77 + Ensure that the commits at the given tips are always sent as "have"
78 + lines during fetch negotiation, regardless of what the negotiation
79 + algorithm selects. This is useful to guarantee that common
80 + history reachable from specific refs is always considered, even
81 + when `--negotiation-restrict` restricts the set of tips or when
82 + the negotiation algorithm would otherwise skip them.
83 ++
84 +This option may be specified more than once; if so, each commit is sent
85 +unconditionally.
86 ++
87 +The argument may be an exact ref name (e.g. `refs/heads/release`), an
88 +object hash, or a glob pattern (e.g. `refs/heads/release/{asterisk}`).
89 +The pattern syntax is the same as for `--negotiation-restrict`.
90 ++
91 +If `--negotiation-restrict` is used, the have set is first restricted by
92 +that option and then increased to include the tips specified by
93 +`--negotiation-include`.
94 +
95 `--negotiate-only`::
96 Do not fetch anything from the server, and instead print the
97 ancestors of the provided `--negotiation-restrict=` arguments,
builtin/fetch.c
+30 -8
@@ -99,6 +99,7 @@ static struct transport *gsecondary;
99 static struct refspec refmap = REFSPEC_INIT_FETCH;
100 static struct string_list server_options = STRING_LIST_INIT_DUP;
101 static struct string_list negotiation_restrict = STRING_LIST_INIT_NODUP;
102 +static struct string_list negotiation_include = STRING_LIST_INIT_NODUP;
103
104 struct fetch_config {
105 enum display_format display_format;
@@ -1534,23 +1535,29 @@ static int add_oid(const struct reference *ref, void *cb_data)
1535 return 0;
1536 }
1537
1537 -static void add_negotiation_restrict_tips(struct git_transport_options *smart_options)
1538 +static void add_negotiation_tips(struct string_list *input_list,
1539 + struct oid_array **output_list,
1540 + const char *argname)
1541 {
1542 struct oid_array *oids = xcalloc(1, sizeof(*oids));
1543 int i;
1544
1542 - for (i = 0; i < negotiation_restrict.nr; i++) {
1543 - const char *s = negotiation_restrict.items[i].string;
1545 + for (i = 0; i < input_list->nr; i++) {
1546 + const char *s = input_list->items[i].string;
1547 struct refs_for_each_ref_options opts = {
1548 .pattern = s,
1549 };
1550 int old_nr;
1551 if (!has_glob_specials(s)) {
1552 struct object_id oid;
1553 +
1554 + /* Ignore missing reference. */
1555 if (repo_get_oid(the_repository, s, &oid))
1551 - die(_("%s is not a valid object"), s);
1556 + continue;
1557 + /* Fail on missing object pointed by ref. */
1558 if (!odb_has_object(the_repository->objects, &oid, 0))
1559 die(_("the object %s does not exist"), s);
1560 +
1561 oid_array_append(oids, &oid);
1562 continue;
1563 }
@@ -1559,9 +1566,9 @@ static void add_negotiation_restrict_tips(struct git_transport_options *smart_op
1566 add_oid, oids, &opts);
1567 if (old_nr == oids->nr)
1568 warning(_("ignoring %s=%s because it does not match any refs"),
1562 - "--negotiation-restrict", s);
1569 + argname, s);
1570 }
1564 - smart_options->negotiation_restrict_tips = oids;
1571 + *output_list = oids;
1572 }
1573
1574 static struct transport *prepare_transport(struct remote *remote, int deepen,
@@ -1597,7 +1604,9 @@ static struct transport *prepare_transport(struct remote *remote, int deepen,
1604 }
1605 if (negotiation_restrict.nr) {
1606 if (transport->smart_options)
1600 - add_negotiation_restrict_tips(transport->smart_options);
1607 + add_negotiation_tips(&negotiation_restrict,
1608 + &transport->smart_options->negotiation_restrict_tips,
1609 + "--negotiation-restrict");
1610 else
1611 warning(_("ignoring %s because the protocol does not support it"),
1612 "--negotiation-restrict");
@@ -1606,7 +1615,9 @@ static struct transport *prepare_transport(struct remote *remote, int deepen,
1615 for_each_string_list_item(item, &remote->negotiation_restrict)
1616 string_list_append(&negotiation_restrict, item->string);
1617 if (transport->smart_options)
1609 - add_negotiation_restrict_tips(transport->smart_options);
1618 + add_negotiation_tips(&negotiation_restrict,
1619 + &transport->smart_options->negotiation_restrict_tips,
1620 + "--negotiation-restrict");
1621 else {
1622 struct strbuf config_name = STRBUF_INIT;
1623 strbuf_addf(&config_name, "remote.%s.negotiationRestrict", remote->name);
@@ -1615,6 +1626,15 @@ static struct transport *prepare_transport(struct remote *remote, int deepen,
1626 strbuf_release(&config_name);
1627 }
1628 }
1629 + if (negotiation_include.nr) {
1630 + if (transport->smart_options)
1631 + add_negotiation_tips(&negotiation_include,
1632 + &transport->smart_options->negotiation_include_tips,
1633 + "--negotiation-include");
1634 + else
1635 + warning(_("ignoring %s because the protocol does not support it"),
1636 + "--negotiation-include");
1637 + }
1638 return transport;
1639 }
1640
@@ -2582,6 +2602,8 @@ int cmd_fetch(int argc,
2602 OPT_STRING_LIST(0, "negotiation-restrict", &negotiation_restrict, N_("revision"),
2603 N_("report that we have only objects reachable from this object")),
2604 OPT_ALIAS(0, "negotiation-tip", "negotiation-restrict"),
2605 + OPT_STRING_LIST(0, "negotiation-include", &negotiation_include, N_("revision"),
2606 + N_("ensure this ref is always sent as a negotiation have")),
2607 OPT_BOOL(0, "negotiate-only", &negotiate_only,
2608 N_("do not fetch a packfile; instead, print ancestors of negotiation tips")),
2609 OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
builtin/pull.c
+3
@@ -1000,6 +1000,9 @@ int cmd_pull(int argc,
1000 N_("report that we have only objects reachable from this object"),
1001 0),
1002 OPT_ALIAS(0, "negotiation-tip", "negotiation-restrict"),
1003 + OPT_PASSTHRU_ARGV(0, "negotiation-include", &opt_fetch, N_("revision"),
1004 + N_("ensure this ref is always sent as a negotiation have"),
1005 + 0),
1006 OPT_BOOL(0, "show-forced-updates", &opt_show_forced_updates,
1007 N_("check for forced-updates on all updated branches")),
1008 OPT_PASSTHRU(0, "set-upstream", &set_upstream, NULL,
fetch-pack.c
+75 -6
@@ -25,6 +25,7 @@
25 #include "oidset.h"
26 #include "packfile.h"
27 #include "odb.h"
28 +#include "object-name.h"
29 #include "path.h"
30 #include "connected.h"
31 #include "fetch-negotiator.h"
@@ -332,6 +333,21 @@ static void send_filter(struct fetch_pack_args *args,
333 }
334 }
335
336 +static void add_oids_to_set(const struct oid_array *array,
337 + struct oidset *set)
338 +{
339 + if (!array)
340 + return;
341 +
342 + for (size_t i = 0; i < array->nr; i++) {
343 + struct object_id *oid = &array->oid[i];
344 + if (!odb_has_object(the_repository->objects, oid, 0))
345 + die(_("the object %s does not exist"), oid_to_hex(oid));
346 +
347 + oidset_insert(set, oid);
348 + }
349 +}
350 +
351 static int find_common(struct fetch_negotiator *negotiator,
352 struct fetch_pack_args *args,
353 int fd[2], struct object_id *result_oid,
@@ -347,6 +363,7 @@ static int find_common(struct fetch_negotiator *negotiator,
363 struct strbuf req_buf = STRBUF_INIT;
364 size_t state_len = 0;
365 struct packet_reader reader;
366 + struct oidset negotiation_include_oids = OIDSET_INIT;
367
368 if (args->stateless_rpc && multi_ack == 1)
369 die(_("the option '%s' requires '%s'"), "--stateless-rpc", "multi_ack_detailed");
@@ -474,6 +491,27 @@ static int find_common(struct fetch_negotiator *negotiator,
491 trace2_region_enter("fetch-pack", "negotiation_v0_v1", the_repository);
492 flushes = 0;
493 retval = -1;
494 +
495 + /* Send unconditional haves from --negotiation-include */
496 + add_oids_to_set(args->negotiation_include_tips,
497 + &negotiation_include_oids);
498 + if (oidset_size(&negotiation_include_oids)) {
499 + struct oidset_iter iter;
500 + oidset_iter_init(&negotiation_include_oids, &iter);
501 +
502 + while ((oid = oidset_iter_next(&iter))) {
503 + struct commit *commit;
504 + packet_buf_write(&req_buf, "have %s\n",
505 + oid_to_hex(oid));
506 + print_verbose(args, "have %s", oid_to_hex(oid));
507 + count++;
508 +
509 + commit = lookup_commit(the_repository, oid);
510 + if (commit)
511 + negotiator->have_sent(negotiator, commit);
512 + }
513 + }
514 +
515 while ((oid = negotiator->next(negotiator))) {
516 packet_buf_write(&req_buf, "have %s\n", oid_to_hex(oid));
517 print_verbose(args, "have %s", oid_to_hex(oid));
@@ -584,6 +622,7 @@ done:
622 flushes++;
623 }
624 strbuf_release(&req_buf);
625 + oidset_clear(&negotiation_include_oids);
626
627 if (!got_ready || !no_done)
628 consume_shallow_list(args, &reader);
@@ -1305,11 +1344,27 @@ static void add_common(struct strbuf *req_buf, struct oidset *common)
1344
1345 static int add_haves(struct fetch_negotiator *negotiator,
1346 struct strbuf *req_buf,
1308 - int *haves_to_send)
1347 + int *haves_to_send,
1348 + struct oidset *negotiation_include_oids)
1349 {
1350 int haves_added = 0;
1351 const struct object_id *oid;
1352
1353 + /* Send unconditional haves from --negotiation-include */
1354 + if (negotiation_include_oids) {
1355 + struct oidset_iter iter;
1356 + oidset_iter_init(negotiation_include_oids, &iter);
1357 +
1358 + while ((oid = oidset_iter_next(&iter))) {
1359 + struct commit *commit = lookup_commit(the_repository, oid);
1360 + if (commit) {
1361 + packet_buf_write(req_buf, "have %s\n",
1362 + oid_to_hex(oid));
1363 + negotiator->have_sent(negotiator, commit);
1364 + }
1365 + }
1366 + }
1367 +
1368 while ((oid = negotiator->next(negotiator))) {
1369 packet_buf_write(req_buf, "have %s\n", oid_to_hex(oid));
1370 if (++haves_added >= *haves_to_send)
@@ -1358,7 +1413,8 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
1413 struct fetch_pack_args *args,
1414 const struct ref *wants, struct oidset *common,
1415 int *haves_to_send, int *in_vain,
1361 - int sideband_all, int seen_ack)
1416 + int sideband_all, int seen_ack,
1417 + struct oidset *negotiation_include_oids)
1418 {
1419 int haves_added;
1420 int done_sent = 0;
@@ -1413,7 +1469,8 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
1469 /* Add all of the common commits we've found in previous rounds */
1470 add_common(&req_buf, common);
1471
1416 - haves_added = add_haves(negotiator, &req_buf, haves_to_send);
1472 + haves_added = add_haves(negotiator, &req_buf, haves_to_send,
1473 + negotiation_include_oids);
1474 *in_vain += haves_added;
1475 trace2_data_intmax("negotiation_v2", the_repository, "haves_added", haves_added);
1476 trace2_data_intmax("negotiation_v2", the_repository, "in_vain", *in_vain);
@@ -1657,6 +1714,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
1714 struct ref *ref = copy_ref_list(orig_ref);
1715 enum fetch_state state = FETCH_CHECK_LOCAL;
1716 struct oidset common = OIDSET_INIT;
1717 + struct oidset negotiation_include_oids = OIDSET_INIT;
1718 struct packet_reader reader;
1719 int in_vain = 0, negotiation_started = 0;
1720 int negotiation_round = 0;
@@ -1729,6 +1787,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
1787 state = FETCH_SEND_REQUEST;
1788
1789 mark_tips(negotiator, args->negotiation_restrict_tips);
1790 + add_oids_to_set(args->negotiation_include_tips,
1791 + &negotiation_include_oids);
1792 for_each_cached_alternate(negotiator,
1793 insert_one_alternate_object);
1794 break;
@@ -1747,7 +1807,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
1807 &common,
1808 &haves_to_send, &in_vain,
1809 reader.use_sideband,
1750 - seen_ack)) {
1810 + seen_ack,
1811 + &negotiation_include_oids)) {
1812 trace2_region_leave_printf("negotiation_v2", "round",
1813 the_repository, "%d",
1814 negotiation_round);
@@ -1883,6 +1944,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
1944 negotiator->release(negotiator);
1945
1946 oidset_clear(&common);
1947 + oidset_clear(&negotiation_include_oids);
1948 return ref;
1949 }
1950
@@ -2181,12 +2243,14 @@ void negotiate_using_fetch(const struct oid_array *negotiation_restrict_tips,
2243 const struct string_list *server_options,
2244 int stateless_rpc,
2245 int fd[],
2184 - struct oidset *acked_commits)
2246 + struct oidset *acked_commits,
2247 + const struct oid_array *negotiation_include_tips)
2248 {
2249 struct fetch_negotiator negotiator;
2250 struct packet_reader reader;
2251 struct object_array nt_object_array = OBJECT_ARRAY_INIT;
2252 struct strbuf req_buf = STRBUF_INIT;
2253 + struct oidset negotiation_include_oids = OIDSET_INIT;
2254 int haves_to_send = INITIAL_FLUSH;
2255 int in_vain = 0;
2256 int seen_ack = 0;
@@ -2197,6 +2261,9 @@ void negotiate_using_fetch(const struct oid_array *negotiation_restrict_tips,
2261 fetch_negotiator_init(the_repository, &negotiator);
2262 mark_tips(&negotiator, negotiation_restrict_tips);
2263
2264 + add_oids_to_set(negotiation_include_tips,
2265 + &negotiation_include_oids);
2266 +
2267 packet_reader_init(&reader, fd[0], NULL, 0,
2268 PACKET_READ_CHOMP_NEWLINE |
2269 PACKET_READ_DIE_ON_ERR_PACKET);
@@ -2221,7 +2288,8 @@ void negotiate_using_fetch(const struct oid_array *negotiation_restrict_tips,
2288
2289 packet_buf_write(&req_buf, "wait-for-done");
2290
2224 - haves_added = add_haves(&negotiator, &req_buf, &haves_to_send);
2291 + haves_added = add_haves(&negotiator, &req_buf, &haves_to_send,
2292 + &negotiation_include_oids);
2293 in_vain += haves_added;
2294 if (!haves_added || (seen_ack && in_vain >= MAX_IN_VAIN))
2295 last_iteration = 1;
@@ -2273,6 +2341,7 @@ void negotiate_using_fetch(const struct oid_array *negotiation_restrict_tips,
2341
2342 clear_common_flag(acked_commits);
2343 object_array_clear(&nt_object_array);
2344 + oidset_clear(&negotiation_include_oids);
2345 negotiator.release(&negotiator);
2346 strbuf_release(&req_buf);
2347 }
fetch-pack.h
+4 -2
@@ -19,9 +19,10 @@ struct fetch_pack_args {
19
20 /*
21 * If not NULL, during packfile negotiation, fetch-pack will send "have"
22 - * lines only with these tips and their ancestors.
22 + * lines for all _include_ tips and then a subset of the _restrict_ tips.
23 */
24 const struct oid_array *negotiation_restrict_tips;
25 + const struct oid_array *negotiation_include_tips;
26
27 unsigned deepen_relative:1;
28 unsigned quiet:1;
@@ -93,7 +94,8 @@ void negotiate_using_fetch(const struct oid_array *negotiation_restrict_tips,
94 const struct string_list *server_options,
95 int stateless_rpc,
96 int fd[],
96 - struct oidset *acked_commits);
97 + struct oidset *acked_commits,
98 + const struct oid_array *negotiation_include_tips);
99
100 /*
101 * Print an appropriate error message for each sought ref that wasn't
t/t5510-fetch.sh
+91
@@ -1460,6 +1460,16 @@ EOF
1460 test_cmp fatal-expect fatal-actual
1461 '
1462
1463 +test_expect_success '--negotiation-tip ignores missing refs and invalid hashes' '
1464 + setup_negotiation_tip server server 0 &&
1465 + GIT_TRACE_PACKET="$(pwd)/trace" git -C client fetch \
1466 + --negotiation-tip=alpha_1 --negotiation-tip=beta_1 \
1467 + --negotiation-tip=no-such-ref \
1468 + --negotiation-tip=invalid-hash \
1469 + origin alpha_s beta_s &&
1470 + check_negotiation_tip
1471 +'
1472 +
1473 test_expect_success '--negotiation-restrict limits "have" lines sent' '
1474 setup_negotiation_tip server server 0 &&
1475 GIT_TRACE_PACKET="$(pwd)/trace" git -C client fetch \
@@ -1511,6 +1521,87 @@ test_expect_success 'CLI --negotiation-restrict overrides remote config' '
1521 test_grep ! "fetch> have $BETA_1" trace
1522 '
1523
1524 +test_expect_success '--negotiation-include includes configured refs as haves' '
1525 + test_when_finished rm -f trace &&
1526 + setup_negotiation_tip server server 0 &&
1527 +
1528 + GIT_TRACE_PACKET="$(pwd)/trace" git -C client fetch \
1529 + --negotiation-restrict=alpha_1 \
1530 + --negotiation-include=refs/tags/beta_1 \
1531 + origin alpha_s beta_s &&
1532 +
1533 + ALPHA_1=$(git -C client rev-parse alpha_1) &&
1534 + test_grep "fetch> have $ALPHA_1" trace &&
1535 + BETA_1=$(git -C client rev-parse beta_1) &&
1536 + test_grep "fetch> have $BETA_1" trace
1537 +'
1538 +
1539 +test_expect_success '--negotiation-include works with glob patterns' '
1540 + test_when_finished rm -f trace &&
1541 + setup_negotiation_tip server server 0 &&
1542 +
1543 + GIT_TRACE_PACKET="$(pwd)/trace" git -C client fetch \
1544 + --negotiation-restrict=alpha_1 \
1545 + --negotiation-include="refs/tags/beta_*" \
1546 + origin alpha_s beta_s &&
1547 +
1548 + BETA_1=$(git -C client rev-parse beta_1) &&
1549 + test_grep "fetch> have $BETA_1" trace &&
1550 + BETA_2=$(git -C client rev-parse beta_2) &&
1551 + test_grep "fetch> have $BETA_2" trace
1552 +'
1553 +
1554 +test_expect_success '--negotiation-include is additive with negotiation' '
1555 + test_when_finished rm -f trace &&
1556 + setup_negotiation_tip server server 0 &&
1557 +
1558 + GIT_TRACE_PACKET="$(pwd)/trace" git -C client fetch \
1559 + --negotiation-include=refs/tags/beta_1 \
1560 + origin alpha_s beta_s &&
1561 +
1562 + BETA_1=$(git -C client rev-parse beta_1) &&
1563 + test_grep "fetch> have $BETA_1" trace
1564 +'
1565 +
1566 +test_expect_success '--negotiation-include ignores non-existent refs silently' '
1567 + setup_negotiation_tip server server 0 &&
1568 +
1569 + git -C client fetch --quiet \
1570 + --negotiation-restrict=alpha_1 \
1571 + --negotiation-include=refs/tags/nonexistent \
1572 + origin alpha_s beta_s 2>err &&
1573 + test_must_be_empty err
1574 +'
1575 +
1576 +test_expect_success '--negotiation-include avoids duplicates with negotiator' '
1577 + test_when_finished rm -f trace &&
1578 + setup_negotiation_tip server server 0 &&
1579 +
1580 + ALPHA_1=$(git -C client rev-parse alpha_1) &&
1581 + GIT_TRACE_PACKET="$(pwd)/trace" git -C client fetch \
1582 + --negotiation-restrict=alpha_1 \
1583 + --negotiation-include=refs/tags/alpha_1 \
1584 + origin alpha_s beta_s &&
1585 +
1586 + test_grep "fetch> have $ALPHA_1" trace >matches &&
1587 + test_line_count = 1 matches
1588 +'
1589 +
1590 +test_expect_success '--negotiation-include avoids duplicates with v0' '
1591 + test_when_finished rm -f trace &&
1592 + setup_negotiation_tip server server 0 &&
1593 +
1594 + ALPHA_1=$(git -C client rev-parse alpha_1) &&
1595 + GIT_TRACE_PACKET="$(pwd)/trace" git -C client \
1596 + -c protocol.version=0 fetch \
1597 + --negotiation-restrict=alpha_1 \
1598 + --negotiation-include=refs/tags/alpha_1 \
1599 + origin alpha_s beta_s &&
1600 +
1601 + test_grep "fetch> have $ALPHA_1" trace >matches &&
1602 + test_line_count = 1 matches
1603 +'
1604 +
1605 test_expect_success SYMLINKS 'clone does not get confused by a D/F conflict' '
1606 git init df-conflict &&
1607 (
transport.c
+7 -1
@@ -464,6 +464,7 @@ static int fetch_refs_via_pack(struct transport *transport,
464 args.stateless_rpc = transport->stateless_rpc;
465 args.server_options = transport->server_options;
466 args.negotiation_restrict_tips = data->options.negotiation_restrict_tips;
467 + args.negotiation_include_tips = data->options.negotiation_include_tips;
468 args.reject_shallow_remote = transport->smart_options->reject_shallow;
469
470 if (!data->finished_handshake) {
@@ -495,7 +496,8 @@ static int fetch_refs_via_pack(struct transport *transport,
496 transport->server_options,
497 transport->stateless_rpc,
498 data->fd,
498 - data->options.acked_commits);
499 + data->options.acked_commits,
500 + data->options.negotiation_include_tips);
501 ret = 0;
502 }
503 goto cleanup;
@@ -983,6 +985,10 @@ static int disconnect_git(struct transport *transport)
985 oid_array_clear(data->options.negotiation_restrict_tips);
986 free(data->options.negotiation_restrict_tips);
987 }
988 + if (data->options.negotiation_include_tips) {
989 + oid_array_clear(data->options.negotiation_include_tips);
990 + free(data->options.negotiation_include_tips);
991 + }
992 list_objects_filter_release(&data->options.filter_options);
993 oid_array_clear(&data->extra_have);
994 oid_array_clear(&data->shallow);
transport.h
+3 -2
@@ -40,13 +40,14 @@ struct git_transport_options {
40
41 /*
42 * This is only used during fetch. See the documentation of
43 - * negotiation_restrict_tips in struct fetch_pack_args.
43 + * these member names in struct fetch_pack_args.
44 *
45 - * This field is only supported by transports that support connect or
45 + * These fields are only supported by transports that support connect or
46 * stateless_connect. Set this field directly instead of using
47 * transport_set_option().
48 */
49 struct oid_array *negotiation_restrict_tips;
50 + struct oid_array *negotiation_include_tips;
51
52 /*
53 * If allocated, whenever transport_fetch_refs() is called, add known