git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org
Cc: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH 6/7] {send,receive}-pack: support pushing from a shallow clone
Date: Wed, 17 Jul 2013 19:47:13 +0700	[thread overview]
Message-ID: <1374065234-870-7-git-send-email-pclouds@gmail.com> (raw)
In-Reply-To: <1374065234-870-1-git-send-email-pclouds@gmail.com>

Pushing from a shallow clone using today's send-pack and receive-pack
may work, if the transferred pack does not ends up at any graft
points. If it does, recent receive-pack that does connectivity check
will reject the push. If receive-pack is old, the upstream repo
becomes corrupt.

The pack protocol is updated and send-pack now sends all shallow
grafts before it sends the commands, if the repo is shallow. This
protocol extension will break current receive-pack, which is intended,
mostly to stop corrupting the upstream repo.

The receiver end, the newreceive-pack, does something similar to
fetch-pack: it creates a temporary shallow file with grafts from
send-pack, then receives the pack, and finally writes the refined
shallow file down.

shadow file is not cleaned up after deleting (or force updating) a ref
if that ref is the only way to reach the graft points. The reason is
once we delete graft points, we can't recover. That may make reflog
entries on server useless. Leave that for the administrators to decide
when to clean up shadow file (maybe at repack/gc time).

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/technical/pack-protocol.txt |  4 +-
 builtin/receive-pack.c                    | 49 ++++++++++++++++++----
 send-pack.c                               |  3 ++
 t/t5537-push-shallow.sh (new +x)          | 67 +++++++++++++++++++++++++++++++
 4 files changed, 114 insertions(+), 9 deletions(-)
 create mode 100755 t/t5537-push-shallow.sh

diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt
index eb8edd1..c73b62f 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -464,7 +464,9 @@ contain all the objects that the server will need to complete the new
 references.
 
 ----
-  update-request    =  command-list [pack-file]
+  update-request    =  *shallow command-list [pack-file]
+
+  shallow           =  PKT-LINE("shallow" SP obj-id)
 
   command-list      =  PKT-LINE(command NUL capability-list LF)
 		       *PKT-LINE(command LF)
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 2d8e19b..0537e26 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -41,6 +41,10 @@ static int auto_gc = 1;
 static const char *head_name;
 static void *head_name_to_free;
 static int sent_capabilities;
+static int shallow_changed;
+static const char* alternate_shallow_file;
+static struct lock_file shallow_lock;
+static struct extra_have_objects shallow;
 
 static enum deny_action parse_deny_action(const char *var, const char *value)
 {
@@ -751,6 +755,13 @@ static void execute_commands(struct command *commands, const char *unpacker_erro
 	}
 }
 
+static void add_extra_have(struct extra_have_objects *extra, unsigned char *sha1)
+{
+	ALLOC_GROW(extra->array, extra->nr + 1, extra->alloc);
+	hashcpy(&(extra->array[extra->nr][0]), sha1);
+	extra->nr++;
+}
+
 static struct command *read_head_info(void)
 {
 	struct command *commands = NULL;
@@ -765,6 +776,17 @@ static struct command *read_head_info(void)
 		line = packet_read_line(0, &len);
 		if (!line)
 			break;
+
+		if (len == 48 && !prefixcmp(line, "shallow ")) {
+			if (get_sha1_hex(line + 8, old_sha1))
+				die("protocol error: expected shallow sha, got '%s'", line + 8);
+			if (!has_sha1_file(old_sha1)) {
+				add_extra_have(&shallow, old_sha1);
+				shallow_changed = 1;
+			}
+			continue;
+		}
+
 		if (len < 83 ||
 		    line[40] != ' ' ||
 		    line[81] != ' ' ||
@@ -827,6 +849,12 @@ static const char *unpack(int err_fd)
 			    ? transfer_fsck_objects
 			    : 0);
 
+	if (shallow_changed)
+		setup_alternate_shallow(&shallow_lock,
+					&alternate_shallow_file,
+					&shallow, 0);
+
+
 	hdr_err = parse_pack_header(&hdr);
 	if (hdr_err) {
 		if (err_fd > 0)
@@ -854,9 +882,8 @@ static const char *unpack(int err_fd)
 		child.err = err_fd;
 		child.git_cmd = 1;
 		code = run_command(&child);
-		if (!code)
-			return NULL;
-		return "unpack-objects abnormal exit";
+		if (code)
+			return "unpack-objects abnormal exit";
 	} else {
 		const char *keeper[7];
 		int s, status, i = 0;
@@ -887,12 +914,18 @@ static const char *unpack(int err_fd)
 		pack_lockfile = index_pack_lockfile(ip.out);
 		close(ip.out);
 		status = finish_command(&ip);
-		if (!status) {
-			reprepare_packed_git();
-			return NULL;
-		}
-		return "index-pack abnormal exit";
+		if (status)
+			return "index-pack abnormal exit";
+		reprepare_packed_git();
+	}
+
+	if (shallow_changed) {
+		setup_alternate_shallow(&shallow_lock,
+					&alternate_shallow_file,
+					&shallow, 1);
+		commit_lock_file(&shallow_lock);
 	}
+	return NULL;
 }
 
 static const char *unpack_with_sideband(void)
