builtin-push.con commit Merge branch 'jk/push-to-delete' (84d52ca)
   1/*
   2 * "git push"
   3 */
   4#include "cache.h"
   5#include "refs.h"
   6#include "run-command.h"
   7#include "builtin.h"
   8#include "remote.h"
   9#include "transport.h"
  10#include "parse-options.h"
  11
  12static const char * const push_usage[] = {
  13        "git push [<options>] [<repository> <refspec>...]",
  14        NULL,
  15};
  16
  17static int thin;
  18static int deleterefs;
  19static const char *receivepack;
  20
  21static const char **refspec;
  22static int refspec_nr;
  23
  24static void add_refspec(const char *ref)
  25{
  26        int nr = refspec_nr + 1;
  27        refspec = xrealloc(refspec, nr * sizeof(char *));
  28        refspec[nr-1] = ref;
  29        refspec_nr = nr;
  30}
  31
  32static void set_refspecs(const char **refs, int nr)
  33{
  34        int i;
  35        for (i = 0; i < nr; i++) {
  36                const char *ref = refs[i];
  37                if (!strcmp("tag", ref)) {
  38                        char *tag;
  39                        int len;
  40                        if (nr <= ++i)
  41                                die("tag shorthand without <tag>");
  42                        len = strlen(refs[i]) + 11;
  43                        if (deleterefs) {
  44                                tag = xmalloc(len+1);
  45                                strcpy(tag, ":refs/tags/");
  46                        } else {
  47                                tag = xmalloc(len);
  48                                strcpy(tag, "refs/tags/");
  49                        }
  50                        strcat(tag, refs[i]);
  51                        ref = tag;
  52                } else if (deleterefs && !strchr(ref, ':')) {
  53                        char *delref;
  54                        int len = strlen(ref)+1;
  55                        delref = xmalloc(len);
  56                        strcpy(delref, ":");
  57                        strcat(delref, ref);
  58                        ref = delref;
  59                } else if (deleterefs)
  60                        die("--delete only accepts plain target ref names");
  61                add_refspec(ref);
  62        }
  63}
  64
  65static void setup_push_tracking(void)
  66{
  67        struct strbuf refspec = STRBUF_INIT;
  68        struct branch *branch = branch_get(NULL);
  69        if (!branch)
  70                die("You are not currently on a branch.");
  71        if (!branch->merge_nr)
  72                die("The current branch %s is not tracking anything.",
  73                    branch->name);
  74        if (branch->merge_nr != 1)
  75                die("The current branch %s is tracking multiple branches, "
  76                    "refusing to push.", branch->name);
  77        strbuf_addf(&refspec, "%s:%s", branch->name, branch->merge[0]->src);
  78        add_refspec(refspec.buf);
  79}
  80
  81static void setup_default_push_refspecs(void)
  82{
  83        switch (push_default) {
  84        default:
  85        case PUSH_DEFAULT_MATCHING:
  86                add_refspec(":");
  87                break;
  88
  89        case PUSH_DEFAULT_TRACKING:
  90                setup_push_tracking();
  91                break;
  92
  93        case PUSH_DEFAULT_CURRENT:
  94                add_refspec("HEAD");
  95                break;
  96
  97        case PUSH_DEFAULT_NOTHING:
  98                die("You didn't specify any refspecs to push, and "
  99                    "push.default is \"nothing\".");
 100                break;
 101        }
 102}
 103
 104static int push_with_options(struct transport *transport, int flags)
 105{
 106        int err;
 107        int nonfastforward;
 108        if (receivepack)
 109                transport_set_option(transport,
 110                                     TRANS_OPT_RECEIVEPACK, receivepack);
 111        if (thin)
 112                transport_set_option(transport, TRANS_OPT_THIN, "yes");
 113
 114        if (flags & TRANSPORT_PUSH_VERBOSE)
 115                fprintf(stderr, "Pushing to %s\n", transport->url);
 116        err = transport_push(transport, refspec_nr, refspec, flags,
 117                             &nonfastforward);
 118        if (err != 0)
 119                error("failed to push some refs to '%s'", transport->url);
 120
 121        err |= transport_disconnect(transport);
 122
 123        if (!err)
 124                return 0;
 125
 126        if (nonfastforward && advice_push_nonfastforward) {
 127                printf("To prevent you from losing history, non-fast-forward updates were rejected\n"
 128                       "Merge the remote changes before pushing again.  See the 'non-fast-forward'\n"
 129                       "section of 'git push --help' for details.\n");
 130        }
 131
 132        return 1;
 133}
 134
 135static int do_push(const char *repo, int flags)
 136{
 137        int i, errs;
 138        struct remote *remote = remote_get(repo);
 139        const char **url;
 140        int url_nr;
 141
 142        if (!remote) {
 143                if (repo)
 144                        die("bad repository '%s'", repo);
 145                die("No destination configured to push to.");
 146        }
 147
 148        if (remote->mirror)
 149                flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
 150
 151        if ((flags & TRANSPORT_PUSH_ALL) && refspec) {
 152                if (!strcmp(*refspec, "refs/tags/*"))
 153                        return error("--all and --tags are incompatible");
 154                return error("--all can't be combined with refspecs");
 155        }
 156
 157        if ((flags & TRANSPORT_PUSH_MIRROR) && refspec) {
 158                if (!strcmp(*refspec, "refs/tags/*"))
 159                        return error("--mirror and --tags are incompatible");
 160                return error("--mirror can't be combined with refspecs");
 161        }
 162
 163        if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) ==
 164                                (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) {
 165                return error("--all and --mirror are incompatible");
 166        }
 167
 168        if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) {
 169                if (remote->push_refspec_nr) {
 170                        refspec = remote->push_refspec;
 171                        refspec_nr = remote->push_refspec_nr;
 172                } else if (!(flags & TRANSPORT_PUSH_MIRROR))
 173                        setup_default_push_refspecs();
 174        }
 175        errs = 0;
 176        if (remote->pushurl_nr) {
 177                url = remote->pushurl;
 178                url_nr = remote->pushurl_nr;
 179        } else {
 180                url = remote->url;
 181                url_nr = remote->url_nr;
 182        }
 183        if (url_nr) {
 184                for (i = 0; i < url_nr; i++) {
 185                        struct transport *transport =
 186                                transport_get(remote, url[i]);
 187                        if (push_with_options(transport, flags))
 188                                errs++;
 189                }
 190        } else {
 191                struct transport *transport =
 192                        transport_get(remote, NULL);
 193
 194                if (push_with_options(transport, flags))
 195                        errs++;
 196        }
 197        return !!errs;
 198}
 199
 200int cmd_push(int argc, const char **argv, const char *prefix)
 201{
 202        int flags = 0;
 203        int tags = 0;
 204        int rc;
 205        const char *repo = NULL;        /* default repository */
 206        struct option options[] = {
 207                OPT_BIT('q', "quiet", &flags, "be quiet", TRANSPORT_PUSH_QUIET),
 208                OPT_BIT('v', "verbose", &flags, "be verbose", TRANSPORT_PUSH_VERBOSE),
 209                OPT_STRING( 0 , "repo", &repo, "repository", "repository"),
 210                OPT_BIT( 0 , "all", &flags, "push all refs", TRANSPORT_PUSH_ALL),
 211                OPT_BIT( 0 , "mirror", &flags, "mirror all refs",
 212                            (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
 213                OPT_BOOLEAN( 0, "delete", &deleterefs, "delete refs"),
 214                OPT_BOOLEAN( 0 , "tags", &tags, "push tags (can't be used with --all or --mirror)"),
 215                OPT_BIT('n' , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN),
 216                OPT_BIT( 0,  "porcelain", &flags, "machine-readable output", TRANSPORT_PUSH_PORCELAIN),
 217                OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE),
 218                OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
 219                OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),
 220                OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"),
 221                OPT_END()
 222        };
 223
 224        git_config(git_default_config, NULL);
 225        argc = parse_options(argc, argv, prefix, options, push_usage, 0);
 226
 227        if (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR))))
 228                die("--delete is incompatible with --all, --mirror and --tags");
 229        if (deleterefs && argc < 2)
 230                die("--delete doesn't make sense without any refs");
 231
 232        if (tags)
 233                add_refspec("refs/tags/*");
 234
 235        if (argc > 0) {
 236                repo = argv[0];
 237                set_refspecs(argv + 1, argc - 1);
 238        }
 239
 240        rc = do_push(repo, flags);
 241        if (rc == -1)
 242                usage_with_options(push_usage, options);
 243        else
 244                return rc;
 245}