Skip to content

Commit f8828f9

Browse files
committed
Merge branch 'ps/receive-use-only-advertised'
"git receive-pack" used to use all the local refs as the boundary for checking connectivity of the data "git push" sent, but now it uses only the refs that it advertised to the pusher. In a repository with the .hideRefs configuration, this reduces the resources needed to perform the check. cf. <[email protected]> cf. <[email protected]> * ps/receive-use-only-advertised: receive-pack: only use visible refs for connectivity check rev-parse: add `--exclude-hidden=` option revision: add new parameter to exclude hidden refs revision: introduce struct to handle exclusions revision: move together exclusion-related functions refs: get rid of global list of hidden refs refs: fix memory leak when parsing hideRefs config
2 parents 173fc54 + bcec678 commit f8828f9

15 files changed

+410
-82
lines changed

Documentation/git-rev-parse.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,13 @@ respectively, and they must begin with `refs/` when applied to `--glob`
197197
or `--all`. If a trailing '/{asterisk}' is intended, it must be given
198198
explicitly.
199199

200+
--exclude-hidden=[receive|uploadpack]::
201+
Do not include refs that would be hidden by `git-receive-pack` or
202+
`git-upload-pack` by consulting the appropriate `receive.hideRefs` or
203+
`uploadpack.hideRefs` configuration along with `transfer.hideRefs` (see
204+
linkgit:git-config[1]). This option affects the next pseudo-ref option
205+
`--all` or `--glob` and is cleared after processing them.
206+
200207
--disambiguate=<prefix>::
201208
Show every object whose name begins with the given prefix.
202209
The <prefix> must be at least 4 hexadecimal digits long to

Documentation/rev-list-options.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,13 @@ respectively, and they must begin with `refs/` when applied to `--glob`
195195
or `--all`. If a trailing '/{asterisk}' is intended, it must be given
196196
explicitly.
197197

198+
--exclude-hidden=[receive|uploadpack]::
199+
Do not include refs that would be hidden by `git-receive-pack` or
200+
`git-upload-pack` by consulting the appropriate `receive.hideRefs` or
201+
`uploadpack.hideRefs` configuration along with `transfer.hideRefs` (see
202+
linkgit:git-config[1]). This option affects the next pseudo-ref option
203+
`--all` or `--glob` and is cleared after processing them.
204+
198205
--reflog::
199206
Pretend as if all objects mentioned by reflogs are listed on the
200207
command line as `<commit>`.

builtin/receive-pack.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ static struct object_id push_cert_oid;
8080
static struct signature_check sigcheck;
8181
static const char *push_cert_nonce;
8282
static const char *cert_nonce_seed;
83+
static struct string_list hidden_refs = STRING_LIST_INIT_DUP;
8384

8485
static const char *NONCE_UNSOLICITED = "UNSOLICITED";
8586
static const char *NONCE_BAD = "BAD";
@@ -130,7 +131,7 @@ static enum deny_action parse_deny_action(const char *var, const char *value)
130131

