path: root/connect.c
diff options
authorJunio C Hamano <>2008-09-09 08:27:09 (GMT)
committerJunio C Hamano <>2008-09-09 16:27:46 (GMT)
commit40c155ff14c8b313d408f2e51a55c881ce082e4e (patch)
tree97509e2459ec5eac8e771d5ea2b131fc8faacc8d /connect.c
parentbe5908aed35d1c129f1ea38913b230ee1927361b (diff)
push: prepare sender to receive extended ref information from the receiver
"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 <>
Diffstat (limited to 'connect.c')
1 files changed, 15 insertions, 1 deletions
diff --git a/connect.c b/connect.c
index dd96f8e..67d2cd8 100644
--- a/connect.c
+++ b/connect.c
@@ -41,12 +41,20 @@ 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)
+ 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 +80,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))
if (nr_match && !path_match(name, nr_match, match))