Merge branch 'mh/attr'
[gitweb.git] / builtin / receive-pack.c
index 6bb1281666e45684b0f75ecbfc04e887723e914a..60260d0aa93a878968e5ed72a2a77b96c5c0f040 100644 (file)
@@ -10,6 +10,7 @@
 #include "remote.h"
 #include "transport.h"
 #include "string-list.h"
+#include "sha1-array.h"
 
 static const char receive_pack_usage[] = "git receive-pack <git-dir>";
 
@@ -119,9 +120,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 +349,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 +361,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 +392,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 +448,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 +512,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;
 
@@ -635,7 +669,7 @@ static const char *parse_pack_header(struct pack_header *hdr)
 
 static const char *pack_lockfile;
 
-static const char *unpack(void)
+static const char *unpack(int quiet)
 {
        struct pack_header hdr;
        const char *hdr_err;
@@ -650,8 +684,10 @@ static const char *unpack(void)
 
        if (ntohl(hdr.hdr_entries) < unpack_limit) {
                int code, i = 0;
-               const char *unpacker[4];
+               const char *unpacker[5];
                unpacker[i++] = "unpack-objects";
+               if (quiet)
+                       unpacker[i++] = "-q";
                if (receive_fsck_objects)
                        unpacker[i++] = "--strict";
                unpacker[i++] = hdr_arg;
@@ -731,18 +767,28 @@ static int delete_only(struct command *commands)
        return 1;
 }
 
-static void add_one_alternate_ref(const struct ref *ref, void *unused)
+static void add_one_alternate_sha1(const unsigned char sha1[20], void *unused)
+{
+       add_extra_ref(".have", sha1, 0);
+}
+
+static void collect_one_alternate_ref(const struct ref *ref, void *data)
 {
-       add_extra_ref(".have", ref->old_sha1, 0);
+       struct sha1_array *sa = data;
+       sha1_array_append(sa, ref->old_sha1);
 }
 
 static void add_alternate_refs(void)
 {
-       for_each_alternate_ref(add_one_alternate_ref, NULL);
+       struct sha1_array sa = SHA1_ARRAY_INIT;
+       for_each_alternate_ref(collect_one_alternate_ref, &sa);
+       sha1_array_for_each_unique(&sa, add_one_alternate_sha1, NULL);
+       sha1_array_clear(&sa);
 }
 
 int cmd_receive_pack(int argc, const char **argv, const char *prefix)
 {
+       int quiet = 0;
        int advertise_refs = 0;
        int stateless_rpc = 0;
        int i;
@@ -756,6 +802,11 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
                const char *arg = *argv++;
 
                if (*arg == '-') {
+                       if (!strcmp(arg, "--quiet")) {
+                               quiet = 1;
+                               continue;
+                       }
+
                        if (!strcmp(arg, "--advertise-refs")) {
                                advertise_refs = 1;
                                continue;
@@ -804,7 +855,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
                const char *unpack_status = NULL;
 
                if (!delete_only(commands))
-                       unpack_status = unpack();
+                       unpack_status = unpack(quiet);
                execute_commands(commands, unpack_status);
                if (pack_lockfile)
                        unlink_or_warn(pack_lockfile);