]>
Commit | Line | Data |
---|---|---|
755225de LT |
1 | /* |
2 | * "git push" | |
3 | */ | |
4 | #include "cache.h" | |
5 | #include "refs.h" | |
6 | #include "run-command.h" | |
7 | #include "builtin.h" | |
5751f490 | 8 | #include "remote.h" |
755225de | 9 | |
d23842fd | 10 | static const char push_usage[] = "git-push [--all] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]"; |
755225de | 11 | |
bcc785f6 | 12 | static int all, tags, force, thin = 1, verbose; |
d23842fd | 13 | static const char *receivepack; |
755225de | 14 | |
96f1e58f DR |
15 | static const char **refspec; |
16 | static int refspec_nr; | |
755225de LT |
17 | |
18 | static void add_refspec(const char *ref) | |
19 | { | |
20 | int nr = refspec_nr + 1; | |
21 | refspec = xrealloc(refspec, nr * sizeof(char *)); | |
22 | refspec[nr-1] = ref; | |
23 | refspec_nr = nr; | |
24 | } | |
25 | ||
8da19775 | 26 | static int expand_one_ref(const char *ref, const unsigned char *sha1, int flag, void *cb_data) |
755225de LT |
27 | { |
28 | /* Ignore the "refs/" at the beginning of the refname */ | |
29 | ref += 5; | |
30 | ||
cc44c765 | 31 | if (!prefixcmp(ref, "tags/")) |
9befac47 | 32 | add_refspec(xstrdup(ref)); |
755225de LT |
33 | return 0; |
34 | } | |
35 | ||
36 | static void expand_refspecs(void) | |
37 | { | |
38 | if (all) { | |
39 | if (refspec_nr) | |
40 | die("cannot mix '--all' and a refspec"); | |
41 | ||
42 | /* | |
43 | * No need to expand "--all" - we'll just use | |
44 | * the "--all" flag to send-pack | |
45 | */ | |
46 | return; | |
47 | } | |
48 | if (!tags) | |
49 | return; | |
cb5d709f | 50 | for_each_ref(expand_one_ref, NULL); |
755225de LT |
51 | } |
52 | ||
d46ae3f0 JH |
53 | struct wildcard_cb { |
54 | const char *from_prefix; | |
55 | int from_prefix_len; | |
56 | const char *to_prefix; | |
57 | int to_prefix_len; | |
58 | int force; | |
59 | }; | |
60 | ||
61 | static int expand_wildcard_ref(const char *ref, const unsigned char *sha1, int flag, void *cb_data) | |
62 | { | |
63 | struct wildcard_cb *cb = cb_data; | |
64 | int len = strlen(ref); | |
65 | char *expanded, *newref; | |
66 | ||
67 | if (len < cb->from_prefix_len || | |
68 | memcmp(cb->from_prefix, ref, cb->from_prefix_len)) | |
69 | return 0; | |
70 | expanded = xmalloc(len * 2 + cb->force + | |
71 | (cb->to_prefix_len - cb->from_prefix_len) + 2); | |
72 | newref = expanded + cb->force; | |
73 | if (cb->force) | |
74 | expanded[0] = '+'; | |
75 | memcpy(newref, ref, len); | |
76 | newref[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); | |
81 | return 0; | |
82 | } | |
83 | ||
84 | static int wildcard_ref(const char *ref) | |
85 | { | |
86 | int len; | |
87 | const char *colon; | |
88 | struct wildcard_cb cb; | |
89 | ||
90 | memset(&cb, 0, sizeof(cb)); | |
91 | if (ref[0] == '+') { | |
92 | cb.force = 1; | |
93 | ref++; | |
94 | } | |
95 | len = strlen(ref); | |
96 | colon = strchr(ref, ':'); | |
97 | if (! (colon && ref < colon && | |
98 | colon[-2] == '/' && colon[-1] == '*' && | |
99 | /* "<mine>/<asterisk>:<yours>/<asterisk>" is at least 7 bytes */ | |
100 | 7 <= len && | |
101 | ref[len-2] == '/' && ref[len-1] == '*') ) | |
102 | return 0 ; | |
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); | |
108 | return 1; | |
109 | } | |
110 | ||
755225de LT |
111 | static void set_refspecs(const char **refs, int nr) |
112 | { | |
113 | if (nr) { | |
d46ae3f0 JH |
114 | int i; |
115 | for (i = 0; i < nr; i++) { | |
116 | const char *ref = refs[i]; | |
117 | if (!strcmp("tag", ref)) { | |
118 | char *tag; | |
119 | int len; | |
120 | if (nr <= ++i) | |
121 | die("tag shorthand without <tag>"); | |
122 | len = strlen(refs[i]) + 11; | |
123 | tag = xmalloc(len); | |
124 | strcpy(tag, "refs/tags/"); | |
125 | strcat(tag, refs[i]); | |
126 | ref = tag; | |
411fb8ba | 127 | } |
d46ae3f0 JH |
128 | else if (wildcard_ref(ref)) |
129 | continue; | |
130 | add_refspec(ref); | |
411fb8ba | 131 | } |
755225de LT |
132 | } |
133 | expand_refspecs(); | |
134 | } | |
135 | ||
755225de LT |
136 | static int do_push(const char *repo) |
137 | { | |
5751f490 | 138 | int i, errs; |
441c823e | 139 | int common_argc; |
755225de LT |
140 | const char **argv; |
141 | int argc; | |
5751f490 | 142 | struct remote *remote = remote_get(repo); |
755225de | 143 | |
5751f490 | 144 | if (!remote) |
755225de LT |
145 | die("bad repository '%s'", repo); |
146 | ||
5751f490 DB |
147 | if (remote->receivepack) { |
148 | char *rp = xmalloc(strlen(remote->receivepack) + 16); | |
149 | sprintf(rp, "--receive-pack=%s", remote->receivepack); | |
150 | receivepack = rp; | |
151 | } | |
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]); | |
156 | } | |
157 | } | |
158 | ||
755225de LT |
159 | argv = xmalloc((refspec_nr + 10) * sizeof(char *)); |
160 | argv[0] = "dummy-send-pack"; | |
161 | argc = 1; | |
162 | if (all) | |
163 | argv[argc++] = "--all"; | |
164 | if (force) | |
165 | argv[argc++] = "--force"; | |
d23842fd UKK |
166 | if (receivepack) |
167 | argv[argc++] = receivepack; | |
441c823e | 168 | common_argc = argc; |
755225de | 169 | |
fd1d1b05 | 170 | errs = 0; |
5751f490 | 171 | for (i = 0; i < remote->uri_nr; i++) { |
60b7f38e | 172 | int err; |
441c823e NH |
173 | int dest_argc = common_argc; |
174 | int dest_refspec_nr = refspec_nr; | |
175 | const char **dest_refspec = refspec; | |
5751f490 | 176 | const char *dest = remote->uri[i]; |
df91ba36 | 177 | const char *sender = "send-pack"; |
cc44c765 JH |
178 | if (!prefixcmp(dest, "http://") || |
179 | !prefixcmp(dest, "https://")) | |
df91ba36 | 180 | sender = "http-push"; |
b516968f DB |
181 | else { |
182 | char *rem = xmalloc(strlen(remote->name) + 10); | |
183 | sprintf(rem, "--remote=%s", remote->name); | |
184 | argv[dest_argc++] = rem; | |
185 | if (thin) | |
186 | argv[dest_argc++] = "--thin"; | |
187 | } | |
755225de | 188 | argv[0] = sender; |
441c823e NH |
189 | argv[dest_argc++] = dest; |
190 | while (dest_refspec_nr--) | |
191 | argv[dest_argc++] = *dest_refspec++; | |
192 | argv[dest_argc] = NULL; | |
bcc785f6 LT |
193 | if (verbose) |
194 | fprintf(stderr, "Pushing to %s\n", dest); | |
df91ba36 | 195 | err = run_command_v_opt(argv, RUN_GIT_CMD); |
60b7f38e | 196 | if (!err) |
755225de | 197 | continue; |
39878b0c | 198 | |
5751f490 | 199 | error("failed to push to '%s'", remote->uri[i]); |
60b7f38e | 200 | switch (err) { |
755225de | 201 | case -ERR_RUN_COMMAND_FORK: |
fd1d1b05 | 202 | error("unable to fork for %s", sender); |
755225de | 203 | case -ERR_RUN_COMMAND_EXEC: |
fd1d1b05 JH |
204 | error("unable to exec %s", sender); |
205 | break; | |
755225de LT |
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: | |
fd1d1b05 | 210 | error("%s died with strange error", sender); |
755225de | 211 | } |
fd1d1b05 | 212 | errs++; |
755225de | 213 | } |
fd1d1b05 | 214 | return !!errs; |
755225de LT |
215 | } |
216 | ||
a633fca0 | 217 | int cmd_push(int argc, const char **argv, const char *prefix) |
755225de LT |
218 | { |
219 | int i; | |
5751f490 | 220 | const char *repo = NULL; /* default repository */ |
755225de LT |
221 | |
222 | for (i = 1; i < argc; i++) { | |
223 | const char *arg = argv[i]; | |
224 | ||
225 | if (arg[0] != '-') { | |
226 | repo = arg; | |
227 | i++; | |
228 | break; | |
229 | } | |
bcc785f6 LT |
230 | if (!strcmp(arg, "-v")) { |
231 | verbose=1; | |
232 | continue; | |
233 | } | |
cc44c765 | 234 | if (!prefixcmp(arg, "--repo=")) { |
bcc785f6 LT |
235 | repo = arg+7; |
236 | continue; | |
237 | } | |
755225de LT |
238 | if (!strcmp(arg, "--all")) { |
239 | all = 1; | |
240 | continue; | |
241 | } | |
242 | if (!strcmp(arg, "--tags")) { | |
243 | tags = 1; | |
244 | continue; | |
245 | } | |
8f615493 | 246 | if (!strcmp(arg, "--force") || !strcmp(arg, "-f")) { |
755225de LT |
247 | force = 1; |
248 | continue; | |
249 | } | |
250 | if (!strcmp(arg, "--thin")) { | |
251 | thin = 1; | |
252 | continue; | |
253 | } | |
254 | if (!strcmp(arg, "--no-thin")) { | |
255 | thin = 0; | |
256 | continue; | |
257 | } | |
cc44c765 | 258 | if (!prefixcmp(arg, "--receive-pack=")) { |
d23842fd UKK |
259 | receivepack = arg; |
260 | continue; | |
261 | } | |
cc44c765 | 262 | if (!prefixcmp(arg, "--exec=")) { |
d23842fd | 263 | receivepack = arg; |
755225de LT |
264 | continue; |
265 | } | |
266 | usage(push_usage); | |
267 | } | |
268 | set_refspecs(argv + i, argc - i); | |
269 | return do_push(repo); | |
270 | } |