Skip to content

Commit

Permalink
Merge branch 'sp/fetch-optim'
Browse files Browse the repository at this point in the history
* sp/fetch-optim:
  Teach git-fetch to exploit server side automatic tag following
  Teach fetch-pack/upload-pack about --include-tag
  git-pack-objects: Automatically pack annotated tags if object was packed
  Teach git-fetch to grab a tag at the same time as a commit
  Make git-fetch follow tags we already have objects for sooner
  Teach upload-pack to log the received need lines to an fd
  Free the path_lists used to find non-local tags in git-fetch
  Allow builtin-fetch's find_non_local_tags to append onto a list
  Ensure tail pointer gets setup correctly when we fetch HEAD only
  Remove unnecessary delaying of free_refs(ref_map) in builtin-fetch
  Remove unused variable in builtin-fetch find_non_local_tags
  • Loading branch information
Junio C Hamano committed Mar 9, 2008
2 parents 686bc52 + 41fa7d2 commit 5b278eb
Show file tree
Hide file tree
Showing 11 changed files with 338 additions and 24 deletions.
8 changes: 7 additions & 1 deletion Documentation/git-fetch-pack.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ git-fetch-pack - Receive missing objects from another repository

SYNOPSIS
--------
'git-fetch-pack' [--all] [--quiet|-q] [--keep|-k] [--thin] [--upload-pack=<git-upload-pack>] [--depth=<n>] [--no-progress] [-v] [<host>:]<directory> [<refs>...]
'git-fetch-pack' [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] [--no-progress] [-v] [<host>:]<directory> [<refs>...]

DESCRIPTION
-----------
Expand Down Expand Up @@ -45,6 +45,12 @@ OPTIONS
Spend extra cycles to minimize the number of objects to be sent.
Use it on slower connection.

\--include-tag::
If the remote side supports it, annotated tags objects will
be downloaded on the same connection as the other objects if
the object the tag references is downloaded. The caller must
otherwise determine the tags this option made available.

\--upload-pack=<git-upload-pack>::
Use this to specify the path to 'git-upload-pack' on the
remote side, if is not found on your $PATH.
Expand Down
5 changes: 5 additions & 0 deletions Documentation/git-pack-objects.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ base-name::
as if all refs under `$GIT_DIR/refs` are specified to be
included.

--include-tag::
Include unasked-for annotated tags if the object they
reference was included in the resulting packfile. This
can be useful to send new tags to native git clients.

--window=[N], --depth=[N]::
These two options affect how the objects contained in
the pack are stored using delta compression. The
Expand Down
9 changes: 7 additions & 2 deletions builtin-fetch-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ static struct fetch_pack_args args = {
};

static const char fetch_pack_usage[] =
"git-fetch-pack [--all] [--quiet|-q] [--keep|-k] [--thin] [--upload-pack=<git-upload-pack>] [--depth=<n>] [--no-progress] [-v] [<host>:]<directory> [<refs>...]";
"git-fetch-pack [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] [--no-progress] [-v] [<host>:]<directory> [<refs>...]";

#define COMPLETE (1U << 0)
#define COMMON (1U << 1)
Expand Down Expand Up @@ -176,13 +176,14 @@ static int find_common(int fd[2], unsigned char *result_sha1,
}

if (!fetching)
packet_write(fd[1], "want %s%s%s%s%s%s%s\n",
packet_write(fd[1], "want %s%s%s%s%s%s%s%s\n",
sha1_to_hex(remote),
(multi_ack ? " multi_ack" : ""),
(use_sideband == 2 ? " side-band-64k" : ""),
(use_sideband == 1 ? " side-band" : ""),
(args.use_thin_pack ? " thin-pack" : ""),
(args.no_progress ? " no-progress" : ""),
(args.include_tag ? " include-tag" : ""),
" ofs-delta");
else
packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
Expand Down Expand Up @@ -683,6 +684,10 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
args.use_thin_pack = 1;
continue;
}
if (!strcmp("--include-tag", arg)) {
args.include_tag = 1;
continue;
}
if (!strcmp("--all", arg)) {
args.fetch_all = 1;
continue;
Expand Down
52 changes: 36 additions & 16 deletions builtin-fetch.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ static void add_merge_config(struct ref **head,
}
}

static void find_non_local_tags(struct transport *transport,
struct ref **head,
struct ref ***tail);

