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 [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]",
14 NULL,
15};
16
17static int thin;
18static const char *receivepack;
19
20static const char **refspec;
21static int refspec_nr;
22
23static 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
31static 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
51static 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
67static 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
82static 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
89static 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
116static int do_push(const char *repo, int flags)
117{
118 int i, errs;
119 struct remote *remote = remote_get(repo);
120
121 if (!remote) {
122 if (repo)
123 die("bad repository '%s'", repo);
124 die("No destination configured to push to.");
125 }
126
127 if (remote->mirror)
128 flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
129
130 if ((flags & TRANSPORT_PUSH_ALL) && refspec) {
131 if (!strcmp(*refspec, "refs/tags/*"))
132 return error("--all and --tags are incompatible");
133 return error("--all can't be combined with refspecs");
134 }
135
136 if ((flags & TRANSPORT_PUSH_MIRROR) && refspec) {
137 if (!strcmp(*refspec, "refs/tags/*"))
138 return error("--mirror and --tags are incompatible");
139 return error("--mirror can't be combined with refspecs");
140 }
141
142 if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) ==
143 (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) {
144 return error("--all and --mirror are incompatible");
145 }
146
147 if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) {
148 if (remote->push_refspec_nr) {
149 refspec = remote->push_refspec;
150 refspec_nr = remote->push_refspec_nr;
151 } else if (!(flags & TRANSPORT_PUSH_MIRROR))
152 setup_default_push_refspecs();
153 }
154 errs = 0;
155 for (i = 0; i < remote->url_nr; i++) {
156 struct transport *transport =
157 transport_get(remote, remote->url[i]);
158 int err;
159 if (receivepack)
160 transport_set_option(transport,
161 TRANS_OPT_RECEIVEPACK, receivepack);
162 if (thin)
163 transport_set_option(transport, TRANS_OPT_THIN, "yes");
164
165 if (flags & TRANSPORT_PUSH_VERBOSE)
166 fprintf(stderr, "Pushing to %s\n", remote->url[i]);
167 err = transport_push(transport, refspec_nr, refspec, flags);
168 err |= transport_disconnect(transport);
169
170 if (!err)
171 continue;
172
173 error("failed to push some refs to '%s'", remote->url[i]);
174 errs++;
175 }
176 return !!errs;
177}
178
179int cmd_push(int argc, const char **argv, const char *prefix)
180{
181 int flags = 0;
182 int tags = 0;
183 int rc;
184 const char *repo = NULL; /* default repository */
185
186 struct option options[] = {
187 OPT_BIT('v', "verbose", &flags, "be verbose", TRANSPORT_PUSH_VERBOSE),
188 OPT_STRING( 0 , "repo", &repo, "repository", "repository"),
189 OPT_BIT( 0 , "all", &flags, "push all refs", TRANSPORT_PUSH_ALL),
190 OPT_BIT( 0 , "mirror", &flags, "mirror all refs",
191 (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
192 OPT_BOOLEAN( 0 , "tags", &tags, "push tags"),
193 OPT_BIT( 0 , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN),
194 OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE),
195 OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
196 OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),
197 OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"),
198 OPT_END()
199 };
200
201 argc = parse_options(argc, argv, options, push_usage, 0);
202
203 if (tags)
204 add_refspec("refs/tags/*");
205
206 if (argc > 0) {
207 repo = argv[0];
208 set_refspecs(argv + 1, argc - 1);
209 }
210
211 rc = do_push(repo, flags);
212 if (rc == -1)
213 usage_with_options(push_usage, options);
214 else
215 return rc;
216}