Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Smart push over HTTP: client side

The git-remote-curl backend detects if the remote server supports
the git-receive-pack service, and if so, runs git-send-pack in a
pipe to dump the command and pack data as a single POST request.

The advertisements from the server that were obtained during the
discovery are passed into git-send-pack before the POST request
starts.  This permits git-send-pack to operate largely unmodified.

For smaller packs (those under 1 MiB) a HTTP/1.0 POST with a
Content-Length is used, permitting interaction with any server.
The 1 MiB limit is arbitrary, but is sufficent to fit most deltas
created by human authors against text sources with the occasional
small binary file (e.g. few KiB icon image).  The configuration
option http.postBuffer can be used to increase (or shink) this
buffer if the default is not sufficient.

For larger packs which cannot be spooled entirely into the helper's
memory space (due to http.postBuffer being too small), the POST
request requires HTTP/1.1 and sets "Transfer-Encoding: chunked".
This permits the client to upload an unknown amount of data in one
HTTP transaction without needing to pregenerate the entire pack
file locally.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
CC: Daniel Barkalow <barkalow@iabervon.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information...
commit de1a2fdd38b138c4e4fed6412783dcb74d63d2da 1 parent 97cc7bc
Shawn O. Pearce authored October 30, 2009 gitster committed November 04, 2009
8  Documentation/config.txt
@@ -1089,6 +1089,14 @@ http.maxRequests::
1089 1089
 	How many HTTP requests to launch in parallel. Can be overridden
1090 1090
 	by the 'GIT_HTTP_MAX_REQUESTS' environment variable. Default is 5.
1091 1091
 
  1092
+http.postBuffer::
  1093
+	Maximum size in bytes of the buffer used by smart HTTP
  1094
+	transports when POSTing data to the remote system.
  1095
+	For requests larger than this buffer size, HTTP/1.1 and
  1096
+	Transfer-Encoding: chunked is used to avoid creating a
  1097
+	massive pack file locally.  Default is 1 MiB, which is
  1098
+	sufficient for most requests.
  1099
+
1092 1100
 http.lowSpeedLimit, http.lowSpeedTime::
1093 1101
 	If the HTTP transfer speed is less than 'http.lowSpeedLimit'
1094 1102
 	for longer than 'http.lowSpeedTime' seconds, the transfer is aborted.
116  builtin-send-pack.c
@@ -2,9 +2,11 @@
2 2
 #include "commit.h"
3 3
 #include "refs.h"
4 4
 #include "pkt-line.h"
  5
+#include "sideband.h"
5 6
 #include "run-command.h"
6 7
 #include "remote.h"
7 8
 #include "send-pack.h"
  9
+#include "quote.h"
8 10
 
9 11
 static const char send_pack_usage[] =
10 12
 "git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
@@ -59,7 +61,7 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
59 61
 	memset(&po, 0, sizeof(po));
60 62
 	po.argv = argv;
61 63
 	po.in = -1;
62  
-	po.out = fd;
  64
+	po.out = args->stateless_rpc ? -1 : fd;
63 65
 	po.git_cmd = 1;
64 66
 	if (start_command(&po))
65 67
 		die_errno("git pack-objects failed");
@@ -83,6 +85,20 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
83 85
 	}
84 86
 
85 87
 	close(po.in);
  88
+
  89
+	if (args->stateless_rpc) {
  90
+		char *buf = xmalloc(LARGE_PACKET_MAX);
  91
+		while (1) {
  92
+			ssize_t n = xread(po.out, buf, LARGE_PACKET_MAX);
  93
+			if (n <= 0)
  94
+				break;
  95
+			send_sideband(fd, -1, buf, n, LARGE_PACKET_MAX);
  96
+		}
  97
+		free(buf);
  98
+		close(po.out);
  99
+		po.out = -1;
  100
+	}
  101
+
86 102
 	if (finish_command(&po))
87 103
 		return error("pack-objects died with strange error");
88 104
 	return 0;
@@ -303,6 +319,59 @@ static int refs_pushed(struct ref *ref)
303 319
 	return 0;
304 320
 }
305 321
 
  322
+static void print_helper_status(struct ref *ref)
  323
