Skip to content

Commit 6b01ecf

Browse files
joshtriplettgitster
authored andcommitted
ref namespaces: Support remote repositories via upload-pack and receive-pack
Change upload-pack and receive-pack to use the namespace-prefixed refs when working with the repository, and use the unprefixed refs when talking to the client, maintaining the masquerade. This allows clone, pull, fetch, and push to work with a suitably configured GIT_NAMESPACE. receive-pack advertises refs outside the current namespace as .have refs (as it currently does for refs in alternates), so that the client can use them to minimize data transfer but will otherwise ignore them. With appropriate configuration, this also allows http-backend to expose namespaces as multiple repositories with different paths. This only requires setting GIT_NAMESPACE, which http-backend passes through to upload-pack and receive-pack. Signed-off-by: Josh Triplett <[email protected]> Signed-off-by: Jamey Sharp <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent a1bea2c commit 6b01ecf

File tree

2 files changed

+47
-13
lines changed

2 files changed

+47
-13
lines changed

builtin/receive-pack.c

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,25 @@ static int show_ref(const char *path, const unsigned char *sha1, int flag, void
119119
return 0;
120120
}
121121

122+
static int show_ref_cb(const char *path, const unsigned char *sha1, int flag, void *cb_data)
123+
{
124+
path = strip_namespace(path);
125+
/*
126+
* Advertise refs outside our current namespace as ".have"
127+
* refs, so that the client can use them to minimize data
128+
* transfer but will otherwise ignore them. This happens to
129+
* cover ".have" that are thrown in by add_one_alternate_ref()
130+
* to mark histories that are complete in our alternates as
131+
* well.
132+
*/
133+
if (!path)
134+
path = ".have";
135+
return show_ref(path, sha1, flag, cb_data);
136+
}
137+
122138
static void write_head_info(void)
123139
{
124-
for_each_ref(show_ref, NULL);
140+
for_each_ref(show_ref_cb, NULL);
125141
if (!sent_capabilities)
126142
show_ref("capabilities^{}", null_sha1, 0, NULL);
127143

@@ -332,6 +348,8 @@ static void refuse_unconfigured_deny_delete_current(void)
332348
static const char *update(struct command *cmd)
333349
{
334350
const char *name = cmd->ref_name;
351+
struct strbuf namespaced_name_buf = STRBUF_INIT;
352+
const char *namespaced_name;
335353
unsigned char *old_sha1 = cmd->old_sha1;
336354
unsigned char *new_sha1 = cmd->new_sha1;
337355
struct ref_lock *lock;
@@ -342,7 +360,10 @@ static const char *update(struct command *cmd)
342360
return "funny refname";
343361
}
344362

345-
if (is_ref_checked_out(name)) {
363+
strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name);
364+
namespaced_name = strbuf_detach(&namespaced_name_buf, NULL);
365+
366+
if (is_ref_checked_out(namespaced_name)) {
346367
switch (deny_current_branch) {
347368
case DENY_IGNORE:
348369
break;
@@ -370,7 +391,7 @@ static const char *update(struct command *cmd)
370391
return "deletion prohibited";
371392
}
372393

373-
if (!strcmp(name, head_name)) {
394+
if (!strcmp(namespaced_name, head_name)) {
374395
switch (deny_delete_current) {
375396
case DENY_IGNORE:
376397
break;
@@ -426,14 +447,14 @@ static const char *update(struct command *cmd)
426447
rp_warning("Allowing deletion of corrupt ref.");
427448
old_sha1 = NULL;
428449
}
429-
if (delete_ref(name, old_sha1, 0)) {
450+
if (delete_ref(namespaced_name, old_sha1, 0)) {
430451
rp_error("failed to delete %s", name);
431452
return "failed to delete";
432453
}
433454
return NULL; /* good */
434455
}
435456
else {
436-
lock = lock_any_ref_for_update(name, old_sha1, 0);
457+
lock = lock_any_ref_for_update(namespaced_name, old_sha1, 0);
437458
if (!lock) {
438459
rp_error("failed to lock %s", name);
439460
return "failed to lock";
@@ -490,17 +511,29 @@ static void run_update_post_hook(struct command *commands)
490511

491512
static void check_aliased_update(struct command *cmd, struct string_list *list)
492513
{
514+
struct strbuf buf = STRBUF_INIT;
515+
const char *dst_name;
493516
struct string_list_item *item;
494517
struct command *dst_cmd;
495518
unsigned char sha1[20];
496519
char cmd_oldh[41], cmd_newh[41], dst_oldh[41], dst_newh[41];
497520
int flag;
498521

499-
const char *dst_name = resolve_ref(cmd->ref_name, sha1, 0, &flag);
522+
strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name);
523+
dst_name = resolve_ref(buf.buf, sha1, 0, &flag);
524+
strbuf_release(&buf);
500525

501526
if (!(flag & REF_ISSYMREF))
502527
return;
503528

529+
dst_name = strip_namespace(dst_name);
530+
if (!dst_name) {
531+
rp_error("refusing update to broken symref '%s'", cmd->ref_name);
532+
cmd->skip_update = 1;
533+
cmd->error_string = "broken symref";
534+
return;
535+
}
536+
504537
if ((item = string_list_lookup(list, dst_name)) == NULL)
505538
return;
506539

upload-pack.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -641,16 +641,17 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
641641
" side-band-64k ofs-delta shallow no-progress"
642642
" include-tag multi_ack_detailed";
643643
struct object *o = parse_object(sha1);
644+
const char *refname_nons = strip_namespace(refname);
644645

645646
if (!o)
646647
die("git upload-pack: cannot find object %s:", sha1_to_hex(sha1));
647648

648649
if (capabilities)
649-
packet_write(1, "%s %s%c%s%s\n", sha1_to_hex(sha1), refname,
650+
packet_write(1, "%s %s%c%s%s\n", sha1_to_hex(sha1), refname_nons,
650651
0, capabilities,
651652
stateless_rpc ? " no-done" : "");
652653
else
653-
packet_write(1, "%s %s\n", sha1_to_hex(sha1), refname);
654+
packet_write(1, "%s %s\n", sha1_to_hex(sha1), refname_nons);
654655
capabilities = NULL;
655656
if (!(o->flags & OUR_REF)) {
656657
o->flags |= OUR_REF;
@@ -659,7 +660,7 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
659660
if (o->type == OBJ_TAG) {
660661
o = deref_tag(o, refname, 0);
661662
if (o)
662-
packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname);
663+
packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname_nons);
663664
}
664665
return 0;
665666
}
@@ -680,12 +681,12 @@ static void upload_pack(void)
680681
{
681682
if (advertise_refs || !stateless_rpc) {
682683
reset_timeout();
683-
head_ref(send_ref, NULL);
684-
for_each_ref(send_ref, NULL);
684+
head_ref_namespaced(send_ref, NULL);
685+
for_each_namespaced_ref(send_ref, NULL);
685686
packet_flush(1);
686687
} else {
687-
head_ref(mark_our_ref, NULL);
688-
for_each_ref(mark_our_ref, NULL);
688+
head_ref_namespaced(mark_our_ref, NULL);
689+
for_each_namespaced_ref(mark_our_ref, NULL);
689690
}
690691
if (advertise_refs)
691692
return;

0 commit comments

Comments
 (0)