Merge branch 'fg/push-default'
[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
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
179 int 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 }