+{
  324
+	struct strbuf buf = STRBUF_INIT;
  325
+
  326
+	for (; ref; ref = ref->next) {
  327
+		const char *msg = NULL;
  328
+		const char *res;
  329
+
  330
+		switch(ref->status) {
  331
+		case REF_STATUS_NONE:
  332
+			res = "error";
  333
+			msg = "no match";
  334
+			break;
  335
+
  336
+		case REF_STATUS_OK:
  337
+			res = "ok";
  338
+			break;
  339
+
  340
+		case REF_STATUS_UPTODATE:
  341
+			res = "ok";
  342
+			msg = "up to date";
  343
+			break;
  344
+
  345
+		case REF_STATUS_REJECT_NONFASTFORWARD:
  346
+			res = "error";
  347
+			msg = "non-fast forward";
  348
+			break;
  349
+
  350
+		case REF_STATUS_REJECT_NODELETE:
  351
+		case REF_STATUS_REMOTE_REJECT:
  352
+			res = "error";
  353
+			break;
  354
+
  355
+		case REF_STATUS_EXPECTING_REPORT:
  356
+		default:
  357
+			continue;
  358
+		}
  359
+
  360
+		strbuf_reset(&buf);
  361
+		strbuf_addf(&buf, "%s %s", res, ref->name);
  362
+		if (ref->remote_status)
  363
+			msg = ref->remote_status;
  364
+		if (msg) {
  365
+			strbuf_addch(&buf, ' ');
  366
+			quote_two_c_style(&buf, "", msg, 0);
  367
+		}
  368
+		strbuf_addch(&buf, '\n');
  369
+
  370
+		safe_write(1, buf.buf, buf.len);
  371
+	}
  372
+	strbuf_release(&buf);
  373
+}
  374
