6 #include "run-command.h"
11 static const char push_usage
[] = "git-push [--all] [--tags] [-f | --force] <repository> [<refspec>...]";
13 static int all
, tags
, force
, thin
= 1, verbose
;
14 static const char *execute
;
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 (!strncmp(ref
, "tags/", 5))
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
);
57 static void set_refspecs(const char **refs
, int nr
)
61 for (pass
= 0; pass
< 2; pass
++) {
62 /* pass 0 counts and allocates, pass 1 fills */
64 for (i
= cnt
= 0; i
< nr
; i
++) {
65 if (!strcmp("tag", refs
[i
])) {
69 die("tag <tag> shorthand without <tag>");
71 len
= strlen(refs
[i
]) + 11;
73 strcpy(tag
, "refs/tags/");
81 refspec
[cnt
] = refs
[i
];
85 size_t bytes
= cnt
* sizeof(char *);
87 refspec
= xrealloc(refspec
, bytes
);
94 static int get_remotes_uri(const char *repo
, const char *uri
[MAX_URI
])
97 FILE *f
= fopen(git_path("remotes/%s", repo
), "r");
98 int has_explicit_refspec
= refspec_nr
|| all
|| tags
;
102 while (fgets(buffer
, BUF_SIZE
, f
)) {
106 if (!strncmp("URL:", buffer
, 4)) {
109 } else if (!strncmp("Push:", buffer
, 5)) {
115 /* Remove whitespace at the head.. */
121 /* ..and at the end */
123 while (isspace(p
[-1]))
128 uri
[n
++] = xstrdup(s
);
130 error("more than %d URL's specified, ignoring the rest", MAX_URI
);
132 else if (is_refspec
&& !has_explicit_refspec
)
133 add_refspec(xstrdup(s
));
137 die("remote '%s' has no URL", repo
);
141 static const char **config_uri
;
142 static const char *config_repo
;
143 static int config_repo_len
;
144 static int config_current_uri
;
145 static int config_get_refspecs
;
147 static int get_remote_config(const char* key
, const char* value
)
149 if (!strncmp(key
, "remote.", 7) &&
150 !strncmp(key
+ 7, config_repo
, config_repo_len
)) {
151 if (!strcmp(key
+ 7 + config_repo_len
, ".url")) {
152 if (config_current_uri
< MAX_URI
)
153 config_uri
[config_current_uri
++] = xstrdup(value
);
155 error("more than %d URL's specified, ignoring the rest", MAX_URI
);
157 else if (config_get_refspecs
&&
158 !strcmp(key
+ 7 + config_repo_len
, ".push"))
159 add_refspec(xstrdup(value
));
164 static int get_config_remotes_uri(const char *repo
, const char *uri
[MAX_URI
])
166 config_repo_len
= strlen(repo
);
168 config_current_uri
= 0;
170 config_get_refspecs
= !(refspec_nr
|| all
|| tags
);
172 git_config(get_remote_config
);
173 return config_current_uri
;
176 static int get_branches_uri(const char *repo
, const char *uri
[MAX_URI
])
178 const char *slash
= strchr(repo
, '/');
179 int n
= slash
? slash
- repo
: 1000;
180 FILE *f
= fopen(git_path("branches/%.*s", n
, repo
), "r");
186 s
= fgets(buffer
, BUF_SIZE
, f
);
195 while (isspace(p
[-1]))
199 len
+= strlen(slash
);
200 p
= xmalloc(len
+ 1);
209 * Read remotes and branches file, fill the push target URI
210 * list. If there is no command line refspecs, read Push: lines
211 * to set up the *refspec list as well.
212 * return the number of push target URIs
214 static int read_config(const char *repo
, const char *uri
[MAX_URI
])
219 n
= get_remotes_uri(repo
, uri
);
223 n
= get_config_remotes_uri(repo
, uri
);
227 n
= get_branches_uri(repo
, uri
);
236 static int do_push(const char *repo
)
238 const char *uri
[MAX_URI
];
244 n
= read_config(repo
, uri
);
246 die("bad repository '%s'", repo
);
248 argv
= xmalloc((refspec_nr
+ 10) * sizeof(char *));
249 argv
[0] = "dummy-send-pack";
252 argv
[argc
++] = "--all";
254 argv
[argc
++] = "--force";
256 argv
[argc
++] = execute
;
259 for (i
= 0; i
< n
; i
++) {
261 int dest_argc
= common_argc
;
262 int dest_refspec_nr
= refspec_nr
;
263 const char **dest_refspec
= refspec
;
264 const char *dest
= uri
[i
];
265 const char *sender
= "git-send-pack";
266 if (!strncmp(dest
, "http://", 7) ||
267 !strncmp(dest
, "https://", 8))
268 sender
= "git-http-push";
270 argv
[dest_argc
++] = "--thin";
272 argv
[dest_argc
++] = dest
;
273 while (dest_refspec_nr
--)
274 argv
[dest_argc
++] = *dest_refspec
++;
275 argv
[dest_argc
] = NULL
;
277 fprintf(stderr
, "Pushing to %s\n", dest
);
278 err
= run_command_v(argv
);
282 case -ERR_RUN_COMMAND_FORK
:
283 die("unable to fork for %s", sender
);
284 case -ERR_RUN_COMMAND_EXEC
:
285 die("unable to exec %s", sender
);
286 case -ERR_RUN_COMMAND_WAITPID
:
287 case -ERR_RUN_COMMAND_WAITPID_WRONG_PID
:
288 case -ERR_RUN_COMMAND_WAITPID_SIGNAL
:
289 case -ERR_RUN_COMMAND_WAITPID_NOEXIT
:
290 die("%s died with strange error", sender
);
298 int cmd_push(int argc
, const char **argv
, const char *prefix
)
301 const char *repo
= "origin"; /* default repository */
303 for (i
= 1; i
< argc
; i
++) {
304 const char *arg
= argv
[i
];
311 if (!strcmp(arg
, "-v")) {
315 if (!strncmp(arg
, "--repo=", 7)) {
319 if (!strcmp(arg
, "--all")) {
323 if (!strcmp(arg
, "--tags")) {
327 if (!strcmp(arg
, "--force") || !strcmp(arg
, "-f")) {
331 if (!strcmp(arg
, "--thin")) {
335 if (!strcmp(arg
, "--no-thin")) {
339 if (!strncmp(arg
, "--exec=", 7)) {
345 set_refspecs(argv
+ i
, argc
- i
);
346 return do_push(repo
);