Skip to content

Commit

Permalink
Merge branch 'nd/fetch-into-shallow' into maint
Browse files Browse the repository at this point in the history
When there is no sufficient overlap between old and new history
during a "git fetch" into a shallow repository, objects that the
sending side knows the receiving end has were unnecessarily sent.

* nd/fetch-into-shallow:
  Add testcase for needless objects during a shallow fetch
  list-objects: mark more commits as edges in mark_edges_uninteresting
  list-objects: reduce one argument in mark_edges_uninteresting
  upload-pack: delegate rev walking in shallow fetch to pack-objects
  shallow: add setup_temporary_shallow()
  shallow: only add shallow graft points to new shallow file
  move setup_alternate_shallow and write_shallow_commits to shallow.c
  • Loading branch information
Junio C Hamano committed Oct 23, 2013
2 parents 5f737ac + f21d2a7 commit 6ba0d95
Show file tree
Hide file tree
Showing 12 changed files with 152 additions and 160 deletions.
2 changes: 1 addition & 1 deletion bisect.c
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ static void bisect_common(struct rev_info *revs)
if (prepare_revision_walk(revs))
die("revision walk setup failed");
if (revs->tree_objects)
mark_edges_uninteresting(revs->commits, revs, NULL);
mark_edges_uninteresting(revs, NULL);
}

static void exit_if_skipped_commits(struct commit_list *tried,
Expand Down
2 changes: 1 addition & 1 deletion builtin/pack-objects.c
Original file line number Diff line number Diff line change
Expand Up @@ -2378,7 +2378,7 @@ static void get_object_list(int ac, const char **av)

if (prepare_revision_walk(&revs))
die("revision walk setup failed");
mark_edges_uninteresting(revs.commits, &revs, show_edge);
mark_edges_uninteresting(&revs, show_edge);
traverse_commit_list(&revs, show_commit, show_object, NULL);

if (keep_unreachable)
Expand Down
2 changes: 1 addition & 1 deletion builtin/rev-list.c
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
if (prepare_revision_walk(&revs))
die("revision walk setup failed");
if (revs.tree_objects)
mark_edges_uninteresting(revs.commits, &revs, show_edge);
mark_edges_uninteresting(&revs, show_edge);

if (bisect_list) {
int reaches = reaches, all = all;
Expand Down
4 changes: 4 additions & 0 deletions commit.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,10 @@ extern struct commit_list *get_shallow_commits(struct object_array *heads,
int depth, int shallow_flag, int not_shallow_flag);
extern void check_shallow_file_for_update(void);
extern void set_alternate_shallow_file(const char *path);
extern int write_shallow_commits(struct strbuf *out, int use_pack_protocol);
extern void setup_alternate_shallow(struct lock_file *shallow_lock,
const char **alternate_shallow_file);
extern char *setup_temporary_shallow(void);

int is_descendant_of(struct commit *, struct commit_list *);
int in_merge_bases(struct commit *, struct commit *);
Expand Down
53 changes: 1 addition & 52 deletions fetch-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,36 +184,6 @@ static void consume_shallow_list(struct fetch_pack_args *args, int fd)
}
}

struct write_shallow_data {
struct strbuf *out;
int use_pack_protocol;
int count;
};

static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
{
struct write_shallow_data *data = cb_data;
const char *hex = sha1_to_hex(graft->sha1);
data->count++;
if (data->use_pack_protocol)
packet_buf_write(data->out, "shallow %s", hex);
else {
strbuf_addstr(data->out, hex);
strbuf_addch(data->out, '\n');
}
return 0;
}

static int write_shallow_commits(struct strbuf *out, int use_pack_protocol)
{
struct write_shallow_data data;
data.out = out;
data.use_pack_protocol = use_pack_protocol;
data.count = 0;
for_each_commit_graft(write_one_shallow, &data);
return data.count;
}

static enum ack_type get_ack(int fd, unsigned char *result_sha1)
{
int len;
Expand Down Expand Up @@ -795,27 +765,6 @@ static int cmp_ref_by_name(const void *a_, const void *b_)
return strcmp(a->name, b->name);
}

static void setup_alternate_shallow(void)
{
struct strbuf sb = STRBUF_INIT;
int fd;

check_shallow_file_for_update();
fd = hold_lock_file_for_update(&shallow_lock, git_path("shallow"),
LOCK_DIE_ON_ERROR);
if (write_shallow_commits(&sb, 0)) {
if (write_in_full(fd, sb.buf, sb.len) != sb.len)
die_errno("failed to write to %s", shallow_lock.filename);
alternate_shallow_file = shallow_lock.filename;
} else
/*
* is_repository_shallow() sees empty string as "no
* shallow file".
*/
alternate_shallow_file = "";
strbuf_release(&sb);
}

static struct ref *do_fetch_pack(struct fetch_pack_args *args,
int fd[2],
const struct ref *orig_ref,
Expand Down Expand Up @@ -896,7 +845,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
if (args->stateless_rpc)
packet_flush(fd[1]);
if (args->depth > 0)
setup_alternate_shallow();
setup_alternate_shallow(&shallow_lock, &alternate_shallow_file);
else
alternate_shallow_file = NULL;
if (get_pack(args, fd, pack_lockfile))
Expand Down
2 changes: 1 addition & 1 deletion http-push.c
Original file line number Diff line number Diff line change
Expand Up @@ -1976,7 +1976,7 @@ int main(int argc, char **argv)
pushing = 0;
if (prepare_revision_walk(&revs))
die("revision walk setup failed");
mark_edges_uninteresting(revs.commits, &revs, NULL);
mark_edges_uninteresting(&revs, NULL);
objects_to_send = get_delta(&revs, ref_lock);
finish_all_active_slots();

Expand Down
24 changes: 20 additions & 4 deletions list-objects.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,19 +145,35 @@ static void mark_edge_parents_uninteresting(struct commit *commit,
}
}

