untracked cache: load from UNTR index extension
[gitweb.git] / send-pack.c
index 49748259234dea7301530251bcb1c86f1bb9f36f..9d2b0c52ed8235425795772db99fc14ea9c2bf2b 100644 (file)
@@ -47,6 +47,7 @@ static int pack_objects(int fd, struct ref *refs, struct sha1_array *extra, stru
                NULL,
                NULL,
                NULL,
+               NULL,
        };
        struct child_process po = CHILD_PROCESS_INIT;
        int i;
@@ -60,6 +61,8 @@ static int pack_objects(int fd, struct ref *refs, struct sha1_array *extra, stru
                argv[i++] = "-q";
        if (args->progress)
                argv[i++] = "--progress";
+       if (is_repository_shallow())
+               argv[i++] = "--shallow";
        po.argv = argv;
        po.in = -1;
        po.out = args->stateless_rpc ? -1 : fd;
@@ -282,6 +285,29 @@ static int generate_push_cert(struct strbuf *req_buf,
        return update_seen;
 }
 
+
+static int atomic_push_failure(struct send_pack_args *args,
+                              struct ref *remote_refs,
+                              struct ref *failing_ref)
+{
+       struct ref *ref;
+       /* Mark other refs as failed */
+       for (ref = remote_refs; ref; ref = ref->next) {
+               if (!ref->peer_ref && !args->send_mirror)
+                       continue;
+
+               switch (ref->status) {
+               case REF_STATUS_EXPECTING_REPORT:
+                       ref->status = REF_STATUS_ATOMIC_PUSH_FAILED;
+                       continue;
+               default:
+                       break; /* do nothing */
+               }
+       }
+       return error("atomic push failed for ref %s. status: %d\n",
+                    failing_ref->name, failing_ref->status);
+}
+
 int send_pack(struct send_pack_args *args,
              int fd[], struct child_process *conn,
              struct ref *remote_refs,
@@ -298,6 +324,8 @@ int send_pack(struct send_pack_args *args,
        int use_sideband = 0;
        int quiet_supported = 0;
        int agent_supported = 0;
+       int use_atomic = 0;
+       int atomic_supported = 0;
        unsigned cmds_sent = 0;
        int ret;
        struct async demux;
@@ -318,6 +346,8 @@ int send_pack(struct send_pack_args *args,
                agent_supported = 1;
        if (server_supports("no-thin"))
                args->use_thin_pack = 0;
+       if (server_supports("atomic"))
+               atomic_supported = 1;
        if (args->push_cert) {
                int len;
 
@@ -332,6 +362,10 @@ int send_pack(struct send_pack_args *args,
                        "Perhaps you should specify a branch such as 'master'.\n");
                return 0;
        }
+       if (args->atomic && !atomic_supported)
+               die(_("server does not support --atomic push"));
+
+       use_atomic = atomic_supported && args->atomic;
 
        if (status_report)
                strbuf_addstr(&cap_buf, " report-status");
@@ -339,6 +373,8 @@ int send_pack(struct send_pack_args *args,
                strbuf_addstr(&cap_buf, " side-band-64k");
        if (quiet_supported && (args->quiet || !args->progress))
                strbuf_addstr(&cap_buf, " quiet");
+       if (use_atomic)
+               strbuf_addstr(&cap_buf, " atomic");
        if (agent_supported)
                strbuf_addf(&cap_buf, " agent=%s", git_user_agent_sanitized());
 
@@ -363,9 +399,21 @@ int send_pack(struct send_pack_args *args,
         * the pack data.
         */
        for (ref = remote_refs; ref; ref = ref->next) {
-               if (check_to_send_update(ref, args) < 0)
+               switch (check_to_send_update(ref, args)) {
+               case 0: /* no error */
+                       break;
+               case CHECK_REF_STATUS_REJECTED:
+                       /*
+                        * When we know the server would reject a ref update if
+                        * we were to send it and we're trying to send the refs
+                        * atomically, abort the whole operation.
+                        */
+                       if (use_atomic)
+                               return atomic_push_failure(args, remote_refs, ref);
+                       /* Fallthrough for non atomic case. */
+               default:
                        continue;
-
+               }
                if (!ref->deletion)
                        need_pack_data = 1;