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

git-pack-objects: Automatically pack annotated tags if object was packed

The new option "--include-tag" allows the caller to request that any annotated tag be included into the packfile if the object the tag references was also included as part of the packfile. This option can be useful on the server side of a native git transport, where the server knows what commits it is including into a packfile to update the client. If new annotated tags have been introduced then we can also include them in the packfile, saving the client from needing to request them through a second connection. This change only introduces the backend option and provides a test. Protocol extensions to make this useful in fetch-pack/upload-pack are still necessary to activate the logic during transport. 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 f0a24aa56e49a5cb03101ead0211c7080b96c9f1
3 files changed +111 -2
Documentation/git-pack-objects.txt
+5
@@ -73,6 +73,11 @@ base-name::
73 as if all refs under `$GIT_DIR/refs` are specified to be
74 included.
75
76 +--include-tag::
77 + Include unasked-for annotated tags if the object they
78 + reference was included in the resulting packfile. This
79 + can be useful to send new tags to native git clients.
80 +
81 --window=[N], --depth=[N]::
82 These two options affect how the objects contained in
83 the pack are stored using delta compression. The
builtin-pack-objects.c
+22 -2
@@ -15,6 +15,7 @@
15 #include "revision.h"
16 #include "list-objects.h"
17 #include "progress.h"
18 +#include "refs.h"
19
20 #ifdef THREADED_DELTA_SEARCH
21 #include "thread-utils.h"
@@ -27,7 +28,8 @@ git-pack-objects [{ -q | --progress | --all-progress }] \n\
28 [--window=N] [--window-memory=N] [--depth=N] \n\
29 [--no-reuse-delta] [--no-reuse-object] [--delta-base-offset] \n\
30 [--threads=N] [--non-empty] [--revs [--unpacked | --all]*] [--reflog] \n\
30 - [--stdout | base-name] [--keep-unreachable] [<ref-list | <object-list]";
31 + [--stdout | base-name] [--include-tag] [--keep-unreachable] \n\
32 + [<ref-list | <object-list]";
33
34 struct object_entry {
35 struct pack_idx_entry idx;
@@ -63,7 +65,7 @@ static struct pack_idx_entry **written_list;
65 static uint32_t nr_objects, nr_alloc, nr_result, nr_written;
66
67 static int non_empty;
66 -static int no_reuse_delta, no_reuse_object, keep_unreachable;
68 +static int no_reuse_delta, no_reuse_object, keep_unreachable, include_tag;
69 static int local;
70 static int incremental;
71 static int allow_ofs_delta;
@@ -1630,6 +1632,18 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
1632 #define ll_find_deltas(l, s, w, d, p) find_deltas(l, &s, w, d, p)
1633 #endif
1634
1635 +static int add_ref_tag(const char *path, const unsigned char *sha1, int flag, void *cb_data)
1636 +{
1637 + unsigned char peeled[20];
1638 +
1639 + if (!prefixcmp(path, "refs/tags/") && /* is a tag? */
1640 + !peel_ref(path, peeled) && /* peelable? */
1641 + !is_null_sha1(peeled) && /* annotated tag? */
1642 + locate_object_entry(peeled)) /* object packed? */
1643 + add_object_entry(sha1, OBJ_TAG, NULL, 0);
1644 + return 0;
1645 +}
1646 +
1647 static void prepare_pack(int window, int depth)
1648 {
1649 struct object_entry **delta_list;
@@ -2033,6 +2047,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
2047 keep_unreachable = 1;
2048 continue;
2049 }
2050 + if (!strcmp("--include-tag", arg)) {
2051 + include_tag = 1;
2052 + continue;
2053 + }
2054 if (!strcmp("--unpacked", arg) ||
2055 !prefixcmp(arg, "--unpacked=") ||
2056 !strcmp("--reflog", arg) ||
@@ -2109,6 +2127,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
2127 rp_av[rp_ac] = NULL;
2128 get_object_list(rp_ac, rp_av);
2129 }
2130 + if (include_tag && nr_result)
2131 + for_each_ref(add_ref_tag, NULL);
2132 stop_progress(&progress_state);
2133
2134 if (non_empty && !nr_result)
t/t5305-include-tag.sh new
+84
@@ -0,0 +1,84 @@
1 +#!/bin/sh
2 +
3 +test_description='git-pack-object --include-tag'
4 +. ./test-lib.sh
5 +
6 +TRASH=`pwd`
7 +
8 +test_expect_success setup '
9 + echo c >d &&
10 + git update-index --add d &&
11 + tree=`git write-tree` &&
12 + commit=`git commit-tree $tree </dev/null` &&
13 + echo "object $commit" >sig &&
14 + echo "type commit" >>sig &&
15 + echo "tag mytag" >>sig &&
16 + echo "tagger $(git var GIT_COMMITTER_IDENT)" >>sig &&
17 + echo >>sig &&
18 + echo "our test tag" >>sig &&
19 + tag=`git mktag <sig` &&
20 + rm d sig &&
21 + git update-ref refs/tags/mytag $tag && {
22 + echo $tree &&
23 + echo $commit &&
24 + git ls-tree $tree | sed -e "s/.* \\([0-9a-f]*\\) .*/\\1/"
25 + } >obj-list
26 +'
27 +
28 +rm -rf clone.git
29 +test_expect_success 'pack without --include-tag' '
30 + packname_1=$(git pack-objects \
31 + --window=0 \
32 + test-1 <obj-list)
33 +'
34 +
35 +test_expect_success 'unpack objects' '
36 + (
37 + GIT_DIR=clone.git &&
38 + export GIT_DIR &&
39 + git init &&
40 + git unpack-objects -n <test-1-${packname_1}.pack &&
41 + git unpack-objects <test-1-${packname_1}.pack
42 + )
43 +'
44 +
45 +test_expect_success 'check unpacked result (have commit, no tag)' '
46 + git rev-list --objects $commit >list.expect &&
47 + (
48 + GIT_DIR=clone.git &&
49 + export GIT_DIR &&
50 + test_must_fail git cat-file -e $tag &&
51 + git rev-list --objects $commit
52 + ) >list.actual &&
53 + git diff list.expect list.actual
54 +'
55 +
56 +rm -rf clone.git
57 +test_expect_success 'pack with --include-tag' '
58 + packname_1=$(git pack-objects \
59 + --window=0 \
60 + --include-tag \
61 + test-2 <obj-list)
62 +'
63 +
64 +test_expect_success 'unpack objects' '
65 + (
66 + GIT_DIR=clone.git &&
67 + export GIT_DIR &&
68 + git init &&
69 + git unpack-objects -n <test-2-${packname_1}.pack &&
70 + git unpack-objects <test-2-${packname_1}.pack
71 + )
72 +'
73 +
74 +test_expect_success 'check unpacked result (have commit, have tag)' '
75 + git rev-list --objects mytag >list.expect &&
76 + (
77 + GIT_DIR=clone.git &&
78 + export GIT_DIR &&
79 + git rev-list --objects $tag
80 + ) >list.actual &&
81 + git diff list.expect list.actual
82 +'
83 +
84 +test_done