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;
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
)
60 size_t bytes
= nr
* sizeof(char *);
62 refspec
= xrealloc(refspec
, bytes
);
63 memcpy(refspec
, refs
, bytes
);
69 static int get_remotes_uri(const char *repo
, const char *uri
[MAX_URI
])
72 FILE *f
= fopen(git_path("remotes/%s", repo
), "r");
73 int has_explicit_refspec
= refspec_nr
|| all
|| tags
;
77 while (fgets(buffer
, BUF_SIZE
, f
)) {
81 if (!strncmp("URL: ", buffer
, 5)) {
84 } else if (!strncmp("Push: ", buffer
, 6)) {
90 /* Remove whitespace at the head.. */
96 /* ..and at the end */
98 while (isspace(p
[-1]))
103 uri
[n
++] = xstrdup(s
);
105 error("more than %d URL's specified, ignoring the rest", MAX_URI
);
107 else if (is_refspec
&& !has_explicit_refspec
)
108 add_refspec(xstrdup(s
));
112 die("remote '%s' has no URL", repo
);
116 static const char **config_uri
;
117 static const char *config_repo
;
118 static int config_repo_len
;
119 static int config_current_uri
;
120 static int config_get_refspecs
;
122 static int get_remote_config(const char* key
, const char* value
)
124 if (!strncmp(key
, "remote.", 7) &&
125 !strncmp(key
+ 7, config_repo
, config_repo_len
)) {
126 if (!strcmp(key
+ 7 + config_repo_len
, ".url")) {
127 if (config_current_uri
< MAX_URI
)
128 config_uri
[config_current_uri
++] = xstrdup(value
);
130 error("more than %d URL's specified, ignoring the rest", MAX_URI
);
132 else if (config_get_refspecs
&&
133 !strcmp(key
+ 7 + config_repo_len
, ".push"))
134 add_refspec(xstrdup(value
));
139 static int get_config_remotes_uri(const char *repo
, const char *uri
[MAX_URI
])
141 config_repo_len
= strlen(repo
);
143 config_current_uri
= 0;
145 config_get_refspecs
= !(refspec_nr
|| all
|| tags
);
147 git_config(get_remote_config
);
148 return config_current_uri
;
151 static int get_branches_uri(const char *repo
, const char *uri
[MAX_URI
])
153 const char *slash
= strchr(repo
, '/');
154 int n
= slash
? slash
- repo
: 1000;
155 FILE *f
= fopen(git_path("branches/%.*s", n
, repo
), "r");
161 s
= fgets(buffer
, BUF_SIZE
, f
);
170 while (isspace(p
[-1]))
174 len
+= strlen(slash
);
175 p
= xmalloc(len
+ 1);
184 * Read remotes and branches file, fill the push target URI
185 * list. If there is no command line refspecs, read Push: lines
186 * to set up the *refspec list as well.
187 * return the number of push target URIs
189 static int read_config(const char *repo
, const char *uri
[MAX_URI
])
194 n
= get_remotes_uri(repo
, uri
);
198 n
= get_config_remotes_uri(repo
, uri
);
202 n
= get_branches_uri(repo
, uri
);
211 static int do_push(const char *repo
)
213 const char *uri
[MAX_URI
];
219 n
= read_config(repo
, uri
);
221 die("bad repository '%s'", repo
);
223 argv
= xmalloc((refspec_nr
+ 10) * sizeof(char *));
224 argv
[0] = "dummy-send-pack";
227 argv
[argc
++] = "--all";
229 argv
[argc
++] = "--force";
231 argv
[argc
++] = execute
;
234 for (i
= 0; i
< n
; i
++) {
236 int dest_argc
= common_argc
;
237 int dest_refspec_nr
= refspec_nr
;
238 const char **dest_refspec
= refspec
;
239 const char *dest
= uri
[i
];
240 const char *sender
= "git-send-pack";
241 if (!strncmp(dest
, "http://", 7) ||
242 !strncmp(dest
, "https://", 8))
243 sender
= "git-http-push";
245 argv
[dest_argc
++] = "--thin";
247 argv
[dest_argc
++] = dest
;
248 while (dest_refspec_nr
--)
249 argv
[dest_argc
++] = *dest_refspec
++;
250 argv
[dest_argc
] = NULL
;
251 err
= run_command_v(argc
, argv
);
255 case -ERR_RUN_COMMAND_FORK
:
256 die("unable to fork for %s", sender
);
257 case -ERR_RUN_COMMAND_EXEC
:
258 die("unable to exec %s", sender
);
259 case -ERR_RUN_COMMAND_WAITPID
:
260 case -ERR_RUN_COMMAND_WAITPID_WRONG_PID
:
261 case -ERR_RUN_COMMAND_WAITPID_SIGNAL
:
262 case -ERR_RUN_COMMAND_WAITPID_NOEXIT
:
263 die("%s died with strange error", sender
);
271 int cmd_push(int argc
, const char **argv
, const char *prefix
)
274 const char *repo
= "origin"; /* default repository */
276 for (i
= 1; i
< argc
; i
++) {
277 const char *arg
= argv
[i
];
284 if (!strcmp(arg
, "--all")) {
288 if (!strcmp(arg
, "--tags")) {
292 if (!strcmp(arg
, "--force") || !strcmp(arg
, "-f")) {
296 if (!strcmp(arg
, "--thin")) {
300 if (!strcmp(arg
, "--no-thin")) {
304 if (!strncmp(arg
, "--exec=", 7)) {
310 set_refspecs(argv
+ i
, argc
- i
);
311 return do_push(repo
);