+
306 375
 int send_pack(struct send_pack_args *args,
307 376
 	      int fd[], struct child_process *conn,
308 377
 	      struct ref *remote_refs,
@@ -310,6 +379,7 @@ int send_pack(struct send_pack_args *args,
310 379
 {
311 380
 	int in = fd[0];
312 381
 	int out = fd[1];
  382
+	struct strbuf req_buf = STRBUF_INIT;
313 383
 	struct ref *ref;
314 384
 	int new_refs;
315 385
 	int ask_for_status_report = 0;
@@ -391,14 +461,14 @@ int send_pack(struct send_pack_args *args,
391 461
 			char *new_hex = sha1_to_hex(ref->new_sha1);
392 462
 
393 463
 			if (ask_for_status_report) {
394  
-				packet_write(out, "%s %s %s%c%s",
  464
+				packet_buf_write(&req_buf, "%s %s %s%c%s",
395 465
 					old_hex, new_hex, ref->name, 0,
396 466
 					"report-status");
397 467
 				ask_for_status_report = 0;
398 468
 				expect_status_report = 1;
399 469
 			}
400 470
 			else
401  
-				packet_write(out, "%s %s %s",
  471
+				packet_buf_write(&req_buf, "%s %s %s",
402 472
 					old_hex, new_hex, ref->name);
403 473
 		}
404 474
 		ref->status = expect_status_report ?
@@ -406,7 +476,17 @@ int send_pack(struct send_pack_args *args,
406 476
 			REF_STATUS_OK;
407 477
 	}
408 478
 
409  
-	packet_flush(out);
  479
+	if (args->stateless_rpc) {
  480
+		if (!args->dry_run) {
  481
+			packet_buf_flush(&req_buf);
  482
+			send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
  483
+		}
  484
+	} else {
  485
+		safe_write(out, req_buf.buf, req_buf.len);
  486
+		packet_flush(out);
  487
+	}
  488
+	strbuf_release(&req_buf);
  489
+
410 490
 	if (new_refs && !args->dry_run) {
411 491
 		if (pack_objects(out, remote_refs, extra_have, args) < 0) {
412 492
 			for (ref = remote_refs; ref; ref = ref->next)
@@ -414,11 +494,15 @@ int send_pack(struct send_pack_args *args,
414 494
 			return -1;
415 495
 		}
416 496
 	}
  497
+	if (args->stateless_rpc && !args->dry_run)
  498
+		packet_flush(out);
417 499
 
418 500
 	if (expect_status_report)
419 501
 		ret = receive_status(in, remote_refs);
420 502
 	else
421 503
 		ret = 0;
  504
+	if (args->stateless_rpc)
  505
+		packet_flush(out);
422 506
 
423 507
 	if (ret < 0)
424 508
 		return ret;
@@ -478,6 +562,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
478 562
 	struct extra_have_objects extra_have;
479 563
 	struct ref *remote_refs, *local_refs;
480 564
 	int ret;
  565
+	int helper_status = 0;
481 566
 	int send_all = 0;
482 567
 	const char *receivepack = "git-receive-pack";
483 568
 	int flags;
@@ -523,6 +608,14 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
523 608
 				args.use_thin_pack = 1;
524 609
 				continue;
525 610
 			}
  611
+			if (!strcmp(arg, "--stateless-rpc")) {
  612
+				args.stateless_rpc = 1;
  613
+				continue;
  614
+			}
  615
+			if (!strcmp(arg, "--helper-status")) {
  616
+				helper_status = 1;
  617
+				continue;
  618
+			}
526 619
 			usage(send_pack_usage);
527 620
 		}
528 621
 		if (!dest) {
@@ -551,7 +644,14 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
551 644
 		}
552 645
 	}
553 646
 
554  
-	conn = git_connect(fd, dest, receivepack, args.verbose ? CONNECT_VERBOSE : 0);
  647
+	if (args.stateless_rpc) {
  648
+		conn = NULL;
  649
+		fd[0] = 0;
  650
+		fd[1] = 1;
  651
+	} else {
  652
+		conn = git_connect(fd, dest, receivepack,
  653
+			args.verbose ? CONNECT_VERBOSE : 0);
  654
+	}
555 655
 
556 656
 	memset(&extra_have, 0, sizeof(extra_have));
557 657
 
@@ -575,12 +675,16 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
575 675
 
576 676
 	ret = send_pack(&args, fd, conn, remote_refs, &extra_have);
577 677
 
  678
+	if (helper_status)
  679
+		print_helper_status(remote_refs);
  680
+
578 681
 	close(fd[1]);
579 682
 	close(fd[0]);
580 683
 
581 684
 	ret |= finish_connect(conn);
582 685
 
583  
-	print_push_status(dest, remote_refs);
  686
+	if (!helper_status)
  687
+		print_push_status(dest, remote_refs);
584 688
 
585 689
 	if (!args.dry_run && remote) {
586 690
 		struct ref *ref;
13  http.c
... ...
@@ -1,9 +1,11 @@
1 1
 #include "http.h"
2 2
 #include "pack.h"
  3
+#include "sideband.h"
3 4
 
4 5
 int data_received;
5 6
 int active_requests;
6 7
 int http_is_verbose;
  8
+size_t http_post_buffer = 16 * LARGE_PACKET_MAX;
7 9
 
8 10
 #ifdef USE_CURL_MULTI
9 11
 static int max_requests = -1;
@@ -97,8 +99,6 @@ size_t fwrite_null(const void *ptr, size_t eltsize, size_t nmemb, void *strbuf)
97 99
 	return eltsize * nmemb;
98 100
 }
99 101
 
100  
-static void finish_active_slot(struct active_request_slot *slot);
101  
-
102 102
 #ifdef USE_CURL_MULTI
103 103
 static void process_curl_messages(void)
104 104
 {
@@ -174,6 +174,13 @@ static int http_options(const char *var, const char *value, void *cb)
174 174
 	if (!strcmp("http.proxy", var))
175 175
 		return git_config_string(&curl_http_proxy, var, value);
176 176
 
  177
+	if (!strcmp("http.postbuffer", var)) {
  178
+		http_post_buffer = git_config_int(var, value);
  179
+		if (http_post_buffer < LARGE_PACKET_MAX)
  180
+			http_post_buffer = LARGE_PACKET_MAX;
  181
+		return 0;
  182
+	}
  183
+
177 184
 	/* Fall back on the default ones */
178 185
 	return git_default_config(var, value, cb);
179 186
 }
@@ -638,7 +645,7 @@ void release_active_slot(struct active_request_slot *slot)
638 645
 #endif
639 646
 }
640 647
 
641  
-static void finish_active_slot(struct active_request_slot *slot)
  648
+void finish_active_slot(struct active_request_slot *slot)
642 649
 {
643 650
 	closedown_active_slot(slot);
644 651
 	curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code);
2  http.h
@@ -79,6 +79,7 @@ extern curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp);
79 79
 extern struct active_request_slot *get_active_slot(void);
80 80
 extern int start_active_slot(struct active_request_slot *slot);
81 81
 extern void run_active_slot(struct active_request_slot *slot);
  82
+extern void finish_active_slot(struct active_request_slot *slot);
82 83
 extern void finish_all_active_slots(void);
83 84
 extern void release_active_slot(struct active_request_slot *slot);
84 85
 
@@ -94,6 +95,7 @@ extern void http_cleanup(void);
94 95
 extern int data_received;
95 96
 extern int active_requests;
96 97
 extern int http_is_verbose;
  98
+extern size_t http_post_buffer;
97 99
 
98 100
 extern char curl_errorstr[CURL_ERROR_SIZE];
99 101
 
235  remote-curl.c
@@ -6,6 +6,7 @@
6 6
 #include "exec_cmd.h"
7 7
 #include "run-command.h"
8 8
 #include "pkt-line.h"
  9
+#include "sideband.h"
9 10
 
10 11
 static struct remote *remote;
11 12
 static const char *url;
@@ -16,7 +17,8 @@ struct options {
16 17
 	unsigned long depth;
17 18
 	unsigned progress : 1,
18 19
 		followtags : 1,
19  
-		dry_run : 1;
  20
+		dry_run : 1,
  21
+		thin : 1;
20 22
 };
21 23
 static struct options options;
22 24
 
@@ -274,6 +276,188 @@ static void output_refs(struct ref *refs)
274 276
 	free_refs(refs);
275 277
 }
