]> git.ipfire.org Git - thirdparty/git.git/blobdiff - transport.c
New capability "report-status-v2" for git-push
[thirdparty/git.git] / transport.c
index 1fdc7dac1a6230bdf3492cbebd6642fc825dac5f..e146de6c4eba4bedd577933a97e95929f2c0d123 100644 (file)
@@ -16,7 +16,7 @@
 #include "url.h"
 #include "submodule.h"
 #include "string-list.h"
-#include "sha1-array.h"
+#include "oid-array.h"
 #include "sigchain.h"
 #include "transport-internal.h"
 #include "protocol.h"
@@ -461,13 +461,21 @@ void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int v
 
 static void print_ref_status(char flag, const char *summary,
                             struct ref *to, struct ref *from, const char *msg,
+                            struct ref_push_report *report,
                             int porcelain, int summary_width)
 {
+       const char *to_name;
+
+       if (report && report->ref_name)
+               to_name = report->ref_name;
+       else
+               to_name = to->name;
+
        if (porcelain) {
                if (from)
-                       fprintf(stdout, "%c\t%s:%s\t", flag, from->name, to->name);
+                       fprintf(stdout, "%c\t%s:%s\t", flag, from->name, to_name);
                else
-                       fprintf(stdout, "%c\t:%s\t", flag, to->name);
+                       fprintf(stdout, "%c\t:%s\t", flag, to_name);
                if (msg)
                        fprintf(stdout, "%s (%s)\n", summary, msg);
                else
@@ -481,9 +489,11 @@ static void print_ref_status(char flag, const char *summary,
                fprintf(stderr, " %s%c %-*s%s ", red, flag, summary_width,
                        summary, reset);
                if (from)
-                       fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
+                       fprintf(stderr, "%s -> %s",
+                               prettify_refname(from->name),
+                               prettify_refname(to_name));
                else
-                       fputs(prettify_refname(to->name), stderr);
+                       fputs(prettify_refname(to_name), stderr);
                if (msg) {
                        fputs(" (", stderr);
                        fputs(msg, stderr);
@@ -493,24 +503,52 @@ static void print_ref_status(char flag, const char *summary,
        }
 }
 
-static void print_ok_ref_status(struct ref *ref, int porcelain, int summary_width)
+static void print_ok_ref_status(struct ref *ref,
+                               struct ref_push_report *report,
+                               int porcelain, int summary_width)
 {
+       struct object_id *old_oid;
+       struct object_id *new_oid;
+       const char *ref_name;
+       int forced_update;
+
+       if (report && report->old_oid)
+               old_oid = report->old_oid;
+       else
+               old_oid = &ref->old_oid;
+       if (report && report->new_oid)
+               new_oid = report->new_oid;
+       else
+               new_oid = &ref->new_oid;
+       if (report && report->forced_update)
+               forced_update = report->forced_update;
+       else
+               forced_update = ref->forced_update;
+       if (report && report->ref_name)
+               ref_name = report->ref_name;
+       else
+               ref_name = ref->name;
+
        if (ref->deletion)
                print_ref_status('-', "[deleted]", ref, NULL, NULL,
-                                porcelain, summary_width);
-       else if (is_null_oid(&ref->old_oid))
+                                report, porcelain, summary_width);
+       else if (is_null_oid(old_oid))
                print_ref_status('*',
-                       (starts_with(ref->name, "refs/tags/") ? "[new tag]" :
-                       "[new branch]"),
-                       ref, ref->peer_ref, NULL, porcelain, summary_width);
+                                (starts_with(ref_name, "refs/tags/")
+                                 ? "[new tag]"
+                                 : (starts_with(ref_name, "refs/heads/")
+                                    ? "[new branch]"
+                                    : "[new reference]")),
+                                ref, ref->peer_ref, NULL,
+                                report, porcelain, summary_width);
        else {
                struct strbuf quickref = STRBUF_INIT;
                char type;
                const char *msg;
 
-               strbuf_add_unique_abbrev(&quickref, &ref->old_oid,
+               strbuf_add_unique_abbrev(&quickref, old_oid,
                                         DEFAULT_ABBREV);
-               if (ref->forced_update) {
+               if (forced_update) {
                        strbuf_addstr(&quickref, "...");
                        type = '+';
                        msg = "forced update";
@@ -519,16 +557,17 @@ static void print_ok_ref_status(struct ref *ref, int porcelain, int summary_widt
                        type = ' ';
                        msg = NULL;
                }
-               strbuf_add_unique_abbrev(&quickref, &ref->new_oid,
+               strbuf_add_unique_abbrev(&quickref, new_oid,
                                         DEFAULT_ABBREV);
 
                print_ref_status(type, quickref.buf, ref, ref->peer_ref, msg,
-                                porcelain, summary_width);
+                                report, porcelain, summary_width);
                strbuf_release(&quickref);
        }
 }
 
-static int print_one_push_status(struct ref *ref, const char *dest, int count,
+static int print_one_push_report(struct ref *ref, const char *dest, int count,
+                                struct ref_push_report *report,
                                 int porcelain, int summary_width)
 {
        if (!count) {
@@ -540,65 +579,89 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count,
        switch(ref->status) {
        case REF_STATUS_NONE:
                print_ref_status('X', "[no match]", ref, NULL, NULL,
-                                porcelain, summary_width);
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_REJECT_NODELETE:
                print_ref_status('!', "[rejected]", ref, NULL,
                                 "remote does not support deleting refs",
-                                porcelain, summary_width);
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_UPTODATE:
                print_ref_status('=', "[up to date]", ref,
-                                ref->peer_ref, NULL, porcelain, summary_width);
+                                ref->peer_ref, NULL,
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_REJECT_NONFASTFORWARD:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-                                "non-fast-forward", porcelain, summary_width);
+                                "non-fast-forward",
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_REJECT_ALREADY_EXISTS:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-                                "already exists", porcelain, summary_width);
+                                "already exists",
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_REJECT_FETCH_FIRST:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-                                "fetch first", porcelain, summary_width);
+                                "fetch first",
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_REJECT_NEEDS_FORCE:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-                                "needs force", porcelain, summary_width);
+                                "needs force",
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_REJECT_STALE:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-                                "stale info", porcelain, summary_width);
+                                "stale info",
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_REJECT_SHALLOW:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
                                 "new shallow roots not allowed",
-                                porcelain, summary_width);
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_REMOTE_REJECT:
                print_ref_status('!', "[remote rejected]", ref,
                                 ref->deletion ? NULL : ref->peer_ref,
-                                ref->remote_status, porcelain, summary_width);
+                                ref->remote_status,
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_EXPECTING_REPORT:
                print_ref_status('!', "[remote failure]", ref,
                                 ref->deletion ? NULL : ref->peer_ref,
                                 "remote failed to report status",
-                                porcelain, summary_width);
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_ATOMIC_PUSH_FAILED:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-                                "atomic push failed", porcelain, summary_width);
+                                "atomic push failed",
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_OK:
-               print_ok_ref_status(ref, porcelain, summary_width);
+               print_ok_ref_status(ref, report, porcelain, summary_width);
                break;
        }
 
        return 1;
 }
 
