Allow push and fetch urls to be different
[git/mingw/4msysgit.git] / builtin-push.c
blob7be12399b6d95c63efd9102df7967dca61655063
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"
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,
17 static int thin;
18 static const char *receivepack;
20 static const char **refspec;
21 static int refspec_nr;
23 static void add_refspec(const char *ref)
25 int nr = refspec_nr + 1;
26 refspec = xrealloc(refspec, nr * sizeof(char *));
27 refspec[nr-1] = ref;
28 refspec_nr = nr;
31 static void set_refspecs(const char **refs, int nr)
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;
47 add_refspec(ref);
51 static void setup_push_tracking(void)
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);
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"
82 static void warn_unconfigured_push(void)
84 int i;
85 for (i = 0; i < ARRAY_SIZE(warn_unconfigured_push_msg); i++)
86 warning("%s", warn_unconfigured_push_msg[i]);
89 static void setup_default_push_refspecs(void)
91 git_config(git_default_config, NULL);
92 switch (push_default) {
93 case PUSH_DEFAULT_UNSPECIFIED:
94 warn_unconfigured_push();
95 /* fallthrough */
97 case PUSH_DEFAULT_MATCHING:
98 add_refspec(":");
99 break;
101 case PUSH_DEFAULT_TRACKING:
102 setup_push_tracking();
103 break;
105 case PUSH_DEFAULT_CURRENT:
106 add_refspec("HEAD");
107 break;
109 case PUSH_DEFAULT_NOTHING:
110 die("You didn't specify any refspecs to push, and "
111 "push.default is \"nothing\".");
112 break;
116 static int do_push(const char *repo, int flags)
118 int i, errs;
119 struct remote *remote = remote_get(repo);
120 const char **url;
121 int url_nr;
123 if (!remote) {
124 if (repo)
125 die("bad repository '%s'", repo);
126 die("No destination configured to push to.");
129 if (remote->mirror)
130 flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
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");
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");
144 if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) ==
145 (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) {
146 return error("--all and --mirror are incompatible");
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();
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;
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");
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);
179 if (!err)
180 continue;
182 error("failed to push some refs to '%s'", url[i]);
183 errs++;
185 return !!errs;
188 int cmd_push(int argc, const char **argv, const char *prefix)
190 int flags = 0;
191 int tags = 0;
192 int rc;
193 const char *repo = NULL; /* default repository */
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()
210 argc = parse_options(argc, argv, prefix, options, push_usage, 0);
212 if (tags)
213 add_refspec("refs/tags/*");
215 if (argc > 0) {
216 repo = argv[0];
217 set_refspecs(argv + 1, argc - 1);
220 rc = do_push(repo, flags);
221 if (rc == -1)
222 usage_with_options(push_usage, options);
223 else
224 return rc;