diff --git a/send-pack.c b/send-pack.c
index 7d172ef..81d4b1c 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -212,6 +212,9 @@ int send_pack(struct send_pack_args *args,
 		return 0;
 	}
 
+	if (!args->dry_run && !args->stateless_rpc)
+		advertise_shallow_grafts(out);
+
 	/*
 	 * Finally, tell the other end!
 	 */
diff --git a/t/t5537-push-shallow.sh b/t/t5537-push-shallow.sh
new file mode 100755
index 0000000..30fdbc8
--- /dev/null
+++ b/t/t5537-push-shallow.sh
@@ -0,0 +1,67 @@
+#!/bin/sh
+
+test_description='push from/to a shallow clone'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	test_commit 1 &&
+	test_commit 2 &&
+	test_commit 3 &&
+	test_commit 4
+'
+
+test_expect_success 'setup shallow clone' '
+	git clone --no-local --depth=2 .git shallow &&
+	git --git-dir=shallow/.git log --format=%s >actual &&
+	cat <<EOF >expect &&
+4
+3
+EOF
+	test_cmp expect actual
+'
+
+test_expect_success 'push from shallow clone' '
+	(
+	cd shallow &&
+	test_commit 5 &&
+	git push ../.git +master:refs/remotes/shallow/master
+	) &&
+	git log --format=%s shallow/master >actual &&
+	git fsck &&
+	cat <<EOF >expect &&
+5
+4
+3
+2
+1
+EOF
+	test_cmp expect actual
+'
+
+test_expect_success 'push from shallow clone, with grafted roots' '
+	git init shallow2 &&
+	(
+	cd shallow2 &&
+	test_commit a &&
+	test_commit b &&
+	test_commit c &&
+	git rev-parse b > .git/shallow &&
+	git log --format=%s >actual &&
+	cat <<EOF >expect &&
+c
+b
+EOF
+	test_cmp expect actual &&
+	git push ../.git +master:refs/remotes/shallow2/master
+	) &&
+	git log --format=%s shallow2/master >actual &&
+	git fsck &&
+	cat <<EOF >expect &&
+c
+b
+EOF
+	test_cmp expect actual
+'
+
+test_done
-- 
1.8.2.83.gc99314b

  parent reply	other threads:[~2013-07-17 12:47 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-07-17 12:47 [PATCH 0/7] First class shallow clone Nguyễn Thái Ngọc Duy
2013-07-17 12:47 ` [PATCH 1/7] transport.h: remove send_pack prototype, already defined in send-pack.h Nguyễn Thái Ngọc Duy
2013-07-17 12:47 ` [PATCH 2/7] {receive,upload}-pack: advertise shallow graft information Nguyễn Thái Ngọc Duy
2013-07-17 12:47 ` [PATCH 3/7] connect.c: teach get_remote_heads to parse "shallow" lines Nguyễn Thái Ngọc Duy
2013-07-20  3:27   ` Junio C Hamano
2013-07-17 12:47 ` [PATCH 4/7] Move setup_alternate_shallow and write_shallow_commits to shallow.c Nguyễn Thái Ngọc Duy
2013-07-17 12:47 ` [PATCH 5/7] fetch-pack: support fetching from a shallow repository Nguyễn Thái Ngọc Duy
2013-07-20  3:17   ` Junio C Hamano
2013-07-17 12:47 ` Nguyễn Thái Ngọc Duy [this message]
2013-07-17 12:47 ` [PATCH 7/7] send-pack: support pushing to a shallow clone Nguyễn Thái Ngọc Duy
2013-07-20  9:57 ` [PATCH v2 00/16] First class " Nguyễn Thái Ngọc Duy
2013-07-20  9:57   ` [PATCH v2 01/16] send-pack: forbid pushing from a shallow repository Nguyễn Thái Ngọc Duy
2013-07-20  9:57   ` [PATCH v2 02/16] {receive,upload}-pack: advertise shallow graft information Nguyễn Thái Ngọc Duy
2013-07-20  9:57   ` [PATCH v2 03/16] connect.c: teach get_remote_heads to parse "shallow" lines Nguyễn Thái Ngọc Duy
2013-07-20  9:57   ` [PATCH v2 04/16] Move setup_alternate_shallow and write_shallow_commits to shallow.c Nguyễn Thái Ngọc Duy
2013-07-20  9:57   ` [PATCH v2 05/16] fetch-pack: support fetching from a shallow repository Nguyễn Thái Ngọc Duy
2013-07-22 19:10     ` Philip Oakley
2013-07-23  2:06       ` Duy Nguyen
2013-07-23 14:39         ` Duy Nguyen
2013-07-20  9:58   ` [PATCH v2 06/16] {send,receive}-pack: support pushing from a shallow clone Nguyễn Thái Ngọc Duy
2013-07-20  9:58   ` [PATCH v2 07/16] send-pack: support pushing to " Nguyễn Thái Ngọc Duy
2013-07-20  9:58   ` [PATCH v2 08/16] upload-pack: let pack-objects do the object counting in shallow case Nguyễn Thái Ngọc Duy
2013-07-20  9:58   ` [PATCH v2 09/16] pack-protocol.txt: a bit about smart http Nguyễn Thái Ngọc Duy
2013-07-20  9:58   ` [PATCH v2 10/16] Add document for command arguments for supporting " Nguyễn Thái Ngọc Duy
2013-07-20  9:58   ` [PATCH v2 11/16] {fetch,upload}-pack: support fetching from a shallow clone via " Nguyễn Thái Ngọc Duy
2013-07-20  9:58   ` [PATCH v2 12/16] receive-pack: support pushing to a shallow clone via http Nguyễn Thái Ngọc Duy
2013-07-20  9:58   ` [PATCH v2 13/16] send-pack: support pushing from " Nguyễn Thái Ngọc Duy
2013-07-20  9:58   ` [PATCH v2 14/16] git-clone.txt: remove shallow clone limitations Nguyễn Thái Ngọc Duy
2013-07-20  9:58   ` [PATCH v2 15/16] config: add core.noshallow to prevent turning a repo into a shallow one Nguyễn Thái Ngọc Duy
2013-07-22 19:23     ` Philip Oakley
2013-07-23  1:28       ` Duy Nguyen
2013-07-23  4:06         ` Junio C Hamano
2013-07-23 19:44         ` Philip Oakley
2013-07-20  9:58   ` [PATCH v2 16/16] clone: use git protocol for cloning shallow repo locally Nguyễn Thái Ngọc Duy
2013-07-22 23:41   ` [PATCH v2 00/16] First class shallow clone Philip Oakley
2013-07-23  1:20     ` Duy Nguyen
2013-07-23  4:08       ` Junio C Hamano
2013-07-23  5:01         ` Duy Nguyen
2013-07-23 22:33       ` Philip Oakley
2013-07-24  1:57         ` Duy Nguyen
2013-07-24  7:38           ` Philip Oakley
2013-07-24  8:30           ` Piotr Krukowiecki
2013-07-24 10:35             ` Duy Nguyen
2013-07-24 16:50               ` Piotr Krukowiecki

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1374065234-870-7-git-send-email-pclouds@gmail.com \
    --to=pclouds@gmail.com \
    --cc=git@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).