Merge branch 'jk/terse-push' into aw/mirror-push
[git] / builtin-push.c
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
11 static const char push_usage[] = "git-push [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]";
12
13 static int thin, verbose;
14 static const char *receivepack;
15
16 static const char **refspec;
17 static int refspec_nr;
18
19 static void add_refspec(const char *ref)
20 {
21         int nr = refspec_nr + 1;
22         refspec = xrealloc(refspec, nr * sizeof(char *));
23         refspec[nr-1] = ref;
24         refspec_nr = nr;
25 }
26
27 static void set_refspecs(const char **refs, int nr)
28 {
29         int i;
30         for (i = 0; i < nr; i++) {
31                 const char *ref = refs[i];
32                 if (!strcmp("tag", ref)) {
33                         char *tag;
34                         int len;
35                         if (nr <= ++i)
36                                 die("tag shorthand without <tag>");
37                         len = strlen(refs[i]) + 11;
38                         tag = xmalloc(len);
39                         strcpy(tag, "refs/tags/");
40                         strcat(tag, refs[i]);
41                         ref = tag;
42                 }
43                 add_refspec(ref);
44         }
45 }
46
47 static int do_push(const char *repo, int flags)
48 {
49         int i, errs;
50         struct remote *remote = remote_get(repo);
51
52         if (!remote)
53                 die("bad repository '%s'", repo);
54
55         if (!refspec
56                 && !(flags & TRANSPORT_PUSH_ALL)
57                 && remote->push_refspec_nr) {
58                 refspec = remote->push_refspec;
59                 refspec_nr = remote->push_refspec_nr;
60         }
61         errs = 0;
62         for (i = 0; i < remote->url_nr; i++) {
63                 struct transport *transport =
64                         transport_get(remote, remote->url[i]);
65                 int err;
66                 if (receivepack)
67                         transport_set_option(transport,
68                                              TRANS_OPT_RECEIVEPACK, receivepack);
69                 if (thin)
70                         transport_set_option(transport, TRANS_OPT_THIN, "yes");
71
72                 if (verbose)
73                         fprintf(stderr, "Pushing to %s\n", remote->url[i]);
74                 err = transport_push(transport, refspec_nr, refspec, flags);
75                 err |= transport_disconnect(transport);
76
77                 if (!err)
78                         continue;
79
80                 error("failed to push to '%s'", remote->url[i]);
81                 errs++;
82         }
83         return !!errs;
84 }
85
86 int cmd_push(int argc, const char **argv, const char *prefix)
87 {
88         int i;
89         int flags = 0;
90         const char *repo = NULL;        /* default repository */
91
92         for (i = 1; i < argc; i++) {
93                 const char *arg = argv[i];
94
95                 if (arg[0] != '-') {
96                         repo = arg;
97                         i++;
98                         break;
99                 }
100                 if (!strcmp(arg, "-v")) {
101                         verbose=1;
102                         continue;
103                 }
104                 if (!prefixcmp(arg, "--repo=")) {
105                         repo = arg+7;
106                         continue;
107                 }
108                 if (!strcmp(arg, "--all")) {
109                         flags |= TRANSPORT_PUSH_ALL;
110                         continue;
111                 }
112                 if (!strcmp(arg, "--dry-run")) {
113                         flags |= TRANSPORT_PUSH_DRY_RUN;
114                         continue;
115                 }
116                 if (!strcmp(arg, "--tags")) {
117                         add_refspec("refs/tags/*");
118                         continue;
119                 }
120                 if (!strcmp(arg, "--force") || !strcmp(arg, "-f")) {
121                         flags |= TRANSPORT_PUSH_FORCE;
122                         continue;
123                 }
124                 if (!strcmp(arg, "--thin")) {
125                         thin = 1;
126                         continue;
127                 }
128                 if (!strcmp(arg, "--no-thin")) {
129                         thin = 0;
130                         continue;
131                 }
132                 if (!prefixcmp(arg, "--receive-pack=")) {
133                         receivepack = arg + 15;
134                         continue;
135                 }
136                 if (!prefixcmp(arg, "--exec=")) {
137                         receivepack = arg + 7;
138                         continue;
139                 }
140                 usage(push_usage);
141         }
142         set_refspecs(argv + i, argc - i);
143         if ((flags & TRANSPORT_PUSH_ALL) && refspec)
144                 usage(push_usage);
145
146         return do_push(repo, flags);
147 }