+static int print_one_push_status(struct ref *ref, const char *dest, int count,
+                                int porcelain, int summary_width)
+{
+       struct ref_push_report *report;
+       int n = 0;
+
+       if (!ref->report)
+               return print_one_push_report(ref, dest, count,
+                                            NULL, porcelain, summary_width);
+
+       for (report = ref->report; report; report = report->next)
+               print_one_push_report(ref, dest, count + n++,
+                                     report, porcelain, summary_width);
+       return n;
+}
+
 static int measure_abbrev(const struct object_id *oid, int sofar)
 {
        char hex[GIT_MAX_HEXSZ + 1];
@@ -715,7 +778,15 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
 
        close(data->fd[1]);
        close(data->fd[0]);
-       ret |= finish_connect(data->conn);
+       /*
+        * Atomic push may abort the connection early and close the pipe,
+        * which may cause an error for `finish_connect()`. Ignore this error
+        * for atomic git-push.
+        */
+       if (ret || args.atomic)
+               finish_connect(data->conn);
+       else
+               ret = finish_connect(data->conn);
        data->conn = NULL;
        data->got_remote_heads = 0;
 
@@ -1240,20 +1311,6 @@ int transport_push(struct repository *r,
                err = push_had_errors(remote_refs);
                ret = push_ret | err;
 
-               if ((flags & TRANSPORT_PUSH_ATOMIC) && err) {
-                       struct ref *it;
-                       for (it = remote_refs; it; it = it->next)
-                               switch (it->status) {
-                               case REF_STATUS_NONE:
-                               case REF_STATUS_UPTODATE:
-                               case REF_STATUS_OK:
-                                       it->status = REF_STATUS_ATOMIC_PUSH_FAILED;
-                                       break;
-                               default:
-                                       break;
-                               }
-               }
-
                if (!quiet || err)
                        transport_print_push_status(transport->url, remote_refs,
                                        verbose | porcelain, porcelain,