]>
Commit | Line | Data |
---|---|---|
61221472 | 1 | #include "cache.h" |
2a9c3fe8 | 2 | #include "commit.h" |
584c6cc9 | 3 | #include "refs.h" |
f3a3214e | 4 | #include "pkt-line.h" |
61221472 | 5 | |
2a245013 | 6 | static const char send_pack_usage[] = |
0bc3cdfc JH |
7 | "git-send-pack [--all] [--exec=git-receive-pack] <remote> [<head>...]\n" |
8 | " --all and explicit <head> specification are mutually exclusive."; | |
61221472 | 9 | static const char *exec = "git-receive-pack"; |
d089391c | 10 | static int send_all = 0; |
2a9c3fe8 | 11 | static int force_update = 0; |
61221472 | 12 | |
584c6cc9 LT |
13 | static int is_zero_sha1(const unsigned char *sha1) |
14 | { | |
15 | int i; | |
16 | ||
17 | for (i = 0; i < 20; i++) { | |
18 | if (*sha1++) | |
19 | return 0; | |
20 | } | |
21 | return 1; | |
22 | } | |
23 | ||
94fdb7aa LT |
24 | static void exec_pack_objects(void) |
25 | { | |
26 | static char *args[] = { | |
27 | "git-pack-objects", | |
28 | "--stdout", | |
29 | NULL | |
30 | }; | |
31 | execvp("git-pack-objects", args); | |
32 | die("git-pack-objects exec failed (%s)", strerror(errno)); | |
33 | } | |
34 | ||
35 | static void exec_rev_list(struct ref *refs) | |
36 | { | |
37 | static char *args[1000]; | |
38 | int i = 0; | |
39 | ||
40 | args[i++] = "git-rev-list"; /* 0 */ | |
41 | args[i++] = "--objects"; /* 1 */ | |
42 | while (refs) { | |
43 | char *buf = malloc(100); | |
44 | if (i > 900) | |
45 | die("git-rev-list environment overflow"); | |
40b64d47 JH |
46 | if (!is_zero_sha1(refs->old_sha1) && |
47 | has_sha1_file(refs->old_sha1)) { | |
584c6cc9 LT |
48 | args[i++] = buf; |
49 | snprintf(buf, 50, "^%s", sha1_to_hex(refs->old_sha1)); | |
50 | buf += 50; | |
51 | } | |
52 | if (!is_zero_sha1(refs->new_sha1)) { | |
53 | args[i++] = buf; | |
54 | snprintf(buf, 50, "%s", sha1_to_hex(refs->new_sha1)); | |
55 | } | |
94fdb7aa LT |
56 | refs = refs->next; |
57 | } | |
58 | args[i] = NULL; | |
59 | execvp("git-rev-list", args); | |
60 | die("git-rev-list exec failed (%s)", strerror(errno)); | |
61 | } | |
62 | ||
63 | static void rev_list(int fd, struct ref *refs) | |
64 | { | |
65 | int pipe_fd[2]; | |
66 | pid_t pack_objects_pid; | |
67 | ||
68 | if (pipe(pipe_fd) < 0) | |
69 | die("rev-list setup: pipe failed"); | |
70 | pack_objects_pid = fork(); | |
71 | if (!pack_objects_pid) { | |
72 | dup2(pipe_fd[0], 0); | |
73 | dup2(fd, 1); | |
74 | close(pipe_fd[0]); | |
75 | close(pipe_fd[1]); | |
76 | close(fd); | |
77 | exec_pack_objects(); | |
78 | die("pack-objects setup failed"); | |
79 | } | |
80 | if (pack_objects_pid < 0) | |
81 | die("pack-objects fork failed"); | |
82 | dup2(pipe_fd[1], 1); | |
83 | close(pipe_fd[0]); | |
84 | close(pipe_fd[1]); | |
85 | close(fd); | |
86 | exec_rev_list(refs); | |
87 | } | |
88 | ||
89 | static int pack_objects(int fd, struct ref *refs) | |
90 | { | |
91 | pid_t rev_list_pid; | |
92 | ||
93 | rev_list_pid = fork(); | |
94 | if (!rev_list_pid) { | |
95 | rev_list(fd, refs); | |
96 | die("rev-list setup failed"); | |
97 | } | |
98 | if (rev_list_pid < 0) | |
99 | die("rev-list fork failed"); | |
100 | /* | |
101 | * We don't wait for the rev-list pipeline in the parent: | |
102 | * we end up waiting for the other end instead | |
103 | */ | |
7ec4e608 | 104 | return 0; |
94fdb7aa | 105 | } |
e4b5c7ff | 106 | |
584c6cc9 LT |
107 | static int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1) |
108 | { | |
2a9c3fe8 LT |
109 | struct commit *new, *old; |
110 | struct commit_list *list; | |
111 | ||
112 | if (force_update) | |
113 | return 1; | |
114 | old = lookup_commit_reference(old_sha1); | |
115 | if (!old) | |
584c6cc9 | 116 | return 0; |
2a9c3fe8 LT |
117 | new = lookup_commit_reference(new_sha1); |
118 | if (!new) | |
119 | return 0; | |
120 | if (parse_commit(new) < 0) | |
121 | return 0; | |
122 | list = NULL; | |
123 | commit_list_insert(new, &list); | |
bdf25142 LT |
124 | while (list) { |
125 | new = pop_most_recent_commit(&list, 1); | |
2a9c3fe8 LT |
126 | if (new == old) |
127 | return 1; | |
128 | } | |
129 | return 0; | |
584c6cc9 LT |
130 | } |
131 | ||
f88395ac JH |
132 | static struct ref *local_refs, **local_tail; |
133 | static struct ref *remote_refs, **remote_tail; | |
584c6cc9 | 134 | |
f88395ac | 135 | static int one_local_ref(const char *refname, const unsigned char *sha1) |
584c6cc9 LT |
136 | { |
137 | struct ref *ref; | |
f88395ac JH |
138 | int len = strlen(refname) + 1; |
139 | ref = xcalloc(1, sizeof(*ref) + len); | |
584c6cc9 LT |
140 | memcpy(ref->new_sha1, sha1, 20); |
141 | memcpy(ref->name, refname, len); | |
f88395ac JH |
142 | *local_tail = ref; |
143 | local_tail = &ref->next; | |
584c6cc9 LT |
144 | return 0; |
145 | } | |
146 | ||
f88395ac JH |
147 | static void get_local_heads(void) |
148 | { | |
149 | local_tail = &local_refs; | |
150 | for_each_ref(one_local_ref); | |
151 | } | |
152 | ||
153 | static int send_pack(int in, int out, int nr_refspec, char **refspec) | |
61221472 | 154 | { |
7f8e9828 | 155 | struct ref *ref; |
584c6cc9 | 156 | int new_refs; |
7f8e9828 | 157 | |
f88395ac JH |
158 | /* No funny business with the matcher */ |
159 | remote_tail = get_remote_heads(in, &remote_refs, 0, NULL); | |
160 | get_local_heads(); | |
584c6cc9 | 161 | |
f88395ac JH |
162 | /* match them up */ |
163 | if (!remote_tail) | |
164 | remote_tail = &remote_refs; | |
165 | if (match_refs(local_refs, remote_refs, &remote_tail, | |
166 | nr_refspec, refspec, send_all)) | |
167 | return -1; | |
584c6cc9 | 168 | /* |
f88395ac | 169 | * Finally, tell the other end! |
584c6cc9 | 170 | */ |
f88395ac JH |
171 | new_refs = 0; |
172 | for (ref = remote_refs; ref; ref = ref->next) { | |
173 | char old_hex[60], *new_hex; | |
174 | if (!ref->peer_ref) | |
7f8e9828 | 175 | continue; |
f88395ac JH |
176 | if (!is_zero_sha1(ref->old_sha1)) { |
177 | if (!has_sha1_file(ref->old_sha1)) { | |
178 | error("remote '%s' object %s does not " | |
179 | "exist on local", | |
180 | ref->name, sha1_to_hex(ref->old_sha1)); | |
181 | continue; | |
182 | } | |
183 | if (!ref_newer(ref->peer_ref->new_sha1, | |
184 | ref->old_sha1)) { | |
185 | error("remote ref '%s' is not a strict " | |
186 | "subset of local ref '%s'.", ref->name, | |
187 | ref->peer_ref->name); | |
188 | continue; | |
189 | } | |
e4b5c7ff | 190 | } |
f88395ac JH |
191 | if (!memcmp(ref->old_sha1, ref->peer_ref->new_sha1, 20)) { |
192 | fprintf(stderr, "'%s': up-to-date\n", ref->name); | |
40b64d47 JH |
193 | continue; |
194 | } | |
f88395ac JH |
195 | memcpy(ref->new_sha1, ref->peer_ref->new_sha1, 20); |
196 | if (is_zero_sha1(ref->new_sha1)) { | |
197 | error("cannot happen anymore"); | |
584c6cc9 LT |
198 | continue; |
199 | } | |
584c6cc9 | 200 | new_refs++; |
7f8e9828 LT |
201 | strcpy(old_hex, sha1_to_hex(ref->old_sha1)); |
202 | new_hex = sha1_to_hex(ref->new_sha1); | |
203 | packet_write(out, "%s %s %s", old_hex, new_hex, ref->name); | |
f88395ac JH |
204 | fprintf(stderr, "updating '%s'", ref->name); |
205 | if (strcmp(ref->name, ref->peer_ref->name)) | |
206 | fprintf(stderr, " using '%s'", ref->peer_ref->name); | |
207 | fprintf(stderr, "\n from %s\n to %s\n", old_hex, new_hex); | |
61221472 | 208 | } |
f88395ac | 209 | |
f3a3214e | 210 | packet_flush(out); |
584c6cc9 | 211 | if (new_refs) |
f88395ac | 212 | pack_objects(out, remote_refs); |
61221472 LT |
213 | close(out); |
214 | return 0; | |
215 | } | |
216 | ||
f88395ac | 217 | |
61221472 LT |
218 | int main(int argc, char **argv) |
219 | { | |
220 | int i, nr_heads = 0; | |
221 | char *dest = NULL; | |
222 | char **heads = NULL; | |
7f8e9828 LT |
223 | int fd[2], ret; |
224 | pid_t pid; | |
61221472 LT |
225 | |
226 | argv++; | |
d089391c LT |
227 | for (i = 1; i < argc; i++, argv++) { |
228 | char *arg = *argv; | |
61221472 LT |
229 | |
230 | if (*arg == '-') { | |
231 | if (!strncmp(arg, "--exec=", 7)) { | |
232 | exec = arg + 7; | |
233 | continue; | |
234 | } | |
d089391c LT |
235 | if (!strcmp(arg, "--all")) { |
236 | send_all = 1; | |
237 | continue; | |
238 | } | |
2a9c3fe8 LT |
239 | if (!strcmp(arg, "--force")) { |
240 | force_update = 1; | |
241 | continue; | |
242 | } | |
61221472 LT |
243 | usage(send_pack_usage); |
244 | } | |
d089391c LT |
245 | if (!dest) { |
246 | dest = arg; | |
247 | continue; | |
248 | } | |
61221472 | 249 | heads = argv; |
d089391c | 250 | nr_heads = argc - i; |
61221472 LT |
251 | break; |
252 | } | |
253 | if (!dest) | |
254 | usage(send_pack_usage); | |
0bc3cdfc JH |
255 | if (heads && send_all) |
256 | usage(send_pack_usage); | |
f7192598 | 257 | pid = git_connect(fd, dest, exec); |
7f8e9828 | 258 | if (pid < 0) |
61221472 | 259 | return 1; |
d0efc8a7 | 260 | ret = send_pack(fd[0], fd[1], nr_heads, heads); |
7f8e9828 LT |
261 | close(fd[0]); |
262 | close(fd[1]); | |
f7192598 | 263 | finish_connect(pid); |
7f8e9828 | 264 | return ret; |
61221472 | 265 | } |