Merge branch 'maint'
[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
10 static const char push_usage[] = "git-push [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]";
11
12 static int all, dry_run, force, thin, verbose;
13 static const char *receivepack;
14
15 static const char **refspec;
16 static int refspec_nr;
17
18 static void add_refspec(const char *ref)
19 {
20         int nr = refspec_nr + 1;
21         refspec = xrealloc(refspec, nr * sizeof(char *));
22         refspec[nr-1] = ref;
23         refspec_nr = nr;
24 }
25
26 static void set_refspecs(const char **refs, int nr)
27 {
28         int i;
29         for (i = 0; i < nr; i++) {
30                 const char *ref = refs[i];
31                 if (!strcmp("tag", ref)) {
32                         char *tag;
33                         int len;
34                         if (nr <= ++i)
35                                 die("tag shorthand without <tag>");
36                         len = strlen(refs[i]) + 11;
37                         tag = xmalloc(len);
38                         strcpy(tag, "refs/tags/");
39                         strcat(tag, refs[i]);
40                         ref = tag;
41                 }
42                 add_refspec(ref);
43         }
44 }
45
46 static int do_push(const char *repo)
47 {
48         int i, errs;
49         int common_argc;
50         const char **argv;
51         int argc;
52         struct remote *remote = remote_get(repo);
53
54         if (!remote)
55                 die("bad repository '%s'", repo);
56
57         if (remote->receivepack) {
58                 char *rp = xmalloc(strlen(remote->receivepack) + 16);
59                 sprintf(rp, "--receive-pack=%s", remote->receivepack);
60                 receivepack = rp;
61         }
62         if (!refspec && !all && remote->push_refspec_nr) {
63                 refspec = remote->push_refspec;
64                 refspec_nr = remote->push_refspec_nr;
65         }
66
67         argv = xmalloc((refspec_nr + 10) * sizeof(char *));
68         argv[0] = "dummy-send-pack";
69         argc = 1;
70         if (all)
71                 argv[argc++] = "--all";
72         if (dry_run)
73                 argv[argc++] = "--dry-run";
74         if (force)
75                 argv[argc++] = "--force";
76         if (receivepack)
77                 argv[argc++] = receivepack;
78         common_argc = argc;
79
80         errs = 0;
81         for (i = 0; i < remote->uri_nr; i++) {
82                 int err;
83                 int dest_argc = common_argc;
84                 int dest_refspec_nr = refspec_nr;
85                 const char **dest_refspec = refspec;
86                 const char *dest = remote->uri[i];
87                 const char *sender = "send-pack";
88                 if (!prefixcmp(dest, "http://") ||
89                     !prefixcmp(dest, "https://"))
90                         sender = "http-push";
91                 else {
92                         char *rem = xmalloc(strlen(remote->name) + 10);
93                         sprintf(rem, "--remote=%s", remote->name);
94                         argv[dest_argc++] = rem;
95                         if (thin)
96                                 argv[dest_argc++] = "--thin";
97                 }
98                 argv[0] = sender;
99                 argv[dest_argc++] = dest;
100                 while (dest_refspec_nr--)
101                         argv[dest_argc++] = *dest_refspec++;
102                 argv[dest_argc] = NULL;
103                 if (verbose)
104                         fprintf(stderr, "Pushing to %s\n", dest);
105                 err = run_command_v_opt(argv, RUN_GIT_CMD);
106                 if (!err)
107                         continue;
108
109                 error("failed to push to '%s'", remote->uri[i]);
110                 switch (err) {
111                 case -ERR_RUN_COMMAND_FORK:
112                         error("unable to fork for %s", sender);
113                 case -ERR_RUN_COMMAND_EXEC:
114                         error("unable to exec %s", sender);
115                         break;
116                 case -ERR_RUN_COMMAND_WAITPID:
117                 case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
118                 case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
119                 case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
120                         error("%s died with strange error", sender);
121                 }
122                 errs++;
123         }
124         return !!errs;
125 }
126
127 int cmd_push(int argc, const char **argv, const char *prefix)
128 {
129         int i;
130         const char *repo = NULL;        /* default repository */
131
132         for (i = 1; i < argc; i++) {
133                 const char *arg = argv[i];
134
135                 if (arg[0] != '-') {
136                         repo = arg;
137                         i++;
138                         break;
139                 }
140                 if (!strcmp(arg, "-v")) {
141                         verbose=1;
142                         continue;
143                 }
144                 if (!prefixcmp(arg, "--repo=")) {
145                         repo = arg+7;
146                         continue;
147                 }
148                 if (!strcmp(arg, "--all")) {
149                         all = 1;
150                         continue;
151                 }
152                 if (!strcmp(arg, "--dry-run")) {
153                         dry_run = 1;
154                         continue;
155                 }
156                 if (!strcmp(arg, "--tags")) {
157                         add_refspec("refs/tags/*");
158                         continue;
159                 }
160                 if (!strcmp(arg, "--force") || !strcmp(arg, "-f")) {
161                         force = 1;
162                         continue;
163                 }
164                 if (!strcmp(arg, "--thin")) {
165                         thin = 1;
166                         continue;
167                 }
168                 if (!strcmp(arg, "--no-thin")) {
169                         thin = 0;
170                         continue;
171                 }
172                 if (!prefixcmp(arg, "--receive-pack=")) {
173                         receivepack = arg;
174                         continue;
175                 }
176                 if (!prefixcmp(arg, "--exec=")) {
177                         receivepack = arg;
178                         continue;
179                 }
180                 usage(push_usage);
181         }
182         set_refspecs(argv + i, argc - i);
183         if (all && refspec)
184                 usage(push_usage);
185
186         return do_push(repo);
187 }