static struct ref *get_ref_map(struct transport *transport,
struct refspec *refs, int ref_count, int tags,
int *autotags)
Expand Down Expand Up @@ -157,8 +161,11 @@ static struct ref *get_ref_map(struct transport *transport,
if (!ref_map)
die("Couldn't find remote ref HEAD");
ref_map->merge = 1;
tail = &ref_map->next;
}
}
if (tags == TAGS_DEFAULT && *autotags)
find_non_local_tags(transport, &ref_map, &tail);
ref_remove_duplicates(ref_map);

return ref_map;
Expand Down Expand Up @@ -452,18 +459,28 @@ static int add_existing(const char *refname, const unsigned char *sha1,
return 0;
}

static struct ref *find_non_local_tags(struct transport *transport,
struct ref *fetch_map)
static int will_fetch(struct ref **head, const unsigned char *sha1)
{
struct ref *rm = *head;
while (rm) {
if (!hashcmp(rm->old_sha1, sha1))
return 1;
rm = rm->next;
}
return 0;
}

static void find_non_local_tags(struct transport *transport,
struct ref **head,
struct ref ***tail)
{
static struct path_list existing_refs = { NULL, 0, 0, 0 };
struct path_list existing_refs = { NULL, 0, 0, 0 };
struct path_list new_refs = { NULL, 0, 0, 1 };
char *ref_name;
int ref_name_len;
const unsigned char *ref_sha1;
const struct ref *tag_ref;
struct ref *rm = NULL;
struct ref *ref_map = NULL;
struct ref **tail = &ref_map;
const struct ref *ref;

for_each_ref(add_existing, &existing_refs);
Expand All @@ -489,7 +506,8 @@ static struct ref *find_non_local_tags(struct transport *transport,

if (!path_list_has_path(&existing_refs, ref_name) &&
!path_list_has_path(&new_refs, ref_name) &&
has_sha1_file(ref->old_sha1)) {
(has_sha1_file(ref->old_sha1) ||
will_fetch(head, ref->old_sha1))) {
path_list_insert(ref_name, &new_refs);

rm = alloc_ref(strlen(ref_name) + 1);
Expand All @@ -498,19 +516,19 @@ static struct ref *find_non_local_tags(struct transport *transport,
strcpy(rm->peer_ref->name, ref_name);
hashcpy(rm->old_sha1, ref_sha1);

*tail = rm;
tail = &rm->next;
**tail = rm;
*tail = &rm->next;
}
free(ref_name);
}

return ref_map;
path_list_clear(&existing_refs, 0);
path_list_clear(&new_refs, 0);
}

static int do_fetch(struct transport *transport,
struct refspec *refs, int ref_count)
{
struct ref *ref_map, *fetch_map;
struct ref *ref_map;
struct ref *rm;
int autotags = (transport->remote->fetch_tags == 1);
if (transport->remote->fetch_tags == 2 && tags != TAGS_UNSET)
Expand All @@ -537,26 +555,28 @@ static int do_fetch(struct transport *transport,
read_ref(rm->peer_ref->name, rm->peer_ref->old_sha1);
}

if (tags == TAGS_DEFAULT && autotags)
transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
if (fetch_refs(transport, ref_map)) {
free_refs(ref_map);
return 1;
}

fetch_map = ref_map;
free_refs(ref_map);

/* if neither --no-tags nor --tags was specified, do automated tag
* following ... */
if (tags == TAGS_DEFAULT && autotags) {
ref_map = find_non_local_tags(transport, fetch_map);
struct ref **tail = &ref_map;
ref_map = NULL;
find_non_local_tags(transport, &ref_map, &tail);
if (ref_map) {
transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);
transport_set_option(transport, TRANS_OPT_DEPTH, "0");
fetch_refs(transport, ref_map);
}
free_refs(ref_map);
}

free_refs(fetch_map);

transport_disconnect(transport);

return 0;
Expand Down
24 changes: 22 additions & 2 deletions builtin-pack-objects.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "revision.h"
#include "list-objects.h"
#include "progress.h"
#include "refs.h"

#ifdef THREADED_DELTA_SEARCH
#include "thread-utils.h"
Expand All @@ -27,7 +28,8 @@ git-pack-objects [{ -q | --progress | --all-progress }] \n\
[--window=N] [--window-memory=N] [--depth=N] \n\
[--no-reuse-delta] [--no-reuse-object] [--delta-base-offset] \n\
[--threads=N] [--non-empty] [--revs [--unpacked | --all]*] [--reflog] \n\
[--stdout | base-name] [--keep-unreachable] [<ref-list | <object-list]";
[--stdout | base-name] [--include-tag] [--keep-unreachable] \n\
[<ref-list | <object-list]";

struct object_entry {
struct pack_idx_entry idx;
Expand Down Expand Up @@ -63,7 +65,7 @@ static struct pack_idx_entry **written_list;
static uint32_t nr_objects, nr_alloc, nr_result, nr_written;

static int non_empty;
static int no_reuse_delta, no_reuse_object, keep_unreachable;
static int no_reuse_delta, no_reuse_object, keep_unreachable, include_tag;
static int local;
static int incremental;
static int allow_ofs_delta;
Expand Down Expand Up @@ -1630,6 +1632,18 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
#define ll_find_deltas(l, s, w, d, p) find_deltas(l, &s, w, d, p)
#endif

static int add_ref_tag(const char *path, const unsigned char *sha1, int flag, void *cb_data)
{
unsigned char peeled[20];

if (!prefixcmp(path, "refs/tags/") && /* is a tag? */
!peel_ref(path, peeled) && /* peelable? */
!is_null_sha1(peeled) && /* annotated tag? */
locate_object_entry(peeled)) /* object packed? */
add_object_entry(sha1, OBJ_TAG, NULL, 0);
return 0;
}

static void prepare_pack(int window, int depth)
{
struct object_entry **delta_list;
Expand Down Expand Up @@ -2033,6 +2047,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
keep_unreachable = 1;
continue;
}
if (!strcmp("--include-tag", arg)) {
include_tag = 1;
continue;
}
if (!strcmp("--unpacked", arg) ||
!prefixcmp(arg, "--unpacked=") ||
!strcmp("--reflog", arg) ||
Expand Down Expand Up @@ -2109,6 +2127,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
rp_av[rp_ac] = NULL;
get_object_list(rp_ac, rp_av);
}
if (include_tag && nr_result)
for_each_ref(add_ref_tag, NULL);
stop_progress(&progress_state);

if (non_empty && !nr_result)
Expand Down
3 changes: 2 additions & 1 deletion fetch-pack.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ struct fetch_pack_args
use_thin_pack:1,
fetch_all:1,
verbose:1,
no_progress:1;
no_progress:1,
include_tag:1;
};

struct ref *fetch_pack(struct fetch_pack_args *args,
Expand Down
84 changes: 84 additions & 0 deletions t/t5305-include-tag.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/bin/sh

test_description='git-pack-object --include-tag'
. ./test-lib.sh

TRASH=`pwd`

test_expect_success setup '
echo c >d &&
git update-index --add d &&
tree=`git write-tree` &&
commit=`git commit-tree $tree </dev/null` &&
echo "object $commit" >sig &&
echo "type commit" >>sig &&
echo "tag mytag" >>sig &&
echo "tagger $(git var GIT_COMMITTER_IDENT)" >>sig &&
echo >>sig &&
echo "our test tag" >>sig &&
tag=`git mktag <sig` &&
rm d sig &&
git update-ref refs/tags/mytag $tag && {
echo $tree &&
echo $commit &&
git ls-tree $tree | sed -e "s/.* \\([0-9a-f]*\\) .*/\\1/"
} >obj-list
'

rm -rf clone.git
test_expect_success 'pack without --include-tag' '
packname_1=$(git pack-objects \
--window=0 \
test-1 <obj-list)
'

test_expect_success 'unpack objects' '
(
GIT_DIR=clone.git &&
export GIT_DIR &&
git init &&
git unpack-objects -n <test-1-${packname_1}.pack &&
git unpack-objects <test-1-${packname_1}.pack
)
'

test_expect_success 'check unpacked result (have commit, no tag)' '
git rev-list --objects $commit >list.expect &&
(
GIT_DIR=clone.git &&
export GIT_DIR &&
test_must_fail git cat-file -e $tag &&
git rev-list --objects $commit
) >list.actual &&
git diff list.expect list.actual
'

rm -rf clone.git
test_expect_success 'pack with --include-tag' '
packname_1=$(git pack-objects \
--window=0 \
--include-tag \
test-2 <obj-list)
'

test_expect_success 'unpack objects' '
(
GIT_DIR=clone.git &&
export GIT_DIR &&
git init &&
git unpack-objects -n <test-2-${packname_1}.pack &&
git unpack-objects <test-2-${packname_1}.pack
)
'

test_expect_success 'check unpacked result (have commit, have tag)' '
git rev-list --objects mytag >list.expect &&
(
GIT_DIR=clone.git &&
export GIT_DIR &&
git rev-list --objects $tag
) >list.actual &&
git diff list.expect list.actual
'

test_done
Loading

0 comments on commit 5b278eb

Please sign in to comment.