Skip to content

Commit 78a766a

Browse files
lfosgitster
authored andcommitted
hideRefs: add support for matching full refs
In addition to matching stripped refs, one can now add hideRefs patterns that the full (unstripped) ref is matched against. To distinguish between stripped and full matches, those new patterns must be prefixed with a circumflex (^). This commit also removes support for the undocumented and unintended hideRefs settings ".have" (suppressing all "have" lines) and "capabilities^{}" (suppressing the capabilities line). Signed-off-by: Lukas Fleischer <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 00b293e commit 78a766a

File tree

5 files changed

+52
-16
lines changed

5 files changed

+52
-16
lines changed

Documentation/config.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2680,7 +2680,8 @@ For example, if `refs/heads/master` is specified in `transfer.hideRefs` and
26802680
the current namespace is `foo`, then `refs/namespaces/foo/refs/heads/master`
26812681
is omitted from the advertisements but `refs/heads/master` and
26822682
`refs/namespaces/bar/refs/heads/master` are still advertised as so-called
2683-
"have" lines.
2683+
"have" lines. In order to match refs before stripping, add a `^` in front of
2684+
the ref name. If you combine `!` and `^`, `!` must be specified first.
26842685

26852686
transfer.unpackLimit::
26862687
When `fetch.unpackLimit` or `receive.unpackLimit` are

builtin/receive-pack.c

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,6 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
195195

196196
static void show_ref(const char *path, const unsigned char *sha1)
197197
{
198-
if (ref_is_hidden(path))
199-
return;
200-
201198
if (sent_capabilities) {
202199
packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
203200
} else {
@@ -219,9 +216,14 @@ static void show_ref(const char *path, const unsigned char *sha1)
219216
}
220217
}
221218

222-
static int show_ref_cb(const char *path, const struct object_id *oid, int flag, void *unused)
219+
static int show_ref_cb(const char *path_full, const struct object_id *oid,
220+
int flag, void *unused)
223221
{
224-
path = strip_namespace(path);
222+
const char *path = strip_namespace(path_full);
223+
224+
if (ref_is_hidden(path, path_full))
225+
return 0;
226+
225227
/*
226228
* Advertise refs outside our current namespace as ".have"
227229
* refs, so that the client can use them to minimize data
@@ -1195,16 +1197,29 @@ static int iterate_receive_command_list(void *cb_data, unsigned char sha1[20])
11951197

11961198
static void reject_updates_to_hidden(struct command *commands)
11971199
{
1200+
struct strbuf refname_full = STRBUF_INIT;
1201+
size_t prefix_len;
11981202
struct command *cmd;
11991203

1204+
strbuf_addstr(&refname_full, get_git_namespace());
1205+
prefix_len = refname_full.len;
1206+
12001207
for (cmd = commands; cmd; cmd = cmd->next) {
1201-
if (cmd->error_string || !ref_is_hidden(cmd->ref_name))
1208+
if (cmd->error_string)
1209+
continue;
1210+
1211+
strbuf_setlen(&refname_full, prefix_len);
1212+
strbuf_addstr(&refname_full, cmd->ref_name);
1213+
1214+
if (!ref_is_hidden(cmd->ref_name, refname_full.buf))
12021215
continue;
12031216
if (is_null_sha1(cmd->new_sha1))
12041217
cmd->error_string = "deny deleting a hidden ref";
12051218
else
12061219
cmd->error_string = "deny updating a hidden ref";
12071220
}
1221+
1222+
strbuf_release(&refname_full);
12081223
}
12091224

12101225
static int should_process_cmd(struct command *cmd)

refs.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4534,14 +4534,15 @@ int parse_hide_refs_config(const char *var, const char *value, const char *secti
45344534
return 0;
45354535
}
45364536

4537-
int ref_is_hidden(const char *refname)
4537+
int ref_is_hidden(const char *refname, const char *refname_full)
45384538
{
45394539
int i;
45404540

45414541
if (!hide_refs)
45424542
return 0;
45434543
for (i = hide_refs->nr - 1; i >= 0; i--) {
45444544
const char *match = hide_refs->items[i].string;
4545+
const char *subject;
45454546
int neg = 0;
45464547
int len;
45474548

@@ -4550,10 +4551,18 @@ int ref_is_hidden(const char *refname)
45504551
match++;
45514552
}
45524553

4553-
if (!starts_with(refname, match))
4554+
if (*match == '^') {
4555+
subject = refname_full;
4556+
match++;
4557+
} else {
4558+
subject = refname;
4559+
}
4560+
4561+
/* refname can be NULL when namespaces are used. */
4562+
if (!subject || !starts_with(subject, match))
45544563
continue;
45554564
len = strlen(match);
4556-
if (!refname[len] || refname[len] == '/')
4565+
if (!subject[len] || subject[len] == '/')
45574566
return !neg;
45584567
}
45594568
return 0;

refs.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,15 @@ int update_ref(const char *msg, const char *refname,
444444

445445
extern int parse_hide_refs_config(const char *var, const char *value, const char *);
446446

447-
extern int ref_is_hidden(const char *);
447+
/*
448+
* Check whether a ref is hidden. If no namespace is set, both the first and
449+
* the second parameter point to the full ref name. If a namespace is set and
450+
* the ref is inside that namespace, the first parameter is a pointer to the
451+
* name of the ref with the namespace prefix removed. If a namespace is set and
452+
* the ref is outside that namespace, the first parameter is NULL. The second
453+
* parameter always points to the full ref name.
454+
*/
455+
extern int ref_is_hidden(const char *, const char *);
448456

449457
enum ref_type {
450458
REF_TYPE_PER_WORKTREE,

upload-pack.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -688,22 +688,25 @@ static void receive_needs(void)
688688
}
689689

690690
/* return non-zero if the ref is hidden, otherwise 0 */
691-
static int mark_our_ref(const char *refname, const struct object_id *oid)
691+
static int mark_our_ref(const char *refname, const char *refname_full,
692+
const struct object_id *oid)
692693
{
693694
struct object *o = lookup_unknown_object(oid->hash);
694695

695-
if (refname && ref_is_hidden(refname)) {
696+
if (ref_is_hidden(refname, refname_full)) {
696697
o->flags |= HIDDEN_REF;
697698
return 1;
698699
}
699700
o->flags |= OUR_REF;
700701
return 0;
701702
}
702703

703-
static int check_ref(const char *refname, const struct object_id *oid,
704+
static int check_ref(const char *refname_full, const struct object_id *oid,
704705
int flag, void *cb_data)
705706
{
706-
mark_our_ref(strip_namespace(refname), oid);
707+
const char *refname = strip_namespace(refname_full);
708+
709+
mark_our_ref(refname, refname_full, oid);
707710
return 0;
708711
}
709712

@@ -726,7 +729,7 @@ static int send_ref(const char *refname, const struct object_id *oid,
726729
const char *refname_nons = strip_namespace(refname);
727730
struct object_id peeled;
728731

729-
if (mark_our_ref(refname_nons, oid))
732+
if (mark_our_ref(refname_nons, refname, oid))
730733
return 0;
731734

732735
if (capabilities) {

0 commit comments

Comments
 (0)