@matheusbsbs / matheus-bagliano / commits / cf7f929a10
Fork 0

Teach git-fetch to grab a tag at the same time as a commit

If the situation is the following on the remote and L is the common base between both sides: T - tag1 S - tag2 / / L - A - O - O - B \ \ origin/master master and we have decided to fetch "master" to acquire the range L..B we can also nab tag S at the same time during the first connection, as we can clearly see from the refs advertised by upload-pack that S^{} = B and master = B. Unfortunately we still cannot nab T at the same time as we are not able to see that T^{} will also be in the range implied by L..B. Such computations must be performed on the remote side (not yet supported) or on the client side as post-processing (the current behavior). This optimization is an extension of the previous one in that it helps on projects which tend to publish both a new commit and a new tag, then lay idle for a while before publishing anything else. Most followers are able to download both the new commit and the new tag in one connection, rather than two. git.git tends to follow such patterns with its roughly once-daily updates from Junio. A protocol extension and additional server side logic would be necessary to also ensure T is grabbed on the first connection. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Shawn O. Pearce committed Mar 2, 2008 at 21:35 UTC cf7f929a10f141d319d47c68646c88d5911de777
2 files changed +137 -1
builtin-fetch.c
+13 -1
@@ -459,6 +459,17 @@ static int add_existing(const char *refname, const unsigned char *sha1,
459 return 0;
460 }
461
462 +static int will_fetch(struct ref **head, const unsigned char *sha1)
463 +{
464 + struct ref *rm = *head;
465 + while (rm) {
466 + if (!hashcmp(rm->old_sha1, sha1))
467 + return 1;
468 + rm = rm->next;
469 + }
470 + return 0;
471 +}
472 +
473 static void find_non_local_tags(struct transport *transport,
474 struct ref **head,
475 struct ref ***tail)
@@ -495,7 +506,8 @@ static void find_non_local_tags(struct transport *transport,
506
507 if (!path_list_has_path(&existing_refs, ref_name) &&
508 !path_list_has_path(&new_refs, ref_name) &&
498 - has_sha1_file(ref->old_sha1)) {
509 + (has_sha1_file(ref->old_sha1) ||
510 + will_fetch(head, ref->old_sha1))) {
511 path_list_insert(ref_name, &new_refs);
512
513 rm = alloc_ref(strlen(ref_name) + 1);
t/t5503-tagfollow.sh new
+124
@@ -0,0 +1,124 @@
1 +#!/bin/sh
2 +
3 +test_description='test automatic tag following'
4 +
5 +. ./test-lib.sh
6 +
7 +# End state of the repository:
8 +#
9 +# T - tag1 S - tag2
10 +# / /
11 +# L - A ------ O ------ B
12 +# \ \ \
13 +# \ C - origin/cat \
14 +# origin/master master
15 +
16 +test_expect_success setup '
17 + test_tick &&
18 + echo ichi >file &&
19 + git add file &&
20 + git commit -m L &&
21 + L=$(git rev-parse --verify HEAD) &&
22 +
23 + (
24 + mkdir cloned &&
25 + cd cloned &&
26 + git init-db &&
27 + git remote add -f origin ..
28 + ) &&
29 +
30 + test_tick &&
31 + echo A >file &&
32 + git add file &&
33 + git commit -m A &&
34 + A=$(git rev-parse --verify HEAD)
35 +'
36 +
37 +U=UPLOAD_LOG
38 +
39 +cat - <<EOF >expect
40 +#S
41 +want $A
42 +#E
43 +EOF
44 +test_expect_success 'fetch A (new commit : 1 connection)' '
45 + rm -f $U
46 + (
47 + cd cloned &&
48 + GIT_DEBUG_SEND_PACK=3 git fetch 3>../$U &&
49 + test $A = $(git rev-parse --verify origin/master)
50 + ) &&
51 + test -s $U &&
52 + cut -d" " -f1,2 $U >actual &&
53 + git diff expect actual
54 +'
55 +
56 +test_expect_success "create tag T on A, create C on branch cat" '
57 + git tag -a -m tag1 tag1 $A &&
58 + T=$(git rev-parse --verify tag1) &&
59 +
60 + git checkout -b cat &&
61 + echo C >file &&
62 + git add file &&
63 + git commit -m C &&
64 + C=$(git rev-parse --verify HEAD) &&
65 + git checkout master
66 +'
67 +
68 +cat - <<EOF >expect
69 +#S
70 +want $C
71 +want $T
72 +#E
73 +EOF
74 +test_expect_success 'fetch C, T (new branch, tag : 1 connection)' '
75 + rm -f $U
76 + (
77 + cd cloned &&
78 + GIT_DEBUG_SEND_PACK=3 git fetch 3>../$U &&
79 + test $C = $(git rev-parse --verify origin/cat) &&
80 + test $T = $(git rev-parse --verify tag1) &&
81 + test $A = $(git rev-parse --verify tag1^0)
82 + ) &&
83 + test -s $U &&
84 + cut -d" " -f1,2 $U >actual &&
85 + git diff expect actual
86 +'
87 +
88 +test_expect_success "create commits O, B, tag S on B" '
89 + test_tick &&
90 + echo O >file &&
91 + git add file &&
92 + git commit -m O &&
93 +
94 + test_tick &&
95 + echo B >file &&
96 + git add file &&
97 + git commit -m B &&
98 + B=$(git rev-parse --verify HEAD) &&
99 +
100 + git tag -a -m tag2 tag2 $B &&
101 + S=$(git rev-parse --verify tag2)
102 +'
103 +
104 +cat - <<EOF >expect
105 +#S
106 +want $B
107 +want $S
108 +#E
109 +EOF
110 +test_expect_success 'fetch B, S (commit and tag : 1 connection)' '
111 + rm -f $U
112 + (
113 + cd cloned &&
114 + GIT_DEBUG_SEND_PACK=3 git fetch 3>../$U &&
115 + test $B = $(git rev-parse --verify origin/master) &&
116 + test $B = $(git rev-parse --verify tag2^0) &&
117 + test $S = $(git rev-parse --verify tag2)
118 + ) &&
119 + test -s $U &&
120 + cut -d" " -f1,2 $U >actual &&
121 + git diff expect actual
122 +'
123 +
124 +test_done