Code

builtin-push.c: Fix typo: "anythig" -> "anything"
[git.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"
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 };
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)
24 {
25         int nr = refspec_nr + 1;
26         refspec = xrealloc(refspec, nr * sizeof(char *));
27         refspec[nr-1] = ref;
28         refspec_nr = nr;
29 }
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 }
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 }
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 };
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 }
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 */
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;
113         }
116 static int do_push(const char *repo, int flags)
118         int i, errs;
119         struct remote *remote = remote_get(repo);
121         if (!remote)
122                 die("bad repository '%s'", repo);
124         if (remote->mirror)
125                 flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
127         if ((flags & TRANSPORT_PUSH_ALL) && refspec) {
128                 if (!strcmp(*refspec, "refs/tags/*"))
129                         return error("--all and --tags are incompatible");
130                 return error("--all can't be combined with refspecs");
131         }
133         if ((flags & TRANSPORT_PUSH_MIRROR) && refspec) {
134                 if (!strcmp(*refspec, "refs/tags/*"))
135                         return error("--mirror and --tags are incompatible");
136                 return error("--mirror can't be combined with refspecs");
137         }
139         if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) ==
140                                 (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) {
141                 return error("--all and --mirror are incompatible");
142         }
144         if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) {
145                 if (remote->push_refspec_nr) {
146                         refspec = remote->push_refspec;
147                         refspec_nr = remote->push_refspec_nr;
148                 } else if (!(flags & TRANSPORT_PUSH_MIRROR))
149                         setup_default_push_refspecs();
150         }
151         errs = 0;
152         for (i = 0; i < remote->url_nr; i++) {
153                 struct transport *transport =
154                         transport_get(remote, remote->url[i]);
155                 int err;
156                 if (receivepack)
157                         transport_set_option(transport,
158                                              TRANS_OPT_RECEIVEPACK, receivepack);
159                 if (thin)
160                         transport_set_option(transport, TRANS_OPT_THIN, "yes");
162                 if (flags & TRANSPORT_PUSH_VERBOSE)
163                         fprintf(stderr, "Pushing to %s\n", remote->url[i]);
164                 err = transport_push(transport, refspec_nr, refspec, flags);
165                 err |= transport_disconnect(transport);
167                 if (!err)
168                         continue;
170                 error("failed to push some refs to '%s'", remote->url[i]);
171                 errs++;
172         }
173         return !!errs;
176 int cmd_push(int argc, const char **argv, const char *prefix)
178         int flags = 0;
179         int tags = 0;
180         int rc;
181         const char *repo = NULL;        /* default repository */
183         struct option options[] = {
184                 OPT_BIT('v', "verbose", &flags, "be verbose", TRANSPORT_PUSH_VERBOSE),
185                 OPT_STRING( 0 , "repo", &repo, "repository", "repository"),
186                 OPT_BIT( 0 , "all", &flags, "push all refs", TRANSPORT_PUSH_ALL),
187                 OPT_BIT( 0 , "mirror", &flags, "mirror all refs",
188                             (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
189                 OPT_BOOLEAN( 0 , "tags", &tags, "push tags"),
190                 OPT_BIT( 0 , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN),
191                 OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE),
192                 OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
193                 OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),
194                 OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"),
195                 OPT_END()
196         };
198         argc = parse_options(argc, argv, options, push_usage, 0);
200         if (tags)
201                 add_refspec("refs/tags/*");
203         if (argc > 0) {
204                 repo = argv[0];
205                 set_refspecs(argv + 1, argc - 1);
206         }
208         rc = do_push(repo, flags);
209         if (rc == -1)
210                 usage_with_options(push_usage, options);
211         else
212                 return rc;