6 #include "run-command.h"
10 static const char push_usage[] = "git-push [--all] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]";
12 static int all, tags, force, thin = 1, verbose;
13 static const char *receivepack;
15 static const char **refspec;
16 static int refspec_nr;
18 static void add_refspec(const char *ref)
20 int nr = refspec_nr + 1;
21 refspec = xrealloc(refspec, nr * sizeof(char *));
26 static int expand_one_ref(const char *ref, const unsigned char *sha1, int flag, void *cb_data)
28 /* Ignore the "refs/" at the beginning of the refname */
31 if (!prefixcmp(ref, "tags/"))
32 add_refspec(xstrdup(ref));
36 static void expand_refspecs(void)
40 die("cannot mix '--all' and a refspec");
43 * No need to expand "--all" - we'll just use
44 * the "--all" flag to send-pack
50 for_each_ref(expand_one_ref, NULL);
54 const char *from_prefix;
56 const char *to_prefix;
61 static int expand_wildcard_ref(const char *ref, const unsigned char *sha1, int flag, void *cb_data)
63 struct wildcard_cb *cb = cb_data;
64 int len = strlen(ref);
65 char *expanded, *newref;
67 if (len < cb->from_prefix_len ||
68 memcmp(cb->from_prefix, ref, cb->from_prefix_len))
70 expanded = xmalloc(len * 2 + cb->force +
71 (cb->to_prefix_len - cb->from_prefix_len) + 2);
72 newref = expanded + cb->force;
75 memcpy(newref, ref, len);
77 memcpy(newref + len + 1, cb->to_prefix, cb->to_prefix_len);
78 strcpy(newref + len + 1 + cb->to_prefix_len,
79 ref + cb->from_prefix_len);
80 add_refspec(expanded);
84 static int wildcard_ref(const char *ref)
88 struct wildcard_cb cb;
90 memset(&cb, 0, sizeof(cb));
96 colon = strchr(ref, ':');
97 if (! (colon && ref < colon &&
98 colon[-2] == '/' && colon[-1] == '*' &&
99 /* "<mine>/<asterisk>:<yours>/<asterisk>" is at least 7 bytes */
101 ref[len-2] == '/' && ref[len-1] == '*') )
103 cb.from_prefix = ref;
104 cb.from_prefix_len = colon - ref - 1;
105 cb.to_prefix = colon + 1;
106 cb.to_prefix_len = len - (colon - ref) - 2;
107 for_each_ref(expand_wildcard_ref, &cb);
111 static void set_refspecs(const char **refs, int nr)
115 for (i = 0; i < nr; i++) {
116 const char *ref = refs[i];
117 if (!strcmp("tag", ref)) {
121 die("tag shorthand without <tag>");
122 len = strlen(refs[i]) + 11;
124 strcpy(tag, "refs/tags/");
125 strcat(tag, refs[i]);
128 else if (wildcard_ref(ref))
136 static int do_push(const char *repo)
142 struct remote *remote = remote_get(repo);
145 die("bad repository '%s'", repo);
147 if (remote->receivepack) {
148 char *rp = xmalloc(strlen(remote->receivepack) + 16);
149 sprintf(rp, "--receive-pack=%s", remote->receivepack);
152 if (!refspec && !all && !tags && remote->push_refspec_nr) {
153 for (i = 0; i < remote->push_refspec_nr; i++) {
154 if (!wildcard_ref(remote->push_refspec[i]))
155 add_refspec(remote->push_refspec[i]);
159 argv = xmalloc((refspec_nr + 10) * sizeof(char *));
160 argv[0] = "dummy-send-pack";
163 argv[argc++] = "--all";
165 argv[argc++] = "--force";
167 argv[argc++] = receivepack;
171 for (i = 0; i < remote->uri_nr; i++) {
173 int dest_argc = common_argc;
174 int dest_refspec_nr = refspec_nr;
175 const char **dest_refspec = refspec;
176 const char *dest = remote->uri[i];
177 const char *sender = "send-pack";
178 if (!prefixcmp(dest, "http://") ||
179 !prefixcmp(dest, "https://"))
180 sender = "http-push";
182 char *rem = xmalloc(strlen(remote->name) + 10);
183 sprintf(rem, "--remote=%s", remote->name);
184 argv[dest_argc++] = rem;
186 argv[dest_argc++] = "--thin";
189 argv[dest_argc++] = dest;
190 while (dest_refspec_nr--)
191 argv[dest_argc++] = *dest_refspec++;
192 argv[dest_argc] = NULL;
194 fprintf(stderr, "Pushing to %s\n", dest);
195 err = run_command_v_opt(argv, RUN_GIT_CMD);
199 error("failed to push to '%s'", remote->uri[i]);
201 case -ERR_RUN_COMMAND_FORK:
202 error("unable to fork for %s", sender);
203 case -ERR_RUN_COMMAND_EXEC:
204 error("unable to exec %s", sender);
206 case -ERR_RUN_COMMAND_WAITPID:
207 case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
208 case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
209 case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
210 error("%s died with strange error", sender);
217 int cmd_push(int argc, const char **argv, const char *prefix)
220 const char *repo = NULL; /* default repository */
222 for (i = 1; i < argc; i++) {
223 const char *arg = argv[i];
230 if (!strcmp(arg, "-v")) {
234 if (!prefixcmp(arg, "--repo=")) {
238 if (!strcmp(arg, "--all")) {
242 if (!strcmp(arg, "--tags")) {
246 if (!strcmp(arg, "--force") || !strcmp(arg, "-f")) {
250 if (!strcmp(arg, "--thin")) {
254 if (!strcmp(arg, "--no-thin")) {
258 if (!prefixcmp(arg, "--receive-pack=")) {
262 if (!prefixcmp(arg, "--exec=")) {
268 set_refspecs(argv + i, argc - i);
269 return do_push(repo);