131132
static int receive_pack_config(const char *var, const char *value, void *cb)
132133
{
133-
int status = parse_hide_refs_config(var, value, "receive");
134+
int status = parse_hide_refs_config(var, value, "receive", &hidden_refs);
134135

135136
if (status)
136137
return status;
@@ -296,7 +297,7 @@ static int show_ref_cb(const char *path_full, const struct object_id *oid,
296297
struct oidset *seen = data;
297298
const char *path = strip_namespace(path_full);
298299

299-
if (ref_is_hidden(path, path_full))
300+
if (ref_is_hidden(path, path_full, &hidden_refs))
300301
return 0;
301302

302303
/*
@@ -1794,7 +1795,7 @@ static void reject_updates_to_hidden(struct command *commands)
17941795
strbuf_setlen(&refname_full, prefix_len);
17951796
strbuf_addstr(&refname_full, cmd->ref_name);
17961797

1797-
if (!ref_is_hidden(cmd->ref_name, refname_full.buf))
1798+
if (!ref_is_hidden(cmd->ref_name, refname_full.buf, &hidden_refs))
17981799
continue;
17991800
if (is_null_oid(&cmd->new_oid))
18001801
cmd->error_string = "deny deleting a hidden ref";
@@ -1928,6 +1929,8 @@ static void execute_commands(struct command *commands,
19281929
opt.err_fd = err_fd;
19291930
opt.progress = err_fd && !quiet;
19301931
opt.env = tmp_objdir_env(tmp_objdir);
1932+
opt.exclude_hidden_refs_section = "receive";
1933+
19311934
if (check_connected(iterate_receive_command_list, &data, &opt))
19321935
set_connectivity_errors(commands, si);
19331936

@@ -2591,6 +2594,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
25912594
packet_flush(1);
25922595
oid_array_clear(&shallow);
25932596
oid_array_clear(&ref);
2597+
string_list_clear(&hidden_refs, 0);
25942598
free((void *)push_cert_nonce);
25952599
return 0;
25962600
}

builtin/rev-list.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ static const char rev_list_usage[] =
3838
" --tags\n"
3939
" --remotes\n"
4040
" --stdin\n"
41+
" --exclude-hidden=[receive|uploadpack]\n"
4142
" --quiet\n"
4243
" ordering output:\n"
4344
" --topo-order\n"

builtin/rev-parse.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ static int abbrev_ref_strict;
3939
static int output_sq;
4040

4141
static int stuck_long;
42-
static struct string_list *ref_excludes;
42+
static struct ref_exclusions ref_excludes = REF_EXCLUSIONS_INIT;
4343

4444
/*
4545
* Some arguments are relevant "revision" arguments,
@@ -198,7 +198,7 @@ static int show_default(void)
198198
static int show_reference(const char *refname, const struct object_id *oid,
199199
int flag UNUSED, void *cb_data UNUSED)
200200
{
201-
if (ref_excluded(ref_excludes, refname))
201+
if (ref_excluded(&ref_excludes, refname))
202202
return 0;
203203
show_rev(NORMAL, oid, refname);
204204
return 0;
@@ -585,7 +585,7 @@ static void handle_ref_opt(const char *pattern, const char *prefix)
585585
for_each_glob_ref_in(show_reference, pattern, prefix, NULL);
586586
else
587587
for_each_ref_in(prefix, show_reference, NULL);
588-
clear_ref_exclusion(&ref_excludes);
588+
clear_ref_exclusions(&ref_excludes);
589589
}
590590

591591
enum format_type {
@@ -863,7 +863,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
863863
}
864864
if (!strcmp(arg, "--all")) {
865865
for_each_ref(show_reference, NULL);
866-
clear_ref_exclusion(&ref_excludes);
866+
clear_ref_exclusions(&ref_excludes);
867867
continue;
868868
}
869869
if (skip_prefix(arg, "--disambiguate=", &arg)) {
@@ -876,10 +876,14 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
876876
continue;
877877
}
878878
if (opt_with_value(arg, "--branches", &arg)) {
879+
if (ref_excludes.hidden_refs_configured)
880+
return error(_("--exclude-hidden cannot be used together with --branches"));
879881
handle_ref_opt(arg, "refs/heads/");
880882
continue;
881883
}
882884
if (opt_with_value(arg, "--tags", &arg)) {
885+
if (ref_excludes.hidden_refs_configured)
886+
return error(_("--exclude-hidden cannot be used together with --tags"));
883887
handle_ref_opt(arg, "refs/tags/");
884888
continue;
885889
}
@@ -888,13 +892,19 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
888892
continue;
889893
}
890894
if (opt_with_value(arg, "--remotes", &arg)) {
895+
if (ref_excludes.hidden_refs_configured)
896+
return error(_("--exclude-hidden cannot be used together with --remotes"));
891897
handle_ref_opt(arg, "refs/remotes/");
892898
continue;
893899
}
894900
if (skip_prefix(arg, "--exclude=", &arg)) {
895901
add_ref_exclusion(&ref_excludes, arg);
896902
continue;
897903
}
904+
if (skip_prefix(arg, "--exclude-hidden=", &arg)) {
905+
exclude_hidden_refs(&ref_excludes, arg);
906+
continue;
907+
}
898908
if (!strcmp(arg, "--show-toplevel")) {
899909
const char *work_tree = get_git_work_tree();
900910
if (work_tree)

connected.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
100100
strvec_push(&rev_list.args, "--exclude-promisor-objects");
101101
if (!opt->is_deepening_fetch) {
102102
strvec_push(&rev_list.args, "--not");
103+
if (opt->exclude_hidden_refs_section)
104+
strvec_pushf(&rev_list.args, "--exclude-hidden=%s",
105+
opt->exclude_hidden_refs_section);
103106
strvec_push(&rev_list.args, "--all");
104107
}
105108
strvec_push(&rev_list.args, "--quiet");

connected.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ struct check_connected_options {
4646
* during a fetch.
4747
*/
4848
unsigned is_deepening_fetch : 1;
49+
50+
/*
51+
* If not NULL, use `--exclude-hidden=$section` to exclude all refs
52+
* hidden via the `$section.hideRefs` config from the set of
53+
* already-reachable refs.
54+
*/
55+
const char *exclude_hidden_refs_section;
4956
};
5057

5158
#define CHECK_CONNECTED_INIT { 0 }

ls-refs.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "ls-refs.h"
77
#include "pkt-line.h"
88
#include "config.h"
9+
#include "string-list.h"
910

1011
static int config_read;
1112
static int advertise_unborn;
@@ -73,6 +74,7 @@ struct ls_refs_data {
7374
unsigned symrefs;
7475
struct strvec prefixes;
7576
struct strbuf buf;
77+
struct string_list hidden_refs;
7678
unsigned unborn : 1;
7779
};
7880

@@ -84,7 +86,7 @@ static int send_ref(const char *refname, const struct object_id *oid,
8486

8587
strbuf_reset(&data->buf);
8688

87-
if (ref_is_hidden(refname_nons, refname))
89+
if (ref_is_hidden(refname_nons, refname, &data->hidden_refs))
8890
return 0;
8991

9092
if (!ref_match(&data->prefixes, refname_nons))
@@ -137,14 +139,15 @@ static void send_possibly_unborn_head(struct ls_refs_data *data)
137139
}
138140

139141
static int ls_refs_config(const char *var, const char *value,
140-
void *data UNUSED)
142+
void *cb_data)
141143
{
144+
struct ls_refs_data *data = cb_data;
142145
/*
143146
* We only serve fetches over v2 for now, so respect only "uploadpack"
144147
* config. This may need to eventually be expanded to "receive", but we
145148
* don't yet know how that information will be passed to ls-refs.
146149
*/
147-
return parse_hide_refs_config(var, value, "uploadpack");
150+
return parse_hide_refs_config(var, value, "uploadpack", &data->hidden_refs);
148151
}
149152

