send-pack: move core code to libgit.a
send_pack() is used by transport.c, part of libgit.a while it stays in builtin/send-pack.c. Move it to send-pack.c so that we won't get undefined reference if a program that uses libgit.a happens to pull it in. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Jeff King <peff@peff.net>
Nguyễn Thái Ngọc Duy committed
Oct 26, 2012 at 22:53 UTC
f5d942e1ede7ce5e74537d3021df9fdc179a8377
4 files changed
+350
-333
Makefile
+1
@@ -798,6 +798,7 @@ LIB_OBJS += rerere.o
798
LIB_OBJS += resolve-undo.o
799
LIB_OBJS += revision.o
800
LIB_OBJS += run-command.o
801
+LIB_OBJS += send-pack.o
802
LIB_OBJS += sequencer.o
803
LIB_OBJS += server-info.o
804
LIB_OBJS += setup.o
builtin/send-pack.c
-333
@@ -16,164 +16,6 @@ static const char send_pack_usage[] =
16
17
static struct send_pack_args args;
18
19
-static int feed_object(const unsigned char *sha1, int fd, int negative)
20
-{
21
- char buf[42];
22
-
23
- if (negative && !has_sha1_file(sha1))
24
- return 1;
25
-
26
- memcpy(buf + negative, sha1_to_hex(sha1), 40);
27
- if (negative)
28
- buf[0] = '^';
29
- buf[40 + negative] = '\n';
30
- return write_or_whine(fd, buf, 41 + negative, "send-pack: send refs");
31
-}
32
-
33
-/*
34
- * Make a pack stream and spit it out into file descriptor fd
35
- */
36
-static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra, struct send_pack_args *args)
37
-{
38
- /*
39
- * The child becomes pack-objects --revs; we feed
40
- * the revision parameters to it via its stdin and
41
- * let its stdout go back to the other end.
42
- */
43
- const char *argv[] = {
44
- "pack-objects",
45
- "--all-progress-implied",
46
- "--revs",
47
- "--stdout",
48
- NULL,
49
- NULL,
50
- NULL,
51
- NULL,
52
- NULL,
53
- };
54
- struct child_process po;
55
- int i;
56
-
57
- i = 4;
58
- if (args->use_thin_pack)
59
- argv[i++] = "--thin";
60
- if (args->use_ofs_delta)
61
- argv[i++] = "--delta-base-offset";
62
- if (args->quiet || !args->progress)
63
- argv[i++] = "-q";
64
- if (args->progress)
65
- argv[i++] = "--progress";
66
- memset(&po, 0, sizeof(po));
67
- po.argv = argv;
68
- po.in = -1;
69
- po.out = args->stateless_rpc ? -1 : fd;
70
- po.git_cmd = 1;
71
- if (start_command(&po))
72
- die_errno("git pack-objects failed");
73
-
74
- /*
75
- * We feed the pack-objects we just spawned with revision
76
- * parameters by writing to the pipe.
77
- */
78
- for (i = 0; i < extra->nr; i++)
79
- if (!feed_object(extra->array[i], po.in, 1))
80
- break;
81
-
82
- while (refs) {
83
- if (!is_null_sha1(refs->old_sha1) &&
84
- !feed_object(refs->old_sha1, po.in, 1))
85
- break;
86
- if (!is_null_sha1(refs->new_sha1) &&
87
- !feed_object(refs->new_sha1, po.in, 0))
88
- break;
89
- refs = refs->next;
90
- }
91
-
92
- close(po.in);
93
-
94
- if (args->stateless_rpc) {
95
- char *buf = xmalloc(LARGE_PACKET_MAX);
96
- while (1) {
97
- ssize_t n = xread(po.out, buf, LARGE_PACKET_MAX);
98
- if (n <= 0)
99
- break;
100
- send_sideband(fd, -1, buf, n, LARGE_PACKET_MAX);
101
- }
102
- free(buf);
103
- close(po.out);
104
- po.out = -1;
105
- }
106
-
107
- if (finish_command(&po))
108
- return -1;
109
- return 0;
110
-}
111
-
112
-static int receive_status(int in, struct ref *refs)
113
-{
114
- struct ref *hint;
115
- char line[1000];
116
- int ret = 0;
117
- int len = packet_read_line(in, line, sizeof(line));
118
- if (len < 10 || memcmp(line, "unpack ", 7))
119
- return error("did not receive remote status");
120
- if (memcmp(line, "unpack ok\n", 10)) {
121
- char *p = line + strlen(line) - 1;
122
- if (*p == '\n')
123
- *p = '\0';
124
- error("unpack failed: %s", line + 7);
125
- ret = -1;
126
- }
127
- hint = NULL;
128
- while (1) {
129
- char *refname;
130
- char *msg;
131
- len = packet_read_line(in, line, sizeof(line));
132
- if (!len)
133
- break;
134
- if (len < 3 ||
135
- (memcmp(line, "ok ", 3) && memcmp(line, "ng ", 3))) {
136
- fprintf(stderr, "protocol error: %s\n", line);
137
- ret = -1;
138
- break;
139
- }
140
-
141
- line[strlen(line)-1] = '\0';
142
- refname = line + 3;
143
- msg = strchr(refname, ' ');
144
- if (msg)
145
- *msg++ = '\0';
146
-
147
- /* first try searching at our hint, falling back to all refs */
148
- if (hint)
149
- hint = find_ref_by_name(hint, refname);
150
- if (!hint)
151
- hint = find_ref_by_name(refs, refname);
152
- if (!hint) {
153
- warning("remote reported status on unknown ref: %s",
154
- refname);
155
- continue;
156
- }
157
- if (hint->status != REF_STATUS_EXPECTING_REPORT) {
158
- warning("remote reported status on unexpected ref: %s",
159
- refname);
160
- continue;
161
- }
162
-
163
- if (line[0] == 'o' && line[1] == 'k')
164
- hint->status = REF_STATUS_OK;
165
- else {
166
- hint->status = REF_STATUS_REMOTE_REJECT;
167
- ret = -1;
168
- }
169
- if (msg)
170
- hint->remote_status = xstrdup(msg);
171
- /* start our next search from the next ref */
172
- hint = hint->next;
173
- }
174
- return ret;
175
-}
176
-
19
static void print_helper_status(struct ref *ref)
20
{
21
struct strbuf buf = STRBUF_INIT;
@@ -227,181 +69,6 @@ static void print_helper_status(struct ref *ref)
69
strbuf_release(&buf);
70
}
71
230
-static int sideband_demux(int in, int out, void *data)
231
-{
232
- int *fd = data, ret;
233
-#ifdef NO_PTHREADS
234
- close(fd[1]);
235
-#endif
236
- ret = recv_sideband("send-pack", fd[0], out);
237
- close(out);
238
- return ret;
239
-}
240
-
241
-int send_pack(struct send_pack_args *args,
242
- int fd[], struct child_process *conn,
243
- struct ref *remote_refs,
244
- struct extra_have_objects *extra_have)
245
-{
246
- int in = fd[0];
247
- int out = fd[1];
248
- struct strbuf req_buf = STRBUF_INIT;
249
- struct ref *ref;
250
- int new_refs;
251
- int allow_deleting_refs = 0;
252
- int status_report = 0;
253
- int use_sideband = 0;
254
- int quiet_supported = 0;
255
- int agent_supported = 0;
256
- unsigned cmds_sent = 0;
257
- int ret;
258
- struct async demux;
259
-
260
- /* Does the other end support the reporting? */
261
- if (server_supports("report-status"))
262
- status_report = 1;
263
- if (server_supports("delete-refs"))
264
- allow_deleting_refs = 1;
265
- if (server_supports("ofs-delta"))
266
- args->use_ofs_delta = 1;
267
- if (server_supports("side-band-64k"))
268
- use_sideband = 1;
269
- if (server_supports("quiet"))
270
- quiet_supported = 1;
271
- if (server_supports("agent"))
272
- agent_supported = 1;
273
-
274
- if (!remote_refs) {
275
- fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
276
- "Perhaps you should specify a branch such as 'master'.\n");
277
- return 0;
278
- }
279
-
280
- /*
281
- * Finally, tell the other end!
282
- */
283
- new_refs = 0;
284
- for (ref = remote_refs; ref; ref = ref->next) {
285
- if (!ref->peer_ref && !args->send_mirror)
286
- continue;
287
-
288
- /* Check for statuses set by set_ref_status_for_push() */
289
- switch (ref->status) {
290
- case REF_STATUS_REJECT_NONFASTFORWARD:
291
- case REF_STATUS_UPTODATE:
292
- continue;
293
- default:
294
- ; /* do nothing */
295
- }
296
-
297
- if (ref->deletion && !allow_deleting_refs) {
298
- ref->status = REF_STATUS_REJECT_NODELETE;
299
- continue;
300
- }
301
-
302
- if (!ref->deletion)
303
- new_refs++;
304
-
305
- if (args->dry_run) {
306
- ref->status = REF_STATUS_OK;
307
- } else {
308
- char *old_hex = sha1_to_hex(ref->old_sha1);
309
- char *new_hex = sha1_to_hex(ref->new_sha1);
310
- int quiet = quiet_supported && (args->quiet || !args->progress);
311
-
312
- if (!cmds_sent && (status_report || use_sideband ||
313
- quiet || agent_supported)) {
314
- packet_buf_write(&req_buf,
315
- "%s %s %s%c%s%s%s%s%s",
316
- old_hex, new_hex, ref->name, 0,
317
- status_report ? " report-status" : "",
318
- use_sideband ? " side-band-64k" : "",
319
- quiet ? " quiet" : "",
320
- agent_supported ? " agent=" : "",
321
- agent_supported ? git_user_agent_sanitized() : ""
322
- );
323
- }
324
- else
325
- packet_buf_write(&req_buf, "%s %s %s",
326
- old_hex, new_hex, ref->name);
327
- ref->status = status_report ?
328
- REF_STATUS_EXPECTING_REPORT :
329
- REF_STATUS_OK;
330
- cmds_sent++;
331
- }
332
- }
333
-
334
- if (args->stateless_rpc) {
335
- if (!args->dry_run && cmds_sent) {
336
- packet_buf_flush(&req_buf);
337
- send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
338
- }
339
- } else {
340
- safe_write(out, req_buf.buf, req_buf.len);
341
- packet_flush(out);
342
- }
343
- strbuf_release(&req_buf);
344
-
345
- if (use_sideband && cmds_sent) {
346
- memset(&demux, 0, sizeof(demux));
347
- demux.proc = sideband_demux;
348
- demux.data = fd;
349
- demux.out = -1;
350
- if (start_async(&demux))
351
- die("send-pack: unable to fork off sideband demultiplexer");
352
- in = demux.out;
353
- }
354
-
355
- if (new_refs && cmds_sent) {
356
- if (pack_objects(out, remote_refs, extra_have, args) < 0) {
357
- for (ref = remote_refs; ref; ref = ref->next)
358
- ref->status = REF_STATUS_NONE;
359
- if (args->stateless_rpc)
360
- close(out);
361
- if (git_connection_is_socket(conn))
362
- shutdown(fd[0], SHUT_WR);
363
- if (use_sideband)
364
- finish_async(&demux);
365
- return -1;
366
- }
367
- }
368
- if (args->stateless_rpc && cmds_sent)
369
- packet_flush(out);
370
-
371
- if (status_report && cmds_sent)
372
- ret = receive_status(in, remote_refs);
373
- else
374
- ret = 0;
375
- if (args->stateless_rpc)
376
- packet_flush(out);
377
-
378
- if (use_sideband && cmds_sent) {
379
- if (finish_async(&demux)) {
380
- error("error in sideband demultiplexer");
381
- ret = -1;
382
- }
383
- close(demux.out);
384
- }
385
-
386
- if (ret < 0)
387
- return ret;
388
-
389
- if (args->porcelain)
390
- return 0;
391
-
392
- for (ref = remote_refs; ref; ref = ref->next) {
393
- switch (ref->status) {
394
- case REF_STATUS_NONE:
395
- case REF_STATUS_UPTODATE:
396
- case REF_STATUS_OK:
397
- break;
398
- default:
399
- return -1;
400
- }
401
- }
402
- return 0;
403
-}
404
-
72
int cmd_send_pack(int argc, const char **argv, const char *prefix)
73
{
74
int i, nr_refspecs = 0;
send-pack.c
new
+344
@@ -0,0 +1,344 @@
1
+#include "builtin.h"
2
+#include "commit.h"
3
+#include "refs.h"
4
+#include "pkt-line.h"
5
+#include "sideband.h"
6
+#include "run-command.h"
7
+#include "remote.h"
8
+#include "send-pack.h"
9
+#include "quote.h"
10
+#include "transport.h"
11
+#include "version.h"
12
+
13
+static int feed_object(const unsigned char *sha1, int fd, int negative)
14
+{
15
+ char buf[42];
16
+
17
+ if (negative && !has_sha1_file(sha1))
18
+ return 1;
19
+
20
+ memcpy(buf + negative, sha1_to_hex(sha1), 40);
21
+ if (negative)
22
+ buf[0] = '^';
23
+ buf[40 + negative] = '\n';
24
+ return write_or_whine(fd, buf, 41 + negative, "send-pack: send refs");
25
+}
26
+
27
+/*
28
+ * Make a pack stream and spit it out into file descriptor fd
29
+ */
30
+static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra, struct send_pack_args *args)
31
+{
32
+ /*
33
+ * The child becomes pack-objects --revs; we feed
34
+ * the revision parameters to it via its stdin and
35
+ * let its stdout go back to the other end.
36
+ */
37
+ const char *argv[] = {
38
+ "pack-objects",
39
+ "--all-progress-implied",
40
+ "--revs",
41
+ "--stdout",
42
+ NULL,
43
+ NULL,
44
+ NULL,
45
+ NULL,
46
+ NULL,
47
+ };
48
+ struct child_process po;
49
+ int i;
50
+
51
+ i = 4;
52
+ if (args->use_thin_pack)
53
+ argv[i++] = "--thin";
54
+ if (args->use_ofs_delta)
55
+ argv[i++] = "--delta-base-offset";
56
+ if (args->quiet || !args->progress)
57
+ argv[i++] = "-q";
58
+ if (args->progress)
59
+ argv[i++] = "--progress";
60
+ memset(&po, 0, sizeof(po));
61
+ po.argv = argv;
62
+ po.in = -1;
63
+ po.out = args->stateless_rpc ? -1 : fd;
64
+ po.git_cmd = 1;
65
+ if (start_command(&po))
66
+ die_errno("git pack-objects failed");
67
+
68
+ /*
69
+ * We feed the pack-objects we just spawned with revision
70
+ * parameters by writing to the pipe.
71
+ */
72
+ for (i = 0; i < extra->nr; i++)
73
+ if (!feed_object(extra->array[i], po.in, 1))
74
+ break;
75
+
76
+ while (refs) {
77
+ if (!is_null_sha1(refs->old_sha1) &&
78
+ !feed_object(refs->old_sha1, po.in, 1))
79
+ break;
80
+ if (!is_null_sha1(refs->new_sha1) &&
81
+ !feed_object(refs->new_sha1, po.in, 0))
82
+ break;
83
+ refs = refs->next;
84
+ }
85
+
86
+ close(po.in);
87
+
88
+ if (args->stateless_rpc) {
89
+ char *buf = xmalloc(LARGE_PACKET_MAX);
90
+ while (1) {
91
+ ssize_t n = xread(po.out, buf, LARGE_PACKET_MAX);
92
+ if (n <= 0)
93
+ break;
94
+ send_sideband(fd, -1, buf, n, LARGE_PACKET_MAX);
95
+ }
96
+ free(buf);
97
+ close(po.out);
98
+ po.out = -1;
99
+ }
100
+
101
+ if (finish_command(&po))
102
+ return -1;
103
+ return 0;
104
+}
105
+
106
+static int receive_status(int in, struct ref *refs)
107
+{
108
+ struct ref *hint;
109
+ char line[1000];
110
+ int ret = 0;
111
+ int len = packet_read_line(in, line, sizeof(line));
112
+ if (len < 10 || memcmp(line, "unpack ", 7))
113
+ return error("did not receive remote status");
114
+ if (memcmp(line, "unpack ok\n", 10)) {
115
+ char *p = line + strlen(line) - 1;
116
+ if (*p == '\n')
117
+ *p = '\0';
118
+ error("unpack failed: %s", line + 7);
119
+ ret = -1;
120
+ }
121
+ hint = NULL;
122
+ while (1) {
123
+ char *refname;
124
+ char *msg;
125
+ len = packet_read_line(in, line, sizeof(line));
126
+ if (!len)
127
+ break;
128
+ if (len < 3 ||
129
+ (memcmp(line, "ok ", 3) && memcmp(line, "ng ", 3))) {
130
+ fprintf(stderr, "protocol error: %s\n", line);
131
+ ret = -1;
132
+ break;
133
+ }
134
+
135
+ line[strlen(line)-1] = '\0';
136
+ refname = line + 3;
137
+ msg = strchr(refname, ' ');
138
+ if (msg)
139
+ *msg++ = '\0';
140
+
141
+ /* first try searching at our hint, falling back to all refs */
142
+ if (hint)
143
+ hint = find_ref_by_name(hint, refname);
144
+ if (!hint)
145
+ hint = find_ref_by_name(refs, refname);
146
+ if (!hint) {
147
+ warning("remote reported status on unknown ref: %s",
148
+ refname);
149
+ continue;
150
+ }
151
+ if (hint->status != REF_STATUS_EXPECTING_REPORT) {
152
+ warning("remote reported status on unexpected ref: %s",
153
+ refname);
154
+ continue;
155
+ }
156
+
157
+ if (line[0] == 'o' && line[1] == 'k')
158
+ hint->status = REF_STATUS_OK;
159
+ else {
160
+ hint->status = REF_STATUS_REMOTE_REJECT;
161
+ ret = -1;
162
+ }
163
+ if (msg)
164
+ hint->remote_status = xstrdup(msg);
165
+ /* start our next search from the next ref */
166
+ hint = hint->next;
167
+ }
168
+ return ret;
169
+}
170
+
171
+static int sideband_demux(int in, int out, void *data)
172
+{
173
+ int *fd = data, ret;
174
+#ifdef NO_PTHREADS
175
+ close(fd[1]);
176
+#endif
177
+ ret = recv_sideband("send-pack", fd[0], out);
178
+ close(out);
179
+ return ret;
180
+}
181
+
182
+int send_pack(struct send_pack_args *args,
183
+ int fd[], struct child_process *conn,
184
+ struct ref *remote_refs,
185
+ struct extra_have_objects *extra_have)
186
+{
187
+ int in = fd[0];
188
+ int out = fd[1];
189
+ struct strbuf req_buf = STRBUF_INIT;
190
+ struct ref *ref;
191
+ int new_refs;
192
+ int allow_deleting_refs = 0;
193
+ int status_report = 0;
194
+ int use_sideband = 0;
195
+ int quiet_supported = 0;
196
+ int agent_supported = 0;
197
+ unsigned cmds_sent = 0;
198
+ int ret;
199
+ struct async demux;
200
+
201
+ /* Does the other end support the reporting? */
202
+ if (server_supports("report-status"))
203
+ status_report = 1;
204
+ if (server_supports("delete-refs"))
205
+ allow_deleting_refs = 1;
206
+ if (server_supports("ofs-delta"))
207
+ args->use_ofs_delta = 1;
208
+ if (server_supports("side-band-64k"))
209
+ use_sideband = 1;
210
+ if (server_supports("quiet"))
211
+ quiet_supported = 1;
212
+ if (server_supports("agent"))
213
+ agent_supported = 1;
214
+
215
+ if (!remote_refs) {
216
+ fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
217
+ "Perhaps you should specify a branch such as 'master'.\n");
218
+ return 0;
219
+ }
220
+
221
+ /*
222
+ * Finally, tell the other end!
223
+ */
224
+ new_refs = 0;
225
+ for (ref = remote_refs; ref; ref = ref->next) {
226
+ if (!ref->peer_ref && !args->send_mirror)
227
+ continue;
228
+
229
+ /* Check for statuses set by set_ref_status_for_push() */
230
+ switch (ref->status) {
231
+ case REF_STATUS_REJECT_NONFASTFORWARD:
232
+ case REF_STATUS_UPTODATE:
233
+ continue;
234
+ default:
235
+ ; /* do nothing */
236
+ }
237
+
238
+ if (ref->deletion && !allow_deleting_refs) {
239
+ ref->status = REF_STATUS_REJECT_NODELETE;
240
+ continue;
241
+ }
242
+
243
+ if (!ref->deletion)
244
+ new_refs++;
245
+
246
+ if (args->dry_run) {
247
+ ref->status = REF_STATUS_OK;
248
+ } else {
249
+ char *old_hex = sha1_to_hex(ref->old_sha1);
250
+ char *new_hex = sha1_to_hex(ref->new_sha1);
251
+ int quiet = quiet_supported && (args->quiet || !args->progress);
252
+
253
+ if (!cmds_sent && (status_report || use_sideband ||
254
+ quiet || agent_supported)) {
255
+ packet_buf_write(&req_buf,
256
+ "%s %s %s%c%s%s%s%s%s",
257
+ old_hex, new_hex, ref->name, 0,
258
+ status_report ? " report-status" : "",
259
+ use_sideband ? " side-band-64k" : "",
260
+ quiet ? " quiet" : "",
261
+ agent_supported ? " agent=" : "",
262
+ agent_supported ? git_user_agent_sanitized() : ""
263
+ );
264
+ }
265
+ else
266
+ packet_buf_write(&req_buf, "%s %s %s",
267
+ old_hex, new_hex, ref->name);
268
+ ref->status = status_report ?
269
+ REF_STATUS_EXPECTING_REPORT :
270
+ REF_STATUS_OK;
271
+ cmds_sent++;
272
+ }
273
+ }
274
+
275
+ if (args->stateless_rpc) {
276
+ if (!args->dry_run && cmds_sent) {
277
+ packet_buf_flush(&req_buf);
278
+ send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
279
+ }
280
+ } else {
281
+ safe_write(out, req_buf.buf, req_buf.len);
282
+ packet_flush(out);
283
+ }
284
+ strbuf_release(&req_buf);
285
+
286
+ if (use_sideband && cmds_sent) {
287
+ memset(&demux, 0, sizeof(demux));
288
+ demux.proc = sideband_demux;
289
+ demux.data = fd;
290
+ demux.out = -1;
291
+ if (start_async(&demux))
292
+ die("send-pack: unable to fork off sideband demultiplexer");
293
+ in = demux.out;
294
+ }
295
+
296
+ if (new_refs && cmds_sent) {
297
+ if (pack_objects(out, remote_refs, extra_have, args) < 0) {
298
+ for (ref = remote_refs; ref; ref = ref->next)
299
+ ref->status = REF_STATUS_NONE;
300
+ if (args->stateless_rpc)
301
+ close(out);
302
+ if (git_connection_is_socket(conn))
303
+ shutdown(fd[0], SHUT_WR);
304
+ if (use_sideband)
305
+ finish_async(&demux);
306
+ return -1;
307
+ }
308
+ }
309
+ if (args->stateless_rpc && cmds_sent)
310
+ packet_flush(out);
311
+
312
+ if (status_report && cmds_sent)
313
+ ret = receive_status(in, remote_refs);
314
+ else
315
+ ret = 0;
316
+ if (args->stateless_rpc)
317
+ packet_flush(out);
318
+
319
+ if (use_sideband && cmds_sent) {
320
+ if (finish_async(&demux)) {
321
+ error("error in sideband demultiplexer");
322
+ ret = -1;
323
+ }
324
+ close(demux.out);
325
+ }
326
+
327
+ if (ret < 0)
328
+ return ret;
329
+
330
+ if (args->porcelain)
331
+ return 0;
332
+
333
+ for (ref = remote_refs; ref; ref = ref->next) {
334
+ switch (ref->status) {
335
+ case REF_STATUS_NONE:
336
+ case REF_STATUS_UPTODATE:
337
+ case REF_STATUS_OK:
338
+ break;
339
+ default:
340
+ return -1;
341
+ }
342
+ }
343
+ return 0;
344
+}
transport.h
+5
@@ -175,4 +175,9 @@ void transport_print_push_status(const char *dest, struct ref *refs,
175
typedef void alternate_ref_fn(const struct ref *, void *);
176
extern void for_each_alternate_ref(alternate_ref_fn, void *);
177
178
+struct send_pack_args;
179
+extern int send_pack(struct send_pack_args *args,
180
+ int fd[], struct child_process *conn,
181
+ struct ref *remote_refs,
182
+ struct extra_have_objects *extra_have);
183
#endif