276 278
 
  279
+struct rpc_state {
  280
+	const char *service_name;
  281
+	const char **argv;
  282
+	char *service_url;
  283
+	char *hdr_content_type;
  284
+	char *hdr_accept;
  285
+	char *buf;
  286
+	size_t alloc;
  287
+	size_t len;
  288
+	size_t pos;
  289
+	int in;
  290
+	int out;
  291
+	struct strbuf result;
  292
+};
  293
+
  294
+static size_t rpc_out(void *ptr, size_t eltsize,
  295
+		size_t nmemb, void *buffer_)
  296
+{
  297
+	size_t max = eltsize * nmemb;
  298
+	struct rpc_state *rpc = buffer_;
  299
+	size_t avail = rpc->len - rpc->pos;
  300
+
  301
+	if (!avail) {
  302
+		avail = packet_read_line(rpc->out, rpc->buf, rpc->alloc);
  303
+		if (!avail)
  304
+			return 0;
  305
+		rpc->pos = 0;
  306
+		rpc->len = avail;
  307
+	}
  308
+
  309
+	if (max < avail);
  310
+		avail = max;
  311
+	memcpy(ptr, rpc->buf + rpc->pos, avail);
  312
+	rpc->pos += avail;
  313
+	return avail;
  314
+}
  315
+
  316
+static size_t rpc_in(const void *ptr, size_t eltsize,
  317
+		size_t nmemb, void *buffer_)
  318
+{
  319
+	size_t size = eltsize * nmemb;
  320
+	struct rpc_state *rpc = buffer_;
  321
+	write_or_die(rpc->in, ptr, size);
  322
+	return size;
  323
+}
  324
+
  325
+static int post_rpc(struct rpc_state *rpc)
  326
+{
  327
+	struct active_request_slot *slot;
  328
+	struct slot_results results;
  329
+	struct curl_slist *headers = NULL;
  330
+	int err = 0, large_request = 0;
  331
+
  332
+	/* Try to load the entire request, if we can fit it into the
  333
+	 * allocated buffer space we can use HTTP/1.0 and avoid the
  334
+	 * chunked encoding mess.
  335
+	 */
  336
+	while (1) {
  337
+		size_t left = rpc->alloc - rpc->len;
  338
+		char *buf = rpc->buf + rpc->len;
  339
+		int n;
  340
+
  341
+		if (left < LARGE_PACKET_MAX) {
  342
+			large_request = 1;
  343
+			break;
  344
+		}
  345
+
  346
+		n = packet_read_line(rpc->out, buf, left);
  347
+		if (!n)
  348
+			break;
  349
+		rpc->len += n;
  350
+	}
  351
+
  352
+	slot = get_active_slot();
  353
+	slot->results = &results;
  354
+
  355
+	curl_easy_setopt(slot->curl, CURLOPT_POST, 1);
  356
+	curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
  357
+	curl_easy_setopt(slot->curl, CURLOPT_URL, rpc->service_url);
  358
+
  359
+	headers = curl_slist_append(headers, rpc->hdr_content_type);
  360
+	headers = curl_slist_append(headers, rpc->hdr_accept);
  361
+
  362
+	if (large_request) {
  363
+		/* The request body is large and the size cannot be predicted.
  364
+		 * We must use chunked encoding to send it.
  365
+		 */
  366
+		headers = curl_slist_append(headers, "Expect: 100-continue");
  367
+		headers = curl_slist_append(headers, "Transfer-Encoding: chunked");
  368
+		curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, rpc_out);
  369
+		curl_easy_setopt(slot->curl, CURLOPT_INFILE, rpc);
  370
+		if (options.verbosity > 1) {
  371
+			fprintf(stderr, "POST %s (chunked)\n", rpc->service_name);
  372
+			fflush(stderr);
  373
+		}
  374
+
  375
+	} else {
  376
+		/* We know the complete request size in advance, use the
  377
+		 * more normal Content-Length approach.
  378
+		 */
  379
+		curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, rpc->buf);
  380