void mark_edges_uninteresting(struct commit_list *list,
struct rev_info *revs,
show_edge_fn show_edge)
void mark_edges_uninteresting(struct rev_info *revs, show_edge_fn show_edge)
{
for ( ; list; list = list->next) {
struct commit_list *list;
int i;

for (list = revs->commits; list; list = list->next) {
struct commit *commit = list->item;

if (commit->object.flags & UNINTERESTING) {
mark_tree_uninteresting(commit->tree);
if (revs->edge_hint && !(commit->object.flags & SHOWN)) {
commit->object.flags |= SHOWN;
show_edge(commit);
}
continue;
}
mark_edge_parents_uninteresting(commit, revs, show_edge);
}
for (i = 0; i < revs->cmdline.nr; i++) {
struct object *obj = revs->cmdline.rev[i].item;
struct commit *commit = (struct commit *)obj;
if (obj->type != OBJ_COMMIT || !(obj->flags & UNINTERESTING))
continue;
mark_tree_uninteresting(commit->tree);
if (revs->edge_hint && !(obj->flags & SHOWN)) {
obj->flags |= SHOWN;
show_edge(commit);
}
}
}

static void add_pending_tree(struct rev_info *revs, struct tree *tree)
Expand Down
2 changes: 1 addition & 1 deletion list-objects.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ typedef void (*show_object_fn)(struct object *, const struct name_path *, const
void traverse_commit_list(struct rev_info *, show_commit_fn, show_object_fn, void *);

typedef void (*show_edge_fn)(struct commit *);
void mark_edges_uninteresting(struct commit_list *, struct rev_info *, show_edge_fn);
void mark_edges_uninteresting(struct rev_info *, show_edge_fn);

#endif
79 changes: 79 additions & 0 deletions shallow.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "cache.h"
#include "commit.h"
#include "tag.h"
#include "pkt-line.h"

static int is_shallow = -1;
static struct stat shallow_stat;
Expand Down Expand Up @@ -141,3 +142,81 @@ void check_shallow_file_for_update(void)
)
die("shallow file was changed during fetch");
}

struct write_shallow_data {
struct strbuf *out;
int use_pack_protocol;
int count;
};

static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
{
struct write_shallow_data *data = cb_data;
const char *hex = sha1_to_hex(graft->sha1);
if (graft->nr_parent != -1)
return 0;
data->count++;
if (data->use_pack_protocol)
packet_buf_write(data->out, "shallow %s", hex);
else {
strbuf_addstr(data->out, hex);
strbuf_addch(data->out, '\n');
}
return 0;
}

int write_shallow_commits(struct strbuf *out, int use_pack_protocol)
{
struct write_shallow_data data;
data.out = out;
data.use_pack_protocol = use_pack_protocol;
data.count = 0;
for_each_commit_graft(write_one_shallow, &data);
return data.count;
}

char *setup_temporary_shallow(void)
{
struct strbuf sb = STRBUF_INIT;
int fd;

if (write_shallow_commits(&sb, 0)) {
struct strbuf path = STRBUF_INIT;
strbuf_addstr(&path, git_path("shallow_XXXXXX"));
fd = xmkstemp(path.buf);
if (write_in_full(fd, sb.buf, sb.len) != sb.len)
die_errno("failed to write to %s",
path.buf);
close(fd);
strbuf_release(&sb);
return strbuf_detach(&path, NULL);
}
/*
* is_repository_shallow() sees empty string as "no shallow
* file".
*/
return xstrdup("");
}

void setup_alternate_shallow(struct lock_file *shallow_lock,
const char **alternate_shallow_file)
{
struct strbuf sb = STRBUF_INIT;
int fd;

check_shallow_file_for_update();
fd = hold_lock_file_for_update(shallow_lock, git_path("shallow"),
LOCK_DIE_ON_ERROR);
if (write_shallow_commits(&sb, 0)) {
if (write_in_full(fd, sb.buf, sb.len) != sb.len)
die_errno("failed to write to %s",
shallow_lock->filename);
*alternate_shallow_file = shallow_lock->filename;
} else
/*
* is_repository_shallow() sees empty string as "no
* shallow file".
*/
*alternate_shallow_file = "";
strbuf_release(&sb);
}
11 changes: 11 additions & 0 deletions t/t5500-fetch-pack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,17 @@ test_expect_success 'fetch in shallow repo unreachable shallow objects' '
git fsck --no-dangling
)
'
test_expect_success 'fetch creating new shallow root' '
(
git clone "file://$(pwd)/." shallow10 &&
git commit --allow-empty -m empty &&
cd shallow10 &&
git fetch --depth=1 --progress 2>actual &&
# This should fetch only the empty commit, no tree or
# blob objects
grep "remote: Total 1" actual
)
'

test_expect_success 'setup tests for the --stdin parameter' '
for head in C D E F
Expand Down
3 changes: 0 additions & 3 deletions t/t5530-upload-pack-error.sh
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@ test_expect_success 'upload-pack fails due to error in rev-list' '
printf "0032want %s\n0034shallow %s00000009done\n0000" \
$(git rev-parse HEAD) $(git rev-parse HEAD^) >input &&
test_must_fail git upload-pack . <input >/dev/null 2>output.err &&
# pack-objects survived
grep "Total.*, reused" output.err &&
# but there was an error, which must have been in rev-list
grep "bad tree object" output.err
'

Expand Down
Loading

0 comments on commit 6ba0d95

Please sign in to comment.