{"thread":{"id":"12480","subject":"[PATCH v2 1/3] git-pack-objects: Automatically pack annotated tags if object was packed","startedAt":"2008-03-04T03:27:20Z","lastAt":"2008-03-04T03:27:20Z","messageCount":1,"participants":["Shawn O. Pearce"],"isPatch":true,"patchVersion":2,"patchTotal":3},"messages":[{"id":"70882","messageId":"20080304032720.GA16462@spearce.org","threadId":"12480","inReplyTo":null,"subject":"[PATCH v2 1/3] git-pack-objects: Automatically pack annotated tags if object was packed","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-03-04T03:27:20Z","receivedAt":"2008-03-04T03:27:20Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"The new option \"--auto-include-tag\" allows the caller to request that\nany annotated tag be included into the packfile if the object the tag\nreferences was also included as part of the packfile.\n\nThis option can be useful on the server side of a native git transport,\nwhere the server knows what commits it is including into a packfile to\nupdate the client.  If new annotated tags have been introduced then we\ncan also include them in the packfile, saving the client from needing\nto request them through a second connection.\n\nThis change only introduces the backend option and provides a test.\nProtocol extensions to make this useful in fetch-pack/upload-pack\nare still necessary to activate the logic during transport.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n\n Updated with Nico's suggested option name.\n\n Documentation/git-pack-objects.txt |    5 ++\n builtin-pack-objects.c             |   24 +++++++++-\n t/t5305-auto-include-tag.sh        |   84 ++++++++++++++++++++++++++++++++++++\n 3 files changed, 111 insertions(+), 2 deletions(-)\n create mode 100755 t/t5305-auto-include-tag.sh\n\ndiff --git a/Documentation/git-pack-objects.txt b/Documentation/git-pack-objects.txt\nindex 5c1bd3b..53a4513 100644\n--- a/Documentation/git-pack-objects.txt\n+++ b/Documentation/git-pack-objects.txt\n@@ -73,6 +73,11 @@ base-name::\n \tas if all refs under `$GIT_DIR/refs` are specified to be\n \tincluded.\n \n+--auto-include-tag::\n+\tAutomatically include annotated tags if the object they\n+\treference was included in the resulting packfile.  This\n+\tcan be useful to send new tags to native git clients.\n+\n --window=[N], --depth=[N]::\n \tThese two options affect how the objects contained in\n \tthe pack are stored using delta compression.  The\ndiff --git a/builtin-pack-objects.c b/builtin-pack-objects.c\nindex 2799e68..544eb05 100644\n--- a/builtin-pack-objects.c\n+++ b/builtin-pack-objects.c\n@@ -15,6 +15,7 @@\n #include \"revision.h\"\n #include \"list-objects.h\"\n #include \"progress.h\"\n+#include \"refs.h\"\n \n #ifdef THREADED_DELTA_SEARCH\n #include \"thread-utils.h\"\n@@ -27,7 +28,8 @@ git-pack-objects [{ -q | --progress | --all-progress }] \\n\\\n \t[--window=N] [--window-memory=N] [--depth=N] \\n\\\n \t[--no-reuse-delta] [--no-reuse-object] [--delta-base-offset] \\n\\\n \t[--threads=N] [--non-empty] [--revs [--unpacked | --all]*] [--reflog] \\n\\\n-\t[--stdout | base-name] [--keep-unreachable] [<ref-list | <object-list]\";\n+\t[--stdout | base-name] [--auto-include-tag] [--keep-unreachable] \\n\\\n+\t[<ref-list | <object-list]\";\n \n struct object_entry {\n \tstruct pack_idx_entry idx;\n@@ -63,7 +65,7 @@ static struct pack_idx_entry **written_list;\n static uint32_t nr_objects, nr_alloc, nr_result, nr_written;\n \n static int non_empty;\n-static int no_reuse_delta, no_reuse_object, keep_unreachable;\n+static int no_reuse_delta, no_reuse_object, keep_unreachable, include_tag;\n static int local;\n static int incremental;\n static int allow_ofs_delta;\n@@ -1630,6 +1632,18 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,\n #define ll_find_deltas(l, s, w, d, p)\tfind_deltas(l, &s, w, d, p)\n #endif\n \n+static int add_ref_tag(const char *path, const unsigned char *sha1, int flag, void *cb_data)\n+{\n+\tunsigned char peeled[20];\n+\n+\tif (!prefixcmp(path, \"refs/tags/\") && /* is a tag? */\n+\t    !peel_ref(path, peeled)        && /* peelable? */\n+\t    !is_null_sha1(peeled)          && /* annotated tag? */\n+\t    locate_object_entry(peeled))      /* object packed? */\n+\t\tadd_object_entry(sha1, OBJ_TAG, NULL, 0);\n+\treturn 0;\n+}\n+\n static void prepare_pack(int window, int depth)\n {\n \tstruct object_entry **delta_list;\n@@ -2033,6 +2047,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)\n \t\t\tkeep_unreachable = 1;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strcmp(\"--auto-include-tag\", arg)) {\n+\t\t\tinclude_tag = 1;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(\"--unpacked\", arg) ||\n \t\t    !prefixcmp(arg, \"--unpacked=\") ||\n \t\t    !strcmp(\"--reflog\", arg) ||\n@@ -2109,6 +2127,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)\n \t\trp_av[rp_ac] = NULL;\n \t\tget_object_list(rp_ac, rp_av);\n \t}\n+\tif (include_tag && nr_result)\n+\t\tfor_each_ref(add_ref_tag, NULL);\n \tstop_progress(&progress_state);\n \n \tif (non_empty && !nr_result)\ndiff --git a/t/t5305-auto-include-tag.sh b/t/t5305-auto-include-tag.sh\nnew file mode 100755\nindex 0000000..2c92c25\n--- /dev/null\n+++ b/t/t5305-auto-include-tag.sh\n@@ -0,0 +1,84 @@\n+#!/bin/sh\n+\n+test_description='git-pack-object --auto-include-tag'\n+. ./test-lib.sh\n+\n+TRASH=`pwd`\n+\n+test_expect_success setup '\n+\techo c >d &&\n+\tgit update-index --add d &&\n+\ttree=`git write-tree` &&\n+\tcommit=`git commit-tree $tree </dev/null` &&\n+\techo \"object $commit\" >sig &&\n+\techo \"type commit\" >>sig &&\n+\techo \"tag mytag\" >>sig &&\n+\techo \"tagger $(git var GIT_COMMITTER_IDENT)\" >>sig &&\n+\techo >>sig &&\n+\techo \"our test tag\" >>sig &&\n+\ttag=`git mktag <sig` &&\n+\trm d sig &&\n+\tgit update-ref refs/tags/mytag $tag && {\n+\t\techo $tree &&\n+\t\techo $commit &&\n+\t\tgit ls-tree $tree | sed -e \"s/.* \\\\([0-9a-f]*\\\\)\t.*/\\\\1/\"\n+\t} >obj-list\n+'\n+\n+rm -rf clone.git\n+test_expect_success 'pack without --auto-include-tag' '\n+\tpackname_1=$(git pack-objects \\\n+\t\t--window=0 \\\n+\t\ttest-1 <obj-list)\n+'\n+\n+test_expect_success 'unpack objects' '\n+\t(\n+\t\tGIT_DIR=clone.git &&\n+\t\texport GIT_DIR &&\n+\t\tgit init &&\n+\t\tgit unpack-objects -n <test-1-${packname_1}.pack &&\n+\t\tgit unpack-objects <test-1-${packname_1}.pack\n+\t)\n+'\n+\n+test_expect_success 'check unpacked result (have commit, no tag)' '\n+\tgit rev-list --objects $commit >list.expect &&\n+\t(\n+\t\tGIT_DIR=clone.git &&\n+\t\texport GIT_DIR &&\n+\t\ttest_must_fail git cat-file -e $tag &&\n+\t\tgit rev-list --objects $commit\n+\t) >list.actual &&\n+\tgit diff list.expect list.actual\n+'\n+\n+rm -rf clone.git\n+test_expect_success 'pack with --auto-include-tag' '\n+\tpackname_1=$(git pack-objects \\\n+\t\t--window=0 \\\n+\t\t--auto-include-tag \\\n+\t\ttest-2 <obj-list)\n+'\n+\n+test_expect_success 'unpack objects' '\n+\t(\n+\t\tGIT_DIR=clone.git &&\n+\t\texport GIT_DIR &&\n+\t\tgit init &&\n+\t\tgit unpack-objects -n <test-2-${packname_1}.pack &&\n+\t\tgit unpack-objects <test-2-${packname_1}.pack\n+\t)\n+'\n+\n+test_expect_success 'check unpacked result (have commit, have tag)' '\n+\tgit rev-list --objects mytag >list.expect &&\n+\t(\n+\t\tGIT_DIR=clone.git &&\n+\t\texport GIT_DIR &&\n+\t\tgit rev-list --objects $tag\n+\t) >list.actual &&\n+\tgit diff list.expect list.actual\n+'\n+\n+test_done\n-- \n1.5.4.3.529.gb25fb\n\n"}]}