+		curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, rpc->len);
  381
+		if (options.verbosity > 1) {
  382
+			fprintf(stderr, "POST %s (%lu bytes)\n",
  383
+				rpc->service_name, (unsigned long)rpc->len);
  384
+			fflush(stderr);
  385
+		}
  386
+	}
  387
+
  388
+	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers);
  389
+	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, rpc_in);
  390
+	curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc);
  391
+
  392
+	slot->curl_result = curl_easy_perform(slot->curl);
  393
+	finish_active_slot(slot);
  394
+
  395
+	if (results.curl_result != CURLE_OK) {
  396
+		err |= error("RPC failed; result=%d, HTTP code = %ld",
  397
+			results.curl_result, results.http_code);
  398
+	}
  399
+
  400
+	curl_slist_free_all(headers);
  401
+	return err;
  402
+}
  403
+
  404
+static int rpc_service(struct rpc_state *rpc, struct discovery *heads)
  405
+{
  406
+	const char *svc = rpc->service_name;
  407
+	struct strbuf buf = STRBUF_INIT;
  408
+	struct child_process client;
  409
+	int err = 0;
  410
+
  411
+	init_walker();
  412
+	memset(&client, 0, sizeof(client));
  413
+	client.in = -1;
  414
+	client.out = -1;
  415
+	client.git_cmd = 1;
  416
+	client.argv = rpc->argv;
  417
+	if (start_command(&client))
  418
+		exit(1);
  419
+	if (heads)
  420
+		write_or_die(client.in, heads->buf, heads->len);
  421
+
  422
+	rpc->alloc = http_post_buffer;
  423
+	rpc->buf = xmalloc(rpc->alloc);
  424
+	rpc->in = client.in;
  425
+	rpc->out = client.out;
  426
+	strbuf_init(&rpc->result, 0);
  427
+
  428
+	strbuf_addf(&buf, "%s/%s", url, svc);
  429
+	rpc->service_url = strbuf_detach(&buf, NULL);
  430
+
  431
+	strbuf_addf(&buf, "Content-Type: application/x-%s-request", svc);
  432
+	rpc->hdr_content_type = strbuf_detach(&buf, NULL);
  433
+
  434
+	strbuf_addf(&buf, "Accept: application/x-%s-response", svc);
  435
+	rpc->hdr_accept = strbuf_detach(&buf, NULL);
  436
+
  437
+	while (!err) {
  438
+		int n = packet_read_line(rpc->out, rpc->buf, rpc->alloc);
  439
+		if (!n)
  440
+			break;
  441
+		rpc->pos = 0;
  442
+		rpc->len = n;
  443
+		err |= post_rpc(rpc);
  444
+	}
  445
+	strbuf_read(&rpc->result, client.out, 0);
  446
+
  447
+	close(client.in);
  448
+	close(client.out);
  449
+	client.in = -1;
  450
+	client.out = -1;
  451
+
  452
+	err |= finish_command(&client);
  453
+	free(rpc->service_url);
  454
+	free(rpc->hdr_content_type);
  455
+	free(rpc->hdr_accept);
  456
+	free(rpc->buf);
  457
+	strbuf_release(&buf);
  458
+	return err;
  459
+}
  460
+
277 461
 static int fetch_dumb(int nr_heads, struct ref **to_fetch)
278 462
 {
279 463
 	char **targets = xmalloc(nr_heads * sizeof(char*));
@@ -371,6 +555,52 @@ static int push_dav(int nr_spec, char **specs)
371 555
 	return 0;
372 556
 }
373 557
 
  558
+static int push_git(struct discovery *heads, int nr_spec, char **specs)
  559
