@matheusbsbs / matheus-bagliano / commits / 41fa7d2eae
Fork 0

Teach git-fetch to exploit server side automatic tag following

If the remote peer upload-pack process supports the include-tag protocol extension then we can avoid running a second fetch cycle on the client side by letting the server send us the annotated tags along with the objects it is packing for us. In the following graph we can now fetch both "tag1" and "tag2" on the same connection that we fetched "master" from the remote when we only have L available on the local side: T - tag1 S - tag2 / / L - o ------ o ------ B \ \ \ \ origin/master master The objects for "tag1" are implicitly downloaded without our direct knowledge. The existing "quickfetch" optimization within git-fetch discovers that tag1 is complete after the first connection and does not open a second connection. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Shawn O. Pearce committed Mar 3, 2008 at 22:27 UTC 41fa7d2eaeace0c5c23fc75a3d5cc9efbad467a5
4 files changed +37
builtin-fetch.c
+3
@@ -555,6 +555,8 @@ static int do_fetch(struct transport *transport,
555 read_ref(rm->peer_ref->name, rm->peer_ref->old_sha1);
556 }
557
558 + if (tags == TAGS_DEFAULT && autotags)
559 + transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
560 if (fetch_refs(transport, ref_map)) {
561 free_refs(ref_map);
562 return 1;
@@ -568,6 +570,7 @@ static int do_fetch(struct transport *transport,
570 ref_map = NULL;
571 find_non_local_tags(transport, &ref_map, &tail);
572 if (ref_map) {
573 + transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);
574 transport_set_option(transport, TRANS_OPT_DEPTH, "0");
575 fetch_refs(transport, ref_map);
576 }
t/t5503-tagfollow.sh
+26
@@ -121,4 +121,30 @@ test_expect_success 'fetch B, S (commit and tag : 1 connection)' '
121 git diff expect actual
122 '
123
124 +cat - <<EOF >expect
125 +#S
126 +want $B
127 +want $S
128 +#E
129 +EOF
130 +test_expect_success 'new clone fetch master and tags' '
131 + git branch -D cat
132 + rm -f $U
133 + (
134 + mkdir clone2 &&
135 + cd clone2 &&
136 + git init &&
137 + git remote add origin .. &&
138 + GIT_DEBUG_SEND_PACK=3 git fetch 3>../$U &&
139 + test $B = $(git rev-parse --verify origin/master) &&
140 + test $S = $(git rev-parse --verify tag2) &&
141 + test $B = $(git rev-parse --verify tag2^0) &&
142 + test $T = $(git rev-parse --verify tag1) &&
143 + test $A = $(git rev-parse --verify tag1^0)
144 + ) &&
145 + test -s $U &&
146 + cut -d" " -f1,2 $U >actual &&
147 + git diff expect actual
148 +'
149 +
150 test_done
transport.c
+5
@@ -560,6 +560,7 @@ static int close_bundle(struct transport *transport)
560 struct git_transport_data {
561 unsigned thin : 1;
562 unsigned keep : 1;
563 + unsigned followtags : 1;
564 int depth;
565 struct child_process *conn;
566 int fd[2];
@@ -580,6 +581,9 @@ static int set_git_option(struct transport *connection,
581 } else if (!strcmp(name, TRANS_OPT_THIN)) {
582 data->thin = !!value;
583 return 0;
584 + } else if (!strcmp(name, TRANS_OPT_FOLLOWTAGS)) {
585 + data->followtags = !!value;
586 + return 0;
587 } else if (!strcmp(name, TRANS_OPT_KEEP)) {
588 data->keep = !!value;
589 return 0;
@@ -628,6 +632,7 @@ static int fetch_refs_via_pack(struct transport *transport,
632 args.keep_pack = data->keep;
633 args.lock_pack = 1;
634 args.use_thin_pack = data->thin;
635 + args.include_tag = data->followtags;
636 args.verbose = transport->verbose > 0;
637 args.depth = data->depth;
638
transport.h
+3
@@ -53,6 +53,9 @@ struct transport *transport_get(struct remote *, const char *);
53 /* Limit the depth of the fetch if not null */
54 #define TRANS_OPT_DEPTH "depth"
55
56 +/* Aggressively fetch annotated tags if possible */
57 +#define TRANS_OPT_FOLLOWTAGS "followtags"
58 +
59 /**
60 * Returns 0 if the option was used, non-zero otherwise. Prints a
61 * message to stderr if the option is not used.