]> asedeno.scripts.mit.edu Git - git.git/commitdiff
Merge branch 'ld/push-porcelain'
authorJunio C Hamano <gitster@pobox.com>
Mon, 15 Mar 2010 07:58:24 +0000 (00:58 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 15 Mar 2010 07:58:24 +0000 (00:58 -0700)
* ld/push-porcelain:
  t5516: Use test_cmp when appropriate
  git-push: add tests for git push --porcelain
  git-push: make git push --porcelain print "Done"
  git-push: send "To <remoteurl>" messages to the standard output in --porcelain mode
  git-push: fix an advice message so it goes to stderr

Conflicts:
transport.c

1  2 
builtin/push.c
builtin/send-pack.c
transport.c

diff --combined builtin/push.c
index f7bc2b292fb85725d9cc26ce09f2302aaa7167fe,0a270726982c73538cc72b5c3e6e072b379f00fb..235ca12455e7447118f689040b019cc5aac7c8f3
@@@ -68,7 -68,7 +68,7 @@@ static void setup_push_tracking(void
        struct branch *branch = branch_get(NULL);
        if (!branch)
                die("You are not currently on a branch.");
 -      if (!branch->merge_nr)
 +      if (!branch->merge_nr || !branch->merge)
                die("The current branch %s is not tracking anything.",
                    branch->name);
        if (branch->merge_nr != 1)
@@@ -124,9 -124,9 +124,9 @@@ static int push_with_options(struct tra
                return 0;
  
        if (nonfastforward && advice_push_nonfastforward) {
-               printf("To prevent you from losing history, non-fast-forward updates were rejected\n"
-                      "Merge the remote changes before pushing again.  See the 'Note about\n"
-                      "fast-forwards' section of 'git push --help' for details.\n");
+               fprintf(stderr, "To prevent you from losing history, non-fast-forward updates were rejected\n"
+                               "Merge the remote changes before pushing again.  See the 'Note about\n"
+                               "fast-forwards' section of 'git push --help' for details.\n");
        }
  
        return 1;
diff --combined builtin/send-pack.c
index 6019eac9182e22f2d485acdb83be209dbc49968a,078bc3e8ec2c19f7fc5e8688cccd3ac4679c7a51..481602d8ae73612226bcc758f2aedea7f964779c
@@@ -7,7 -7,6 +7,7 @@@
  #include "remote.h"
  #include "send-pack.h"
  #include "quote.h"
 +#include "transport.h"
  
  static const char send_pack_usage[] =
  "git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
@@@ -170,6 -169,156 +170,6 @@@ static int receive_status(int in, struc
        return ret;
  }
  
 -static void update_tracking_ref(struct remote *remote, struct ref *ref)
 -{
 -      struct refspec rs;
 -
 -      if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE)
 -              return;
 -
 -      rs.src = ref->name;
 -      rs.dst = NULL;
 -
 -      if (!remote_find_tracking(remote, &rs)) {
 -              if (args.verbose)
 -                      fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst);
 -              if (ref->deletion) {
 -                      delete_ref(rs.dst, NULL, 0);
 -              } else
 -                      update_ref("update by push", rs.dst,
 -                                      ref->new_sha1, NULL, 0, 0);
 -              free(rs.dst);
 -      }
 -}
 -
 -#define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
 -
 -static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg)
 -{
 -      fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
 -      if (from)
 -              fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
 -      else
 -              fputs(prettify_refname(to->name), stderr);
 -      if (msg) {
 -              fputs(" (", stderr);
 -              fputs(msg, stderr);
 -              fputc(')', stderr);
 -      }
 -      fputc('\n', stderr);
 -}
 -
 -static const char *status_abbrev(unsigned char sha1[20])
 -{
 -      return find_unique_abbrev(sha1, DEFAULT_ABBREV);
 -}
 -
 -static void print_ok_ref_status(struct ref *ref)
 -{
 -      if (ref->deletion)
 -              print_ref_status('-', "[deleted]", ref, NULL, NULL);
 -      else if (is_null_sha1(ref->old_sha1))
 -              print_ref_status('*',
 -                      (!prefixcmp(ref->name, "refs/tags/") ? "[new tag]" :
 -                        "[new branch]"),
 -                      ref, ref->peer_ref, NULL);
 -      else {
 -              char quickref[84];
 -              char type;
 -              const char *msg;
 -
 -              strcpy(quickref, status_abbrev(ref->old_sha1));
 -              if (ref->nonfastforward) {
 -                      strcat(quickref, "...");
 -                      type = '+';
 -                      msg = "forced update";
 -              } else {
 -                      strcat(quickref, "..");
 -                      type = ' ';
 -                      msg = NULL;
 -              }
 -              strcat(quickref, status_abbrev(ref->new_sha1));
 -
 -              print_ref_status(type, quickref, ref, ref->peer_ref, msg);
 -      }
 -}
 -
 -static int print_one_push_status(struct ref *ref, const char *dest, int count)
 -{
 -      if (!count)
 -              fprintf(stderr, "To %s\n", dest);
 -
 -      switch(ref->status) {
 -      case REF_STATUS_NONE:
 -              print_ref_status('X', "[no match]", ref, NULL, NULL);
 -              break;
 -      case REF_STATUS_REJECT_NODELETE:
 -              print_ref_status('!', "[rejected]", ref, NULL,
 -                              "remote does not support deleting refs");
 -              break;
 -      case REF_STATUS_UPTODATE:
 -              print_ref_status('=', "[up to date]", ref,
 -                              ref->peer_ref, NULL);
 -              break;
 -      case REF_STATUS_REJECT_NONFASTFORWARD:
 -              print_ref_status('!', "[rejected]", ref, ref->peer_ref,
 -                              "non-fast-forward");
 -              break;
 -      case REF_STATUS_REMOTE_REJECT:
 -              print_ref_status('!', "[remote rejected]", ref,
 -                              ref->deletion ? NULL : ref->peer_ref,
 -                              ref->remote_status);
 -              break;
 -      case REF_STATUS_EXPECTING_REPORT:
 -              print_ref_status('!', "[remote failure]", ref,
 -                              ref->deletion ? NULL : ref->peer_ref,
 -                              "remote failed to report status");
 -              break;
 -      case REF_STATUS_OK:
 -              print_ok_ref_status(ref);
 -              break;
 -      }
 -
 -      return 1;
 -}
 -
 -static void print_push_status(const char *dest, struct ref *refs)
 -{
 -      struct ref *ref;
 -      int n = 0;
 -
 -      if (args.verbose) {
 -              for (ref = refs; ref; ref = ref->next)
 -                      if (ref->status == REF_STATUS_UPTODATE)
 -                              n += print_one_push_status(ref, dest, n);
 -      }
 -
 -      for (ref = refs; ref; ref = ref->next)
 -              if (ref->status == REF_STATUS_OK)
 -                      n += print_one_push_status(ref, dest, n);
 -
 -      for (ref = refs; ref; ref = ref->next) {
 -              if (ref->status != REF_STATUS_NONE &&
 -                  ref->status != REF_STATUS_UPTODATE &&
 -                  ref->status != REF_STATUS_OK)
 -                      n += print_one_push_status(ref, dest, n);
 -      }
 -}
 -
 -static int refs_pushed(struct ref *ref)
 -{
 -      for (; ref; ref = ref->next) {
 -              switch(ref->status) {
 -              case REF_STATUS_NONE:
 -              case REF_STATUS_UPTODATE:
 -                      break;
 -              default:
 -                      return 1;
 -              }
 -      }
 -      return 0;
 -}
 -
  static void print_helper_status(struct ref *ref)
  {
        struct strbuf buf = STRBUF_INIT;
        strbuf_release(&buf);
  }
  
 +static int sideband_demux(int in, int out, void *data)
 +{
 +      int *fd = data;
 +      int ret = recv_sideband("send-pack", fd[0], out);
 +      close(out);
 +      return ret;
 +}
 +
  int send_pack(struct send_pack_args *args,
              int fd[], struct child_process *conn,
              struct ref *remote_refs,
        struct strbuf req_buf = STRBUF_INIT;
        struct ref *ref;
        int new_refs;
 -      int ask_for_status_report = 0;
        int allow_deleting_refs = 0;
 -      int expect_status_report = 0;
 +      int status_report = 0;
 +      int use_sideband = 0;
 +      unsigned cmds_sent = 0;
        int ret;
 +      struct async demux;
  
        /* Does the other end support the reporting? */
        if (server_supports("report-status"))
 -              ask_for_status_report = 1;
 +              status_report = 1;
        if (server_supports("delete-refs"))
                allow_deleting_refs = 1;
        if (server_supports("ofs-delta"))
                args->use_ofs_delta = 1;
 +      if (server_supports("side-band-64k"))
 +              use_sideband = 1;
  
        if (!remote_refs) {
                fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
                if (!ref->deletion)
                        new_refs++;
  
 -              if (!args->dry_run) {
 +              if (args->dry_run) {
 +                      ref->status = REF_STATUS_OK;
 +              } else {
                        char *old_hex = sha1_to_hex(ref->old_sha1);
                        char *new_hex = sha1_to_hex(ref->new_sha1);
  
 -                      if (ask_for_status_report) {
 -                              packet_buf_write(&req_buf, "%s %s %s%c%s",
 +                      if (!cmds_sent && (status_report || use_sideband)) {
 +                              packet_buf_write(&req_buf, "%s %s %s%c%s%s",
                                        old_hex, new_hex, ref->name, 0,
 -                                      "report-status");
 -                              ask_for_status_report = 0;
 -                              expect_status_report = 1;
 +                                      status_report ? " report-status" : "",
 +                                      use_sideband ? " side-band-64k" : "");
                        }
                        else
                                packet_buf_write(&req_buf, "%s %s %s",
                                        old_hex, new_hex, ref->name);
 +                      ref->status = status_report ?
 +                              REF_STATUS_EXPECTING_REPORT :
 +                              REF_STATUS_OK;
 +                      cmds_sent++;
                }
 -              ref->status = expect_status_report ?
 -                      REF_STATUS_EXPECTING_REPORT :
 -                      REF_STATUS_OK;
        }
  
        if (args->stateless_rpc) {
 -              if (!args->dry_run) {
 +              if (!args->dry_run && cmds_sent) {
                        packet_buf_flush(&req_buf);
                        send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
                }
        }
        strbuf_release(&req_buf);
  
 -      if (new_refs && !args->dry_run) {
 +      if (use_sideband && cmds_sent) {
 +              memset(&demux, 0, sizeof(demux));
 +              demux.proc = sideband_demux;
 +              demux.data = fd;
 +              demux.out = -1;
 +              if (start_async(&demux))
 +                      die("receive-pack: unable to fork off sideband demultiplexer");
 +              in = demux.out;
 +      }
 +
 +      if (new_refs && cmds_sent) {
                if (pack_objects(out, remote_refs, extra_have, args) < 0) {
                        for (ref = remote_refs; ref; ref = ref->next)
                                ref->status = REF_STATUS_NONE;
 +                      if (use_sideband)
 +                              finish_async(&demux);
                        return -1;
                }
        }
 -      if (args->stateless_rpc && !args->dry_run)
 +      if (args->stateless_rpc && cmds_sent)
                packet_flush(out);
  
 -      if (expect_status_report)
 +      if (status_report && cmds_sent)
                ret = receive_status(in, remote_refs);
        else
                ret = 0;
        if (args->stateless_rpc)
                packet_flush(out);
  
 +      if (use_sideband && cmds_sent) {
 +              if (finish_async(&demux)) {
 +                      error("error in sideband demultiplexer");
 +                      ret = -1;
 +              }
 +              close(demux.out);
 +      }
 +
        if (ret < 0)
                return ret;
+       if (args->porcelain)
+               return 0;
        for (ref = remote_refs; ref; ref = ref->next) {
                switch (ref->status) {
                case REF_STATUS_NONE:
        return 0;
  }
  
 -static void verify_remote_names(int nr_heads, const char **heads)
 -{
 -      int i;
 -
 -      for (i = 0; i < nr_heads; i++) {
 -              const char *local = heads[i];
 -              const char *remote = strrchr(heads[i], ':');
 -
 -              if (*local == '+')
 -                      local++;
 -
 -              /* A matching refspec is okay.  */
 -              if (remote == local && remote[1] == '\0')
 -                      continue;
 -
 -              remote = remote ? (remote + 1) : local;
 -              switch (check_ref_format(remote)) {
 -              case 0: /* ok */
 -              case CHECK_REF_FORMAT_ONELEVEL:
 -                      /* ok but a single level -- that is fine for
 -                       * a match pattern.
 -                       */
 -              case CHECK_REF_FORMAT_WILDCARD:
 -                      /* ok but ends with a pattern-match character */
 -                      continue;
 -              }
 -              die("remote part of refspec is not a valid name in %s",
 -                  heads[i]);
 -      }
 -}
 -
  int cmd_send_pack(int argc, const char **argv, const char *prefix)
  {
        int i, nr_refspecs = 0;
        int send_all = 0;
        const char *receivepack = "git-receive-pack";
        int flags;
 +      int nonfastforward = 0;
  
        argv++;
        for (i = 1; i < argc; i++, argv++) {
        get_remote_heads(fd[0], &remote_refs, 0, NULL, REF_NORMAL,
                         &extra_have);
  
 -      verify_remote_names(nr_refspecs, refspecs);
 +      transport_verify_remote_names(nr_refspecs, refspecs);
  
        local_refs = get_local_heads();
  
        ret |= finish_connect(conn);
  
        if (!helper_status)
 -              print_push_status(dest, remote_refs);
 +              transport_print_push_status(dest, remote_refs, args.verbose, 0, &nonfastforward);
  
        if (!args.dry_run && remote) {
                struct ref *ref;
                for (ref = remote_refs; ref; ref = ref->next)
 -                      update_tracking_ref(remote, ref);
 +                      transport_update_tracking_ref(remote, ref, args.verbose);
        }
  
 -      if (!ret && !refs_pushed(remote_refs))
 +      if (!ret && !transport_refs_pushed(remote_refs))
                fprintf(stderr, "Everything up-to-date\n");
  
        return ret;
diff --combined transport.c
index f07bd33e86cdfb1b41d2e4d27ad1942fcf326147,260350b5a6f1eb38e3755a6be5befef66c04fa29..825be9456c79a47726a6bbf35a6efb4d42d21033
@@@ -573,7 -573,7 +573,7 @@@ static int push_had_errors(struct ref *
        return 0;
  }
  
 -static int refs_pushed(struct ref *ref)
 +int transport_refs_pushed(struct ref *ref)
  {
        for (; ref; ref = ref->next) {
                switch(ref->status) {
        return 0;
  }
  
 -static void update_tracking_ref(struct remote *remote, struct ref *ref, int verbose)
 +void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose)
  {
        struct refspec rs;
  
        }
  }
  
 -#define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
 -
  static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg, int porcelain)
  {
        if (porcelain) {
                else
                        fprintf(stdout, "%s\n", summary);
        } else {
 -              fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
 +              fprintf(stderr, " %c %-*s ", flag, TRANSPORT_SUMMARY_WIDTH, summary);
                if (from)
                        fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
                else
@@@ -673,7 -675,7 +673,7 @@@ static void print_ok_ref_status(struct 
  static int print_one_push_status(struct ref *ref, const char *dest, int count, int porcelain)
  {
        if (!count)
-               fprintf(stderr, "To %s\n", dest);
+               fprintf(porcelain ? stdout : stderr, "To %s\n", dest);
  
        switch(ref->status) {
        case REF_STATUS_NONE:
        return 1;
  }
  
 -static void print_push_status(const char *dest, struct ref *refs,
 -                            int verbose, int porcelain, int * nonfastforward)
 +void transport_print_push_status(const char *dest, struct ref *refs,
 +                                int verbose, int porcelain, int *nonfastforward)
  {
        struct ref *ref;
        int n = 0;
        }
  }
  
 -static void verify_remote_names(int nr_heads, const char **heads)
 +void transport_verify_remote_names(int nr_heads, const char **heads)
  {
        int i;
  
@@@ -789,6 -791,7 +789,7 @@@ static int git_transport_push(struct tr
        args.verbose = !!(flags & TRANSPORT_PUSH_VERBOSE);
        args.quiet = !!(flags & TRANSPORT_PUSH_QUIET);
        args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN);
+       args.porcelain = !!(flags & TRANSPORT_PUSH_PORCELAIN);
  
        ret = send_pack(&args, data->fd, data->conn, remote_refs,
                        &data->extra_have);
@@@ -870,21 -873,6 +871,21 @@@ static int is_file(const char *url
        return S_ISREG(buf.st_mode);
  }
  
 +static int isurlschemechar(int first_flag, int ch)
 +{
 +      /*
 +       * The set of valid URL schemes, as per STD66 (RFC3986) is
 +       * '[A-Za-z][A-Za-z0-9+.-]*'. But use sightly looser check
 +       * of '[A-Za-z0-9][A-Za-z0-9+.-]*' because earlier version
 +       * of check used '[A-Za-z0-9]+' so not to break any remote
 +       * helpers.
 +       */
 +      int alphanumeric, special;
 +      alphanumeric = ch > 0 && isalnum(ch);
 +      special = ch == '+' || ch == '-' || ch == '.';
 +      return alphanumeric || (!first_flag && special);
 +}
 +
  static int is_url(const char *url)
  {
        const char *url2, *first_slash;
         */
        url2 = url;
        while (url2 < first_slash - 1) {
 -              if (!isalnum((unsigned char)*url2))
 +              if (!isurlschemechar(url2 == url, (unsigned char)*url2))
                        return 0;
                url2++;
        }
@@@ -931,7 -919,6 +932,7 @@@ struct transport *transport_get(struct 
        if (!remote)
                die("No remote provided to transport_get()");
  
 +      ret->got_remote_refs = 0;
        ret->remote = remote;
        helper = remote->foreign_vcs;
  
        if (url) {
                const char *p = url;
  
 -              while (isalnum(*p))
 +              while (isurlschemechar(p == url, *p))
                        p++;
                if (!prefixcmp(p, "::"))
                        helper = xstrndup(url, p - url);
@@@ -1032,7 -1019,7 +1033,7 @@@ int transport_push(struct transport *tr
                   int *nonfastforward)
  {
        *nonfastforward = 0;
 -      verify_remote_names(refspec_nr, refspec);
 +      transport_verify_remote_names(refspec_nr, refspec);
  
        if (transport->push) {
                /* Maybe FIXME. But no important transport uses this case. */
                int quiet = flags & TRANSPORT_PUSH_QUIET;
                int porcelain = flags & TRANSPORT_PUSH_PORCELAIN;
                int pretend = flags & TRANSPORT_PUSH_DRY_RUN;
-               int ret, err;
+               int push_ret, ret, err;
  
                if (flags & TRANSPORT_PUSH_ALL)
                        match_flags |= MATCH_REFS_ALL;
                        flags & TRANSPORT_PUSH_MIRROR,
                        flags & TRANSPORT_PUSH_FORCE);
  
-               ret = transport->push_refs(transport, remote_refs, flags);
+               push_ret = transport->push_refs(transport, remote_refs, flags);
                err = push_had_errors(remote_refs);
-               ret |= err;
+               ret = push_ret | err;
  
                if (!quiet || err)
 -                      print_push_status(transport->url, remote_refs,
 +                      transport_print_push_status(transport->url, remote_refs,
                                        verbose | porcelain, porcelain,
                                        nonfastforward);
  
                if (!(flags & TRANSPORT_PUSH_DRY_RUN)) {
                        struct ref *ref;
                        for (ref = remote_refs; ref; ref = ref->next)
 -                              update_tracking_ref(transport->remote, ref, verbose);
 +                              transport_update_tracking_ref(transport->remote, ref, verbose);
                }
  
-               if (!quiet && !ret && !transport_refs_pushed(remote_refs))
+               if (porcelain && !push_ret)
+                       puts("Done");
 -              else if (!quiet && !ret && !refs_pushed(remote_refs))
++              else if (!quiet && !ret && !transport_refs_pushed(remote_refs))
                        fprintf(stderr, "Everything up-to-date\n");
                return ret;
        }
        return 1;
  
  const struct ref *transport_get_remote_refs(struct transport *transport)
  {
 -      if (!transport->remote_refs)
 +      if (!transport->got_remote_refs) {
                transport->remote_refs = transport->get_refs_list(transport, 0);
 +              transport->got_remote_refs = 1;
 +      }
  
        return transport->remote_refs;
  }