1/*
2 * "git push"
3 */
4#include "cache.h"
5#include "refs.h"
6#include "run-command.h"
7#include "builtin.h"
8#include "remote.h"
9#include "transport.h"
10
11static const char push_usage[] = "git-push [--all] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]";
12
13static int all, thin, verbose;
14static const char *receivepack;
15
16static const char **refspec;
17static int refspec_nr;
18
19static void add_refspec(const char *ref)
20{
21 int nr = refspec_nr + 1;
22 refspec = xrealloc(refspec, nr * sizeof(char *));
23 refspec[nr-1] = ref;
24 refspec_nr = nr;
25}
26
27static void set_refspecs(const char **refs, int nr)
28{
29 int i;
30 for (i = 0; i < nr; i++) {
31 const char *ref = refs[i];
32 if (!strcmp("tag", ref)) {
33 char *tag;
34 int len;
35 if (nr <= ++i)
36 die("tag shorthand without <tag>");
37 len = strlen(refs[i]) + 11;
38 tag = xmalloc(len);
39 strcpy(tag, "refs/tags/");
40 strcat(tag, refs[i]);
41 ref = tag;
42 }
43 add_refspec(ref);
44 }
45}
46
47static int do_push(const char *repo, int flags)
48{
49 int i, errs;
50 struct remote *remote = remote_get(repo);
51
52 if (!remote)
53 die("bad repository '%s'", repo);
54
55 if (!refspec && !all && remote->push_refspec_nr) {
56 refspec = remote->push_refspec;
57 refspec_nr = remote->push_refspec_nr;
58 }
59 errs = 0;
60 for (i = 0; i < remote->uri_nr; i++) {
61 struct transport *transport =
62 transport_get(remote, remote->uri[i], 0);
63 int err;
64 if (receivepack)
65 transport_set_option(transport,
66 TRANS_OPT_RECEIVEPACK, receivepack);
67 if (thin)
68 transport_set_option(transport, TRANS_OPT_THIN, "yes");
69
70 if (verbose)
71 fprintf(stderr, "Pushing to %s\n", remote->uri[i]);
72 err = transport_push(transport, refspec_nr, refspec, flags);
73 err |= transport_disconnect(transport);
74
75 if (!err)
76 continue;
77
78 error("failed to push to '%s'", remote->uri[i]);
79 errs++;
80 }
81 return !!errs;
82}
83
84int cmd_push(int argc, const char **argv, const char *prefix)
85{
86 int i;
87 int flags = 0;
88 const char *repo = NULL; /* default repository */
89
90 for (i = 1; i < argc; i++) {
91 const char *arg = argv[i];
92
93 if (arg[0] != '-') {
94 repo = arg;
95 i++;
96 break;
97 }
98 if (!strcmp(arg, "-v")) {
99 verbose=1;
100 continue;
101 }
102 if (!prefixcmp(arg, "--repo=")) {
103 repo = arg+7;
104 continue;
105 }
106 if (!strcmp(arg, "--all")) {
107 flags |= TRANSPORT_PUSH_ALL;
108 continue;
109 }
110 if (!strcmp(arg, "--tags")) {
111 add_refspec("refs/tags/*");
112 continue;
113 }
114 if (!strcmp(arg, "--force") || !strcmp(arg, "-f")) {
115 flags |= TRANSPORT_PUSH_FORCE;
116 continue;
117 }
118 if (!strcmp(arg, "--thin")) {
119 thin = 1;
120 continue;
121 }
122 if (!strcmp(arg, "--no-thin")) {
123 thin = 0;
124 continue;
125 }
126 if (!prefixcmp(arg, "--receive-pack=")) {
127 receivepack = arg + 15;
128 continue;
129 }
130 if (!prefixcmp(arg, "--exec=")) {
131 receivepack = arg + 7;
132 continue;
133 }
134 usage(push_usage);
135 }
136 set_refspecs(argv + i, argc - i);
137 if (all && refspec)
138 usage(push_usage);
139
140 return do_push(repo, flags);
141}