6 #include "run-command.h"
11 static const char push_usage
[] = "git-push [--all] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]";
13 static int all
, tags
, force
, thin
= 1, verbose
;
14 static const char *receivepack
;
16 #define BUF_SIZE (2084)
17 static char buffer
[BUF_SIZE
];
19 static const char **refspec
;
20 static int refspec_nr
;
22 static void add_refspec(const char *ref
)
24 int nr
= refspec_nr
+ 1;
25 refspec
= xrealloc(refspec
, nr
* sizeof(char *));
30 static int expand_one_ref(const char *ref
, const unsigned char *sha1
, int flag
, void *cb_data
)
32 /* Ignore the "refs/" at the beginning of the refname */
35 if (!prefixcmp(ref
, "tags/"))
36 add_refspec(xstrdup(ref
));
40 static void expand_refspecs(void)
44 die("cannot mix '--all' and a refspec");
47 * No need to expand "--all" - we'll just use
48 * the "--all" flag to send-pack
54 for_each_ref(expand_one_ref
, NULL
);
58 const char *from_prefix
;
60 const char *to_prefix
;
65 static int expand_wildcard_ref(const char *ref
, const unsigned char *sha1
, int flag
, void *cb_data
)
67 struct wildcard_cb
*cb
= cb_data
;
68 int len
= strlen(ref
);
69 char *expanded
, *newref
;
71 if (len
< cb
->from_prefix_len
||
72 memcmp(cb
->from_prefix
, ref
, cb
->from_prefix_len
))
74 expanded
= xmalloc(len
* 2 + cb
->force
+
75 (cb
->to_prefix_len
- cb
->from_prefix_len
) + 2);
76 newref
= expanded
+ cb
->force
;
79 memcpy(newref
, ref
, len
);
81 memcpy(newref
+ len
+ 1, cb
->to_prefix
, cb
->to_prefix_len
);
82 strcpy(newref
+ len
+ 1 + cb
->to_prefix_len
,
83 ref
+ cb
->from_prefix_len
);
84 add_refspec(expanded
);
88 static int wildcard_ref(const char *ref
)
92 struct wildcard_cb cb
;
94 memset(&cb
, 0, sizeof(cb
));
100 colon
= strchr(ref
, ':');
101 if (! (colon
&& ref
< colon
&&
102 colon
[-2] == '/' && colon
[-1] == '*' &&
103 /* "<mine>/<asterisk>:<yours>/<asterisk>" is at least 7 bytes */
105 ref
[len
-2] == '/' && ref
[len
-1] == '*') )
107 cb
.from_prefix
= ref
;
108 cb
.from_prefix_len
= colon
- ref
- 1;
109 cb
.to_prefix
= colon
+ 1;
110 cb
.to_prefix_len
= len
- (colon
- ref
) - 2;
111 for_each_ref(expand_wildcard_ref
, &cb
);
115 static void set_refspecs(const char **refs
, int nr
)
119 for (i
= 0; i
< nr
; i
++) {
120 const char *ref
= refs
[i
];
121 if (!strcmp("tag", ref
)) {
125 die("tag shorthand without <tag>");
126 len
= strlen(refs
[i
]) + 11;
128 strcpy(tag
, "refs/tags/");
129 strcat(tag
, refs
[i
]);
132 else if (wildcard_ref(ref
))
140 static int get_remotes_uri(const char *repo
, const char *uri
[MAX_URI
])
143 FILE *f
= fopen(git_path("remotes/%s", repo
), "r");
144 int has_explicit_refspec
= refspec_nr
|| all
|| tags
;
148 while (fgets(buffer
, BUF_SIZE
, f
)) {
152 if (!prefixcmp(buffer
, "URL:")) {
155 } else if (!prefixcmp(buffer
, "Push:")) {
161 /* Remove whitespace at the head.. */
167 /* ..and at the end */
169 while (isspace(p
[-1]))
174 uri
[n
++] = xstrdup(s
);
176 error("more than %d URL's specified, ignoring the rest", MAX_URI
);
178 else if (is_refspec
&& !has_explicit_refspec
) {
179 if (!wildcard_ref(s
))
180 add_refspec(xstrdup(s
));
185 die("remote '%s' has no URL", repo
);
189 static const char **config_uri
;
190 static const char *config_repo
;
191 static int config_repo_len
;
192 static int config_current_uri
;
193 static int config_get_refspecs
;
194 static int config_get_receivepack
;
196 static int get_remote_config(const char* key
, const char* value
)
198 if (!prefixcmp(key
, "remote.") &&
199 !strncmp(key
+ 7, config_repo
, config_repo_len
)) {
200 if (!strcmp(key
+ 7 + config_repo_len
, ".url")) {
201 if (config_current_uri
< MAX_URI
)
202 config_uri
[config_current_uri
++] = xstrdup(value
);
204 error("more than %d URL's specified, ignoring the rest", MAX_URI
);
206 else if (config_get_refspecs
&&
207 !strcmp(key
+ 7 + config_repo_len
, ".push")) {
208 if (!wildcard_ref(value
))
209 add_refspec(xstrdup(value
));
211 else if (config_get_receivepack
&&
212 !strcmp(key
+ 7 + config_repo_len
, ".receivepack")) {
214 char *rp
= xmalloc(strlen(value
) + 16);
215 sprintf(rp
, "--receive-pack=%s", value
);
218 error("more than one receivepack given, using the first");
224 static int get_config_remotes_uri(const char *repo
, const char *uri
[MAX_URI
])
226 config_repo_len
= strlen(repo
);
228 config_current_uri
= 0;
230 config_get_refspecs
= !(refspec_nr
|| all
|| tags
);
231 config_get_receivepack
= (receivepack
== NULL
);
233 git_config(get_remote_config
);
234 return config_current_uri
;
237 static int get_branches_uri(const char *repo
, const char *uri
[MAX_URI
])
239 const char *slash
= strchr(repo
, '/');
240 int n
= slash
? slash
- repo
: 1000;
241 FILE *f
= fopen(git_path("branches/%.*s", n
, repo
), "r");
247 s
= fgets(buffer
, BUF_SIZE
, f
);
256 while (isspace(p
[-1]))
260 len
+= strlen(slash
);
261 p
= xmalloc(len
+ 1);
270 * Read remotes and branches file, fill the push target URI
271 * list. If there is no command line refspecs, read Push: lines
272 * to set up the *refspec list as well.
273 * return the number of push target URIs
275 static int read_config(const char *repo
, const char *uri
[MAX_URI
])
280 n
= get_remotes_uri(repo
, uri
);
284 n
= get_config_remotes_uri(repo
, uri
);
288 n
= get_branches_uri(repo
, uri
);
297 static int do_push(const char *repo
)
299 const char *uri
[MAX_URI
];
305 n
= read_config(repo
, uri
);
307 die("bad repository '%s'", repo
);
309 argv
= xmalloc((refspec_nr
+ 10) * sizeof(char *));
310 argv
[0] = "dummy-send-pack";
313 argv
[argc
++] = "--all";
315 argv
[argc
++] = "--force";
317 argv
[argc
++] = receivepack
;
321 for (i
= 0; i
< n
; i
++) {
323 int dest_argc
= common_argc
;
324 int dest_refspec_nr
= refspec_nr
;
325 const char **dest_refspec
= refspec
;
326 const char *dest
= uri
[i
];
327 const char *sender
= "send-pack";
328 if (!prefixcmp(dest
, "http://") ||
329 !prefixcmp(dest
, "https://"))
330 sender
= "http-push";
332 argv
[dest_argc
++] = "--thin";
334 argv
[dest_argc
++] = dest
;
335 while (dest_refspec_nr
--)
336 argv
[dest_argc
++] = *dest_refspec
++;
337 argv
[dest_argc
] = NULL
;
339 fprintf(stderr
, "Pushing to %s\n", dest
);
340 err
= run_command_v_opt(argv
, RUN_GIT_CMD
);
344 error("failed to push to '%s'", uri
[i
]);
346 case -ERR_RUN_COMMAND_FORK
:
347 error("unable to fork for %s", sender
);
348 case -ERR_RUN_COMMAND_EXEC
:
349 error("unable to exec %s", sender
);
351 case -ERR_RUN_COMMAND_WAITPID
:
352 case -ERR_RUN_COMMAND_WAITPID_WRONG_PID
:
353 case -ERR_RUN_COMMAND_WAITPID_SIGNAL
:
354 case -ERR_RUN_COMMAND_WAITPID_NOEXIT
:
355 error("%s died with strange error", sender
);
362 int cmd_push(int argc
, const char **argv
, const char *prefix
)
365 const char *repo
= "origin"; /* default repository */
367 for (i
= 1; i
< argc
; i
++) {
368 const char *arg
= argv
[i
];
375 if (!strcmp(arg
, "-v")) {
379 if (!prefixcmp(arg
, "--repo=")) {
383 if (!strcmp(arg
, "--all")) {
387 if (!strcmp(arg
, "--tags")) {
391 if (!strcmp(arg
, "--force") || !strcmp(arg
, "-f")) {
395 if (!strcmp(arg
, "--thin")) {
399 if (!strcmp(arg
, "--no-thin")) {
403 if (!prefixcmp(arg
, "--receive-pack=")) {
407 if (!prefixcmp(arg
, "--exec=")) {
413 set_refspecs(argv
+ i
, argc
- i
);
414 return do_push(repo
);