+{
  560
+	struct rpc_state rpc;
  561
+	const char **argv;
  562
+	int argc = 0, i, err;
  563
+
  564
+	argv = xmalloc((10 + nr_spec) * sizeof(char*));
  565
+	argv[argc++] = "send-pack";
  566
+	argv[argc++] = "--stateless-rpc";
  567
+	argv[argc++] = "--helper-status";
  568
+	if (options.thin)
  569
+		argv[argc++] = "--thin";
  570
+	if (options.dry_run)
  571
+		argv[argc++] = "--dry-run";
  572
+	if (options.verbosity > 1)
  573
+		argv[argc++] = "--verbose";
  574
+	argv[argc++] = url;
  575
+	for (i = 0; i < nr_spec; i++)
  576
+		argv[argc++] = specs[i];
  577
+	argv[argc++] = NULL;
  578
+
  579
+	memset(&rpc, 0, sizeof(rpc));
  580
+	rpc.service_name = "git-receive-pack",
  581
+	rpc.argv = argv;
  582
+
  583
+	err = rpc_service(&rpc, heads);
  584
+	if (rpc.result.len)
  585
+		safe_write(1, rpc.result.buf, rpc.result.len);
  586
+	strbuf_release(&rpc.result);
  587
+	free(argv);
  588
+	return err;
  589
+}
  590
+
  591
+static int push(int nr_spec, char **specs)
  592
+{
  593
+	struct discovery *heads = discover_refs("git-receive-pack");
  594
+	int ret;
  595
+
  596
+	if (heads->proto_git)
  597
+		ret = push_git(heads, nr_spec, specs);
  598
+	else
  599
+		ret = push_dav(nr_spec, specs);
  600
+	free_discovery(heads);
  601
+	return ret;
  602
+}
  603
+
374 604
 static void parse_push(struct strbuf *buf)
375 605
 {
376 606
 	char **specs = NULL;
@@ -391,7 +621,7 @@ static void parse_push(struct strbuf *buf)
391 621
 			break;
392 622
 	} while (1);
393 623
 
394  
-	if (push_dav(nr_spec, specs))
  624
+	if (push(nr_spec, specs))
395 625
 		exit(128); /* error already reported */
396 626
 	for (i = 0; i < nr_spec; i++)
397 627
 		free(specs[i]);
@@ -414,6 +644,7 @@ int main(int argc, const char **argv)
414 644
 
415 645
 	options.verbosity = 1;
416 646
 	options.progress = !!isatty(2);
  647
+	options.thin = 1;
417 648
 
418 649
 	remote = remote_get(argv[1]);
419 650
 
3  send-pack.h
@@ -8,7 +8,8 @@ struct send_pack_args {
8 8
 		force_update:1,
9 9
 		use_thin_pack:1,
10 10
 		use_ofs_delta:1,
11  
-		dry_run:1;
  11
+		dry_run:1,
  12
+		stateless_rpc:1;
12 13
 };
13 14
 
14 15
 int send_pack(struct send_pack_args *args,
11  sideband.c
@@ -135,9 +135,14 @@ ssize_t send_sideband(int fd, int band, const char *data, ssize_t sz, int packet
135 135
 		n = sz;
136 136
 		if (packet_max - 5 < n)
137 137
 			n = packet_max - 5;
138  
-		sprintf(hdr, "%04x", n + 5);
139  
-		hdr[4] = band;
140  
-		safe_write(fd, hdr, 5);
  138
+		if (0 <= band) {
  139
+			sprintf(hdr, "%04x", n + 5);
  140
+			hdr[4] = band;
  141
+			safe_write(fd, hdr, 5);
  142
+		} else {
  143
+			sprintf(hdr, "%04x", n + 4);
  144
+			safe_write(fd, hdr, 4);
  145
+		}
141 146
 		safe_write(fd, p, n);
142 147
 		p += n;
143 148
 		sz -= n;
1  transport.c
@@ -731,6 +731,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
731 731
 				 NULL);
732 732
 	}
733 733
 
  734
+	memset(&args, 0, sizeof(args));
734 735
 	args.send_mirror = !!(flags & TRANSPORT_PUSH_MIRROR);
735 736
 	args.force_update = !!(flags & TRANSPORT_PUSH_FORCE);
736 737
 	args.use_thin_pack = data->thin;

0 notes on commit de1a2fd

Please sign in to comment.
Something went wrong with that request. Please try again.