summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin/receive-pack.c45
-rw-r--r--upload-pack.c15
2 files changed, 47 insertions, 13 deletions
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index e1ba4dc697..e589082b31 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -119,9 +119,25 @@ static int show_ref(const char *path, const unsigned char *sha1, int flag, void
return 0;
}
+static int show_ref_cb(const char *path, const unsigned char *sha1, int flag, void *cb_data)
+{
+ path = strip_namespace(path);
+ /*
+ * Advertise refs outside our current namespace as ".have"
+ * refs, so that the client can use them to minimize data
+ * transfer but will otherwise ignore them. This happens to
+ * cover ".have" that are thrown in by add_one_alternate_ref()
+ * to mark histories that are complete in our alternates as
+ * well.
+ */
+ if (!path)
+ path = ".have";
+ return show_ref(path, sha1, flag, cb_data);
+}
+
static void write_head_info(void)
{
- for_each_ref(show_ref, NULL);
+ for_each_ref(show_ref_cb, NULL);
if (!sent_capabilities)
show_ref("capabilities^{}", null_sha1, 0, NULL);
@@ -332,6 +348,8 @@ static void refuse_unconfigured_deny_delete_current(void)
static const char *update(struct command *cmd)
{
const char *name = cmd->ref_name;
+ struct strbuf namespaced_name_buf = STRBUF_INIT;
+ const char *namespaced_name;
unsigned char *old_sha1 = cmd->old_sha1;
unsigned char *new_sha1 = cmd->new_sha1;
struct ref_lock *lock;
@@ -342,7 +360,10 @@ static const char *update(struct command *cmd)
return "funny refname";
}
- if (is_ref_checked_out(name)) {
+ strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name);
+ namespaced_name = strbuf_detach(&namespaced_name_buf, NULL);
+
+ if (is_ref_checked_out(namespaced_name)) {
switch (deny_current_branch) {
case DENY_IGNORE:
break;
@@ -370,7 +391,7 @@ static const char *update(struct command *cmd)
return "deletion prohibited";
}
- if (!strcmp(name, head_name)) {
+ if (!strcmp(namespaced_name, head_name)) {
switch (deny_delete_current) {
case DENY_IGNORE:
break;
@@ -426,14 +447,14 @@ static const char *update(struct command *cmd)
rp_warning("Allowing deletion of corrupt ref.");
old_sha1 = NULL;
}
- if (delete_ref(name, old_sha1, 0)) {
+ if (delete_ref(namespaced_name, old_sha1, 0)) {
rp_error("failed to delete %s", name);
return "failed to delete";
}
return NULL; /* good */
}
else {
- lock = lock_any_ref_for_update(name, old_sha1, 0);
+ lock = lock_any_ref_for_update(namespaced_name, old_sha1, 0);
if (!lock) {
rp_error("failed to lock %s", name);
return "failed to lock";
@@ -490,17 +511,29 @@ static void run_update_post_hook(struct command *commands)
static void check_aliased_update(struct command *cmd, struct string_list *list)
{
+ struct strbuf buf = STRBUF_INIT;
+ const char *dst_name;
struct string_list_item *item;
struct command *dst_cmd;
unsigned char sha1[20];
char cmd_oldh[41], cmd_newh[41], dst_oldh[41], dst_newh[41];
int flag;
- const char *dst_name = resolve_ref(cmd->ref_name, sha1, 0, &flag);
+ strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name);
+ dst_name = resolve_ref(buf.buf, sha1, 0, &flag);
+ strbuf_release(&buf);
if (!(flag & REF_ISSYMREF))
return;
+ dst_name = strip_namespace(dst_name);
+ if (!dst_name) {
+ rp_error("refusing update to broken symref '%s'", cmd->ref_name);
+ cmd->skip_update = 1;
+ cmd->error_string = "broken symref";
+ return;
+ }
+
if ((item = string_list_lookup(list, dst_name)) == NULL)
return;
diff --git a/upload-pack.c b/upload-pack.c
index ce5cbbea6b..267e5b1d82 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -641,16 +641,17 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
" side-band-64k ofs-delta shallow no-progress"
" include-tag multi_ack_detailed";
struct object *o = parse_object(sha1);
+ const char *refname_nons = strip_namespace(refname);
if (!o)
die("git upload-pack: cannot find object %s:", sha1_to_hex(sha1));
if (capabilities)
- packet_write(1, "%s %s%c%s%s\n", sha1_to_hex(sha1), refname,
+ packet_write(1, "%s %s%c%s%s\n", sha1_to_hex(sha1), refname_nons,
0, capabilities,
stateless_rpc ? " no-done" : "");
else
- packet_write(1, "%s %s\n", sha1_to_hex(sha1), refname);
+ packet_write(1, "%s %s\n", sha1_to_hex(sha1), refname_nons);
capabilities = NULL;
if (!(o->flags & OUR_REF)) {
o->flags |= OUR_REF;
@@ -659,7 +660,7 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
if (o->type == OBJ_TAG) {
o = deref_tag(o, refname, 0);
if (o)
- packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname);
+ packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname_nons);
}
return 0;
}
@@ -680,12 +681,12 @@ static void upload_pack(void)
{
if (advertise_refs || !stateless_rpc) {
reset_timeout();
- head_ref(send_ref, NULL);
- for_each_ref(send_ref, NULL);
+ head_ref_namespaced(send_ref, NULL);
+ for_each_namespaced_ref(send_ref, NULL);
packet_flush(1);
} else {
- head_ref(mark_our_ref, NULL);
- for_each_ref(mark_our_ref, NULL);
+ head_ref_namespaced(mark_our_ref, NULL);
+ for_each_namespaced_ref(mark_our_ref, NULL);
}
if (advertise_refs)
return;