{"thread":{"id":"12448","subject":"[PATCH v3 8/8] Teach git-fetch to grab a tag at the same time as a commit","startedAt":"2008-03-03T02:35:33Z","lastAt":"2008-03-03T02:35:33Z","messageCount":1,"participants":["Shawn O. Pearce"],"isPatch":true,"patchVersion":3,"patchTotal":8},"messages":[{"id":"70733","messageId":"20080303023533.GH9966@spearce.org","threadId":"12448","inReplyTo":null,"subject":"[PATCH v3 8/8] Teach git-fetch to grab a tag at the same time as a commit","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-03-03T02:35:33Z","receivedAt":"2008-03-03T02:35:33Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"If the situation is the following on the remote and L is the common\nbase between both sides:\n\n          T - tag1    S - tag2\n         /           /\n    L - A - O - O - B\n     \\               \\\n      origin/master   master\n\nand we have decided to fetch \"master\" to acquire the range L..B we\ncan also nab tag S at the same time during the first connection,\nas we can clearly see from the refs advertised by upload-pack that\nS^{} = B and master = B.\n\nUnfortunately we still cannot nab T at the same time as we are not\nable to see that T^{} will also be in the range implied by L..B.\nSuch computations must be performed on the remote side (not yet\nsupported) or on the client side as post-processing (the current\nbehavior).\n\nThis optimization is an extension of the previous one in that it\nhelps on projects which tend to publish both a new commit and a\nnew tag, then lay idle for a while before publishing anything else.\nMost followers are able to download both the new commit and the new\ntag in one connection, rather than two.  git.git tends to follow\nsuch patterns with its roughly once-daily updates from Junio.\n\nA protocol extension and additional server side logic would be\nnecessary to also ensure T is grabbed on the first connection.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n builtin-fetch.c      |   14 +++++-\n t/t5503-tagfollow.sh |  124 ++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 137 insertions(+), 1 deletions(-)\n create mode 100755 t/t5503-tagfollow.sh\n\ndiff --git a/builtin-fetch.c b/builtin-fetch.c\nindex a58efa6..26c3d74 100644\n--- a/builtin-fetch.c\n+++ b/builtin-fetch.c\n@@ -459,6 +459,17 @@ static int add_existing(const char *refname, const unsigned char *sha1,\n \treturn 0;\n }\n \n+static int will_fetch(struct ref **head, const unsigned char *sha1)\n+{\n+\tstruct ref *rm = *head;\n+\twhile (rm) {\n+\t\tif (!hashcmp(rm->old_sha1, sha1))\n+\t\t\treturn 1;\n+\t\trm = rm->next;\n+\t}\n+\treturn 0;\n+}\n+\n static void find_non_local_tags(struct transport *transport,\n \t\t\tstruct ref **head,\n \t\t\tstruct ref ***tail)\n@@ -495,7 +506,8 @@ static void find_non_local_tags(struct transport *transport,\n \n \t\tif (!path_list_has_path(&existing_refs, ref_name) &&\n \t\t    !path_list_has_path(&new_refs, ref_name) &&\n-\t\t    has_sha1_file(ref->old_sha1)) {\n+\t\t    (has_sha1_file(ref->old_sha1) ||\n+\t\t     will_fetch(head, ref->old_sha1))) {\n \t\t\tpath_list_insert(ref_name, &new_refs);\n \n \t\t\trm = alloc_ref(strlen(ref_name) + 1);\ndiff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh\nnew file mode 100755\nindex 0000000..45ff982\n--- /dev/null\n+++ b/t/t5503-tagfollow.sh\n@@ -0,0 +1,124 @@\n+#!/bin/sh\n+\n+test_description='test automatic tag following'\n+\n+. ./test-lib.sh\n+\n+# End state of the repository:\n+#\n+#         T - tag1          S - tag2\n+#        /                 /\n+#   L - A ------ O ------ B\n+#    \\   \\                 \\\n+#     \\   C - origin/cat    \\\n+#      origin/master         master\n+\n+test_expect_success setup '\n+\ttest_tick &&\n+\techo ichi >file &&\n+\tgit add file &&\n+\tgit commit -m L &&\n+\tL=$(git rev-parse --verify HEAD) &&\n+\n+\t(\n+\t\tmkdir cloned &&\n+\t\tcd cloned &&\n+\t\tgit init-db &&\n+\t\tgit remote add -f origin ..\n+\t) &&\n+\n+\ttest_tick &&\n+\techo A >file &&\n+\tgit add file &&\n+\tgit commit -m A &&\n+\tA=$(git rev-parse --verify HEAD)\n+'\n+\n+U=UPLOAD_LOG\n+\n+cat - <<EOF >expect\n+#S\n+want $A\n+#E\n+EOF\n+test_expect_success 'fetch A (new commit : 1 connection)' '\n+\trm -f $U\n+\t(\n+\t\tcd cloned &&\n+\t\tGIT_DEBUG_SEND_PACK=3 git fetch 3>../$U &&\n+\t\ttest $A = $(git rev-parse --verify origin/master)\n+\t) &&\n+\ttest -s $U &&\n+\tcut -d\" \" -f1,2 $U >actual &&\n+\tgit diff expect actual\n+'\n+\n+test_expect_success \"create tag T on A, create C on branch cat\" '\n+\tgit tag -a -m tag1 tag1 $A &&\n+\tT=$(git rev-parse --verify tag1) &&\n+\n+\tgit checkout -b cat &&\n+\techo C >file &&\n+\tgit add file &&\n+\tgit commit -m C &&\n+\tC=$(git rev-parse --verify HEAD) &&\n+\tgit checkout master\n+'\n+\n+cat - <<EOF >expect\n+#S\n+want $C\n+want $T\n+#E\n+EOF\n+test_expect_success 'fetch C, T (new branch, tag : 1 connection)' '\n+\trm -f $U\n+\t(\n+\t\tcd cloned &&\n+\t\tGIT_DEBUG_SEND_PACK=3 git fetch 3>../$U &&\n+\t\ttest $C = $(git rev-parse --verify origin/cat) &&\n+\t\ttest $T = $(git rev-parse --verify tag1) &&\n+\t\ttest $A = $(git rev-parse --verify tag1^0)\n+\t) &&\n+\ttest -s $U &&\n+\tcut -d\" \" -f1,2 $U >actual &&\n+\tgit diff expect actual\n+'\n+\n+test_expect_success \"create commits O, B, tag S on B\" '\n+\ttest_tick &&\n+\techo O >file &&\n+\tgit add file &&\n+\tgit commit -m O &&\n+\n+\ttest_tick &&\n+\techo B >file &&\n+\tgit add file &&\n+\tgit commit -m B &&\n+\tB=$(git rev-parse --verify HEAD) &&\n+\n+\tgit tag -a -m tag2 tag2 $B &&\n+\tS=$(git rev-parse --verify tag2)\n+'\n+\n+cat - <<EOF >expect\n+#S\n+want $B\n+want $S\n+#E\n+EOF\n+test_expect_success 'fetch B, S (commit and tag : 1 connection)' '\n+\trm -f $U\n+\t(\n+\t\tcd cloned &&\n+\t\tGIT_DEBUG_SEND_PACK=3 git fetch 3>../$U &&\n+\t\ttest $B = $(git rev-parse --verify origin/master) &&\n+\t\ttest $B = $(git rev-parse --verify tag2^0) &&\n+\t\ttest $S = $(git rev-parse --verify tag2)\n+\t) &&\n+\ttest -s $U &&\n+\tcut -d\" \" -f1,2 $U >actual &&\n+\tgit diff expect actual\n+'\n+\n+test_done\n-- \n1.5.4.3.468.g36990\n"}]}