MinGW: truncate exit()'s argument to lowest 8 bits
[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 #include "parse-options.h"
11
12 static const char * const push_usage[] = {
13         "git push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]",
14         NULL,
15 };
16
17 static int thin;
18 static const char *receivepack;
19
20 static const char **refspec;
21 static int refspec_nr;
22
23 static void add_refspec(const char *ref)
24 {
25         int nr = refspec_nr + 1;
26         refspec = xrealloc(refspec, nr * sizeof(char *));
27         refspec[nr-1] = ref;
28         refspec_nr = nr;
29 }
30
31 static void set_refspecs(const char **refs, int nr)
32 {
33         int i;
34         for (i = 0; i < nr; i++) {
35                 const char *ref = refs[i];
36                 if (!strcmp("tag", ref)) {
37                         char *tag;
38                         int len;
39                         if (nr <= ++i)
40                                 die("tag shorthand without <tag>");
41                         len = strlen(refs[i]) + 11;
42                         tag = xmalloc(len);
43                         strcpy(tag, "refs/tags/");
44                         strcat(tag, refs[i]);
45                         ref = tag;
46                 }
47                 add_refspec(ref);
48         }
49 }
50
51 static void setup_push_tracking(void)
52 {
53         struct strbuf refspec = STRBUF_INIT;
54         struct branch *branch = branch_get(NULL);
55         if (!branch)
56                 die("You are not currently on a branch.");
57         if (!branch->merge_nr)
58                 die("The current branch %s is not tracking anything.",
59                     branch->name);
60         if (branch->merge_nr != 1)
61                 die("The current branch %s is tracking multiple branches, "
62                     "refusing to push.", branch->name);
63         strbuf_addf(&refspec, "%s:%s", branch->name, branch->merge[0]->src);
64         add_refspec(refspec.buf);
65 }
66
67 static const char *warn_unconfigured_push_msg[] = {
68         "You did not specify any refspecs to push, and the current remote",
69         "has not configured any push refspecs. The default action in this",
70         "case is to push all matching refspecs, that is, all branches",
71         "that exist both locally and remotely will be updated.  This may",
72         "not necessarily be what you want to happen.",
73         "",
74         "You can specify what action you want to take in this case, and",
75         "avoid seeing this message again, by configuring 'push.default' to:",
76         "  'nothing'  : Do not push anything",
77         "  'matching' : Push all matching branches (default)",
78         "  'tracking' : Push the current branch to whatever it is tracking",
79         "  'current'  : Push the current branch"
80 };
81
82 static void warn_unconfigured_push(void)
83 {
84         int i;
85         for (i = 0; i < ARRAY_SIZE(warn_unconfigured_push_msg); i++)
86                 warning("%s", warn_unconfigured_push_msg[i]);
87 }
88
89 static void setup_default_push_refspecs(void)
90 {
91         git_config(git_default_config, NULL);
92         switch (push_default) {
93         case PUSH_DEFAULT_UNSPECIFIED:
94                 warn_unconfigured_push();
95                 /* fallthrough */
96
97         case PUSH_DEFAULT_MATCHING:
98                 add_refspec(":");
99                 break;
100
101         case PUSH_DEFAULT_TRACKING:
102                 setup_push_tracking();
103                 break;
104
105         case PUSH_DEFAULT_CURRENT:
106                 add_refspec("HEAD");
107                 break;
108
109         case PUSH_DEFAULT_NOTHING:
110                 die("You didn't specify any refspecs to push, and "
111                     "push.default is \"nothing\".");
112                 break;
113         }
114 }
115
116 static int do_push(const char *repo, int flags)
117 {
118         int i, errs;
119         struct remote *remote = remote_get(repo);
120         const char **url;
121         int url_nr;
122
123         if (!remote) {
124                 if (repo)
125                         die("bad repository '%s'", repo);
126                 die("No destination configured to push to.");
127         }
128
129         if (remote->mirror)
130                 flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
131
132         if ((flags & TRANSPORT_PUSH_ALL) && refspec) {
133                 if (!strcmp(*refspec, "refs/tags/*"))
134                         return error("--all and --tags are incompatible");
135                 return error("--all can't be combined with refspecs");
136         }
137
138         if ((flags & TRANSPORT_PUSH_MIRROR) && refspec) {
139                 if (!strcmp(*refspec, "refs/tags/*"))
140                         return error("--mirror and --tags are incompatible");
141                 return error("--mirror can't be combined with refspecs");
142         }
143
144         if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) ==
145                                 (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) {
146                 return error("--all and --mirror are incompatible");
147         }
148
149         if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) {
150                 if (remote->push_refspec_nr) {
151                         refspec = remote->push_refspec;
152                         refspec_nr = remote->push_refspec_nr;
153                 } else if (!(flags & TRANSPORT_PUSH_MIRROR))
154                         setup_default_push_refspecs();
155         }
156         errs = 0;
157         if (remote->pushurl_nr) {
158                 url = remote->pushurl;
159                 url_nr = remote->pushurl_nr;
160         } else {
161                 url = remote->url;
162                 url_nr = remote->url_nr;
163         }
164         for (i = 0; i < url_nr; i++) {
165                 struct transport *transport =
166                         transport_get(remote, url[i]);
167                 int err;
168                 if (receivepack)
169                         transport_set_option(transport,
170                                              TRANS_OPT_RECEIVEPACK, receivepack);
171                 if (thin)
172                         transport_set_option(transport, TRANS_OPT_THIN, "yes");
173
174                 if (flags & TRANSPORT_PUSH_VERBOSE)
175                         fprintf(stderr, "Pushing to %s\n", url[i]);
176                 err = transport_push(transport, refspec_nr, refspec, flags);
177                 err |= transport_disconnect(transport);
178
179                 if (!err)
180                         continue;
181
182                 error("failed to push some refs to '%s'", url[i]);
183                 errs++;
184         }
185         return !!errs;
186 }
187
188 int cmd_push(int argc, const char **argv, const char *prefix)
189 {
190         int flags = 0;
191         int tags = 0;
192         int rc;
193         const char *repo = NULL;        /* default repository */
194
195         struct option options[] = {
196                 OPT_BIT('v', "verbose", &flags, "be verbose", TRANSPORT_PUSH_VERBOSE),
197                 OPT_STRING( 0 , "repo", &repo, "repository", "repository"),
198                 OPT_BIT( 0 , "all", &flags, "push all refs", TRANSPORT_PUSH_ALL),
199                 OPT_BIT( 0 , "mirror", &flags, "mirror all refs",
200                             (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
201                 OPT_BOOLEAN( 0 , "tags", &tags, "push tags"),
202                 OPT_BIT( 0 , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN),
203                 OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE),
204                 OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
205                 OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),
206                 OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"),
207                 OPT_END()
208         };
209
210         argc = parse_options(argc, argv, prefix, options, push_usage, 0);
211
212         if (tags)
213                 add_refspec("refs/tags/*");
214
215         if (argc > 0) {
216                 repo = argv[0];
217                 set_refspecs(argv + 1, argc - 1);
218         }
219
220         rc = do_push(repo, flags);
221         if (rc == -1)
222                 usage_with_options(push_usage, options);
223         else
224                 return rc;
225 }