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 argv
[dest_argc
++] = "--thin";
184 argv
[dest_argc
++] = dest
;
185 while (dest_refspec_nr
--)
186 argv
[dest_argc
++] = *dest_refspec
++;
187 argv
[dest_argc
] = NULL
;
189 fprintf(stderr
, "Pushing to %s\n", dest
);
190 err
= run_command_v_opt(argv
, RUN_GIT_CMD
);
194 error("failed to push to '%s'", remote
->uri
[i
]);
196 case -ERR_RUN_COMMAND_FORK
:
197 error("unable to fork for %s", sender
);
198 case -ERR_RUN_COMMAND_EXEC
:
199 error("unable to exec %s", sender
);
201 case -ERR_RUN_COMMAND_WAITPID
:
202 case -ERR_RUN_COMMAND_WAITPID_WRONG_PID
:
203 case -ERR_RUN_COMMAND_WAITPID_SIGNAL
:
204 case -ERR_RUN_COMMAND_WAITPID_NOEXIT
:
205 error("%s died with strange error", sender
);
212 int cmd_push(int argc
, const char **argv
, const char *prefix
)
215 const char *repo
= NULL
; /* default repository */
217 for (i
= 1; i
< argc
; i
++) {
218 const char *arg
= argv
[i
];
225 if (!strcmp(arg
, "-v")) {
229 if (!prefixcmp(arg
, "--repo=")) {
233 if (!strcmp(arg
, "--all")) {
237 if (!strcmp(arg
, "--tags")) {
241 if (!strcmp(arg
, "--force") || !strcmp(arg
, "-f")) {
245 if (!strcmp(arg
, "--thin")) {
249 if (!strcmp(arg
, "--no-thin")) {
253 if (!prefixcmp(arg
, "--receive-pack=")) {
257 if (!prefixcmp(arg
, "--exec=")) {
263 set_refspecs(argv
+ i
, argc
- i
);
264 return do_push(repo
);