150153
int ls_refs(struct repository *r, struct packet_reader *request)
@@ -154,9 +157,10 @@ int ls_refs(struct repository *r, struct packet_reader *request)
154157
memset(&data, 0, sizeof(data));
155158
strvec_init(&data.prefixes);
156159
strbuf_init(&data.buf, 0);
160+
string_list_init_dup(&data.hidden_refs);
157161

158162
ensure_config_read();
159-
git_config(ls_refs_config, NULL);
163+
git_config(ls_refs_config, &data);
160164

161165
while (packet_reader_read(request) == PACKET_READ_NORMAL) {
162166
const char *arg = request->line;
@@ -195,6 +199,7 @@ int ls_refs(struct repository *r, struct packet_reader *request)
195199
packet_fflush(stdout);
196200
strvec_clear(&data.prefixes);
197201
strbuf_release(&data.buf);
202+
string_list_clear(&data.hidden_refs, 0);
198203
return 0;
199204
}
200205

refs.c

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1414,9 +1414,8 @@ char *shorten_unambiguous_ref(const char *refname, int strict)
14141414
refname, strict);
14151415
}
14161416

1417-
static struct string_list *hide_refs;
1418-
1419-
int parse_hide_refs_config(const char *var, const char *value, const char *section)
1417+
int parse_hide_refs_config(const char *var, const char *value, const char *section,
1418+
struct string_list *hide_refs)
14201419
{
14211420
const char *key;
14221421
if (!strcmp("transfer.hiderefs", var) ||
@@ -1431,21 +1430,16 @@ int parse_hide_refs_config(const char *var, const char *value, const char *secti
14311430
len = strlen(ref);
14321431
while (len && ref[len - 1] == '/')
14331432
ref[--len] = '\0';
1434-
if (!hide_refs) {
1435-
CALLOC_ARRAY(hide_refs, 1);
1436-
hide_refs->strdup_strings = 1;
1437-
}
1438-
string_list_append(hide_refs, ref);
1433+
string_list_append_nodup(hide_refs, ref);
14391434
}
14401435
return 0;
14411436
}
14421437

1443-
int ref_is_hidden(const char *refname, const char *refname_full)
1438+
int ref_is_hidden(const char *refname, const char *refname_full,
1439+
const struct string_list *hide_refs)
14441440
{
14451441
int i;
14461442

1447-
if (!hide_refs)
1448-
return 0;
14491443
for (i = hide_refs->nr - 1; i >= 0; i--) {
14501444
const char *match = hide_refs->items[i].string;
14511445
const char *subject;

refs.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,8 @@ int update_ref(const char *msg, const char *refname,
808808
const struct object_id *new_oid, const struct object_id *old_oid,
809809
unsigned int flags, enum action_on_err onerr);
810810

811-
int parse_hide_refs_config(const char *var, const char *value, const char *);
811+
int parse_hide_refs_config(const char *var, const char *value, const char *,
812+
struct string_list *);
812813

813814
/*
814815
* Check whether a ref is hidden. If no namespace is set, both the first and
@@ -818,7 +819,7 @@ int parse_hide_refs_config(const char *var, const char *value, const char *);
818819
* the ref is outside that namespace, the first parameter is NULL. The second
819820
* parameter always points to the full ref name.
820821
*/
821-
int ref_is_hidden(const char *, const char *);
822+
int ref_is_hidden(const char *, const char *, const struct string_list *);
822823

823824
/* Is this a per-worktree ref living in the refs/ namespace? */
824825
int is_per_worktree_ref(const char *refname);

0 commit comments

Comments
 (0)