From: Junio C Hamano <gitster@pobox.com>
To: git@vger.kernel.org
Subject: [PATCH 3/4] push: prepare sender to receive extended ref information from the receiver
Date: Tue, 9 Sep 2008 01:27:09 -0700 [thread overview]
Message-ID: <1220948830-3275-4-git-send-email-gitster@pobox.com> (raw)
In-Reply-To: <1220948830-3275-3-git-send-email-gitster@pobox.com>
"git push" enhancement allows the receiving end to report not only its own
refs but refs in repositories it borrows from via the alternate object
store mechanism. By telling the sender that objects reachable from these
extra refs are already complete in the receiving end, the number of
objects that need to be transfered can be cut down.
These entries are sent over the wire with string ".have", instead of the
actual names of the refs. This string was chosen so that they are ignored
by older programs at the sending end. If we sent some random but valid
looking refnames for these entries, "matching refs" rule (triggered when
running "git push" without explicit refspecs, where the sender learns what
refs the receiver has, and updates only the ones with the names of the
refs the sender also has) and "delete missing" rule (triggered when "git
push --mirror" is used, where the sender tells the receiver to delete the
refs it itself does not have) would try to update/delete them, which is
not what we want.
This prepares the send-pack (and "push" that runs native protocol) to
accept extended existing ref information and make use of it. The ".have"
entries are excluded from ref matching rules, and are exempt from deletion
rule while pushing with --mirror option, but are still used for pack
generation purposes by providing more "bottom" range commits.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin-fetch-pack.c | 2 +-
builtin-send-pack.c | 21 ++++++++++++++++-----
cache.h | 6 +++++-
connect.c | 17 ++++++++++++++++-
transport.c | 4 ++--
5 files changed, 40 insertions(+), 10 deletions(-)
diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c
index 459c6f0..e0c2561 100644
--- a/builtin-fetch-pack.c
+++ b/builtin-fetch-pack.c
@@ -735,7 +735,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
conn = git_connect(fd, (char *)dest, args.uploadpack,
args.verbose ? CONNECT_VERBOSE : 0);
if (conn) {
- get_remote_heads(fd[0], &ref, 0, NULL, 0);
+ get_remote_heads(fd[0], &ref, 0, NULL, 0, NULL);
ref = fetch_pack(&args, fd, conn, ref, dest, nr_heads, heads, NULL);
close(fd[0]);
diff --git a/builtin-send-pack.c b/builtin-send-pack.c
index 7588d22..b3c22f6 100644
--- a/builtin-send-pack.c
+++ b/builtin-send-pack.c
@@ -18,7 +18,7 @@ static struct send_pack_args args = {
/*
* Make a pack stream and spit it out into file descriptor fd
*/
-static int pack_objects(int fd, struct ref *refs)
+static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra)
{
/*
* The child becomes pack-objects --revs; we feed
@@ -34,6 +34,8 @@ static int pack_objects(int fd, struct ref *refs)
NULL,
};
struct child_process po;
+ int i;
+ char buf[42];
if (args.use_thin_pack)
argv[4] = "--thin";
@@ -49,9 +51,15 @@ static int pack_objects(int fd, struct ref *refs)
* We feed the pack-objects we just spawned with revision
* parameters by writing to the pipe.
*/
- while (refs) {
- char buf[42];
+ for (i = 0; i < extra->nr; i++) {
+ memcpy(buf + 1, sha1_to_hex(&extra->array[i][0]), 40);
+ buf[0] = '^';
+ buf[41] = '\n';
+ if (!write_or_whine(po.in, buf, 42, "send-pack: send refs"))
+ break;
+ }
+ while (refs) {
if (!is_null_sha1(refs->old_sha1) &&
has_sha1_file(refs->old_sha1)) {
memcpy(buf + 1, sha1_to_hex(refs->old_sha1), 40);
@@ -381,14 +389,17 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
int expect_status_report = 0;
int flags = MATCH_REFS_NONE;
int ret;
+ struct extra_have_objects extra_have;
+ memset(&extra_have, 0, sizeof(extra_have));
if (args.send_all)
flags |= MATCH_REFS_ALL;
if (args.send_mirror)
flags |= MATCH_REFS_MIRROR;
/* No funny business with the matcher */
- remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL);
+ remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL,
+ &extra_have);
get_local_heads();
/* Does the other end support the reporting? */
@@ -496,7 +507,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
packet_flush(out);
if (new_refs && !args.dry_run) {
- if (pack_objects(out, remote_refs) < 0)
+ if (pack_objects(out, remote_refs, &extra_have) < 0)
return -1;
}
else
diff --git a/cache.h b/cache.h
index ce1f630..98a7421 100644
--- a/cache.h
+++ b/cache.h
@@ -709,7 +709,11 @@ extern struct child_process *git_connect(int fd[2], const char *url, const char
extern int finish_connect(struct child_process *conn);
extern int path_match(const char *path, int nr, char **match);
extern int get_ack(int fd, unsigned char *result_sha1);
-extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags);
+struct extra_have_objects {
+ int nr, alloc;
+ unsigned char (*array)[20];
+};
+extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags, struct extra_have_objects *);
extern int server_supports(const char *feature);
extern struct packed_git *parse_pack_index(unsigned char *sha1);
diff --git a/connect.c b/connect.c
index dd96f8e..071e355 100644
--- a/connect.c
+++ b/connect.c
@@ -41,12 +41,21 @@ int check_ref_type(const struct ref *ref, int flags)
return check_ref(ref->name, strlen(ref->name), flags);
}
+static void add_extra_have(struct extra_have_objects *extra, unsigned char *sha1)
+{
+ if (extra->alloc <= extra->nr)
+ ALLOC_GROW(extra->array, extra->nr + 1, extra->alloc);
+ hashcpy(&(extra->array[extra->nr][0]), sha1);
+ extra->nr++;
+}
+
/*
* Read all the refs from the other end
*/
struct ref **get_remote_heads(int in, struct ref **list,
int nr_match, char **match,
- unsigned int flags)
+ unsigned int flags,
+ struct extra_have_objects *extra_have)
{
*list = NULL;
for (;;) {
@@ -72,6 +81,12 @@ struct ref **get_remote_heads(int in, struct ref **list,
server_capabilities = xstrdup(name + name_len + 1);
}
+ if (extra_have &&
+ name_len == 5 && !memcmp(".have", name, 5)) {
+ add_extra_have(extra_have, old_sha1);
+ continue;
+ }
+
if (!check_ref(name, name_len, flags))
continue;
if (nr_match && !path_match(name, nr_match, match))
diff --git a/transport.c b/transport.c
index 71433d9..f7db5d9 100644
--- a/transport.c
+++ b/transport.c
@@ -619,7 +619,7 @@ static struct ref *get_refs_via_connect(struct transport *transport)
struct ref *refs;
connect_setup(transport);
- get_remote_heads(data->fd[0], &refs, 0, NULL, 0);
+ get_remote_heads(data->fd[0], &refs, 0, NULL, 0, NULL);
return refs;
}
@@ -652,7 +652,7 @@ static int fetch_refs_via_pack(struct transport *transport,
if (!data->conn) {
connect_setup(transport);
- get_remote_heads(data->fd[0], &refs_tmp, 0, NULL, 0);
+ get_remote_heads(data->fd[0], &refs_tmp, 0, NULL, 0, NULL);
}
refs = fetch_pack(&args, data->fd, data->conn,
--
1.6.0.1.415.g7bb82
next prev parent reply other threads:[~2008-09-09 8:28 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-09-09 8:27 [PATCH 0/4] Pushing into a repository with alternates Junio C Hamano
2008-09-09 8:27 ` [PATCH 1/4] is_directory(): a generic helper function Junio C Hamano
2008-09-09 8:27 ` [PATCH 2/4] receive-pack: make it a builtin Junio C Hamano
2008-09-09 8:27 ` Junio C Hamano [this message]
2008-09-09 8:27 ` [PATCH 4/4] push: receiver end advertises refs from alternate repositories Junio C Hamano
2008-09-09 13:03 ` [PATCH 3/4] push: prepare sender to receive extended ref information from the receiver Jeff King
2008-09-09 9:26 ` [PATCH 2/4] receive-pack: make it a builtin Paolo Bonzini
2008-09-09 14:24 ` Junio C Hamano
2008-09-09 14:47 ` Paolo Bonzini
2008-09-09 10:31 ` [PATCH 1/4] is_directory(): a generic helper function Johannes Sixt
2008-09-09 12:32 ` Jeff King
2008-09-09 14:51 ` Junio C Hamano
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
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1220948830-3275-4-git-send-email-gitster@pobox.com \
--to=gitster@pobox.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.
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 NNTP newsgroup(s).