summaryrefslogtreecommitdiff
path: root/builtin-push.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin-push.c')
-rw-r--r--builtin-push.c181
1 files changed, 181 insertions, 0 deletions
diff --git a/builtin-push.c b/builtin-push.c
new file mode 100644
index 0000000000..2612f07f74
--- /dev/null
+++ b/builtin-push.c
@@ -0,0 +1,181 @@
+/*
+ * "git push"
+ */
+#include "cache.h"
+#include "refs.h"
+#include "run-command.h"
+#include "builtin.h"
+#include "remote.h"
+
+static const char push_usage[] = "git-push [--all] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]";
+
+static int all, force, thin = 1, verbose;
+static const char *receivepack;
+
+static const char **refspec;
+static int refspec_nr;
+
+static void add_refspec(const char *ref)
+{
+ int nr = refspec_nr + 1;
+ refspec = xrealloc(refspec, nr * sizeof(char *));
+ refspec[nr-1] = ref;
+ refspec_nr = nr;
+}
+
+static void set_refspecs(const char **refs, int nr)
+{
+ int i;
+ for (i = 0; i < nr; i++) {
+ const char *ref = refs[i];
+ if (!strcmp("tag", ref)) {
+ char *tag;
+ int len;
+ if (nr <= ++i)
+ die("tag shorthand without <tag>");
+ len = strlen(refs[i]) + 11;
+ tag = xmalloc(len);
+ strcpy(tag, "refs/tags/");
+ strcat(tag, refs[i]);
+ ref = tag;
+ }
+ add_refspec(ref);
+ }
+}
+
+static int do_push(const char *repo)
+{
+ int i, errs;
+ int common_argc;
+ const char **argv;
+ int argc;
+ struct remote *remote = remote_get(repo);
+
+ if (!remote)
+ die("bad repository '%s'", repo);
+
+ if (remote->receivepack) {
+ char *rp = xmalloc(strlen(remote->receivepack) + 16);
+ sprintf(rp, "--receive-pack=%s", remote->receivepack);
+ receivepack = rp;
+ }
+ if (!refspec && !all && remote->push_refspec_nr) {
+ refspec = remote->push_refspec;
+ refspec_nr = remote->push_refspec_nr;
+ }
+
+ argv = xmalloc((refspec_nr + 10) * sizeof(char *));
+ argv[0] = "dummy-send-pack";
+ argc = 1;
+ if (all)
+ argv[argc++] = "--all";
+ if (force)
+ argv[argc++] = "--force";
+ if (receivepack)
+ argv[argc++] = receivepack;
+ common_argc = argc;
+
+ errs = 0;
+ for (i = 0; i < remote->uri_nr; i++) {
+ int err;
+ int dest_argc = common_argc;
+ int dest_refspec_nr = refspec_nr;
+ const char **dest_refspec = refspec;
+ const char *dest = remote->uri[i];
+ const char *sender = "send-pack";
+ if (!prefixcmp(dest, "http://") ||
+ !prefixcmp(dest, "https://"))
+ sender = "http-push";
+ else {
+ char *rem = xmalloc(strlen(remote->name) + 10);
+ sprintf(rem, "--remote=%s", remote->name);
+ argv[dest_argc++] = rem;
+ if (thin)
+ argv[dest_argc++] = "--thin";
+ }
+ argv[0] = sender;
+ argv[dest_argc++] = dest;
+ while (dest_refspec_nr--)
+ argv[dest_argc++] = *dest_refspec++;
+ argv[dest_argc] = NULL;
+ if (verbose)
+ fprintf(stderr, "Pushing to %s\n", dest);
+ err = run_command_v_opt(argv, RUN_GIT_CMD);
+ if (!err)
+ continue;
+
+ error("failed to push to '%s'", remote->uri[i]);
+ switch (err) {
+ case -ERR_RUN_COMMAND_FORK:
+ error("unable to fork for %s", sender);
+ case -ERR_RUN_COMMAND_EXEC:
+ error("unable to exec %s", sender);
+ break;
+ case -ERR_RUN_COMMAND_WAITPID:
+ case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
+ case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
+ case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
+ error("%s died with strange error", sender);
+ }
+ errs++;
+ }
+ return !!errs;
+}
+
+int cmd_push(int argc, const char **argv, const char *prefix)
+{
+ int i;
+ const char *repo = NULL; /* default repository */
+
+ for (i = 1; i < argc; i++) {
+ const char *arg = argv[i];
+
+ if (arg[0] != '-') {
+ repo = arg;
+ i++;
+ break;
+ }
+ if (!strcmp(arg, "-v")) {
+ verbose=1;
+ continue;
+ }
+ if (!prefixcmp(arg, "--repo=")) {
+ repo = arg+7;
+ continue;
+ }
+ if (!strcmp(arg, "--all")) {
+ all = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--tags")) {
+ add_refspec("refs/tags/*");
+ continue;
+ }
+ if (!strcmp(arg, "--force") || !strcmp(arg, "-f")) {
+ force = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--thin")) {
+ thin = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--no-thin")) {
+ thin = 0;
+ continue;
+ }
+ if (!prefixcmp(arg, "--receive-pack=")) {
+ receivepack = arg;
+ continue;
+ }
+ if (!prefixcmp(arg, "--exec=")) {
+ receivepack = arg;
+ continue;
+ }
+ usage(push_usage);
+ }
+ set_refspecs(argv + i, argc - i);
+ if (all && refspec)
+ usage(push_usage);
+
+ return do_push(repo);
+}