Skip to content

Commit 6ba0d95

Browse files
committed
Merge branch 'nd/fetch-into-shallow' into maint
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
2 parents 5f737ac + f21d2a7 commit 6ba0d95

12 files changed

+152
-160
lines changed

bisect.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ static void bisect_common(struct rev_info *revs)
624624
if (prepare_revision_walk(revs))
625625
die("revision walk setup failed");
626626
if (revs->tree_objects)
627-
mark_edges_uninteresting(revs->commits, revs, NULL);
627+
mark_edges_uninteresting(revs, NULL);
628628
}
629629

630630
static void exit_if_skipped_commits(struct commit_list *tried,

builtin/pack-objects.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2378,7 +2378,7 @@ static void get_object_list(int ac, const char **av)
23782378

23792379
if (prepare_revision_walk(&revs))
23802380
die("revision walk setup failed");
2381-
mark_edges_uninteresting(revs.commits, &revs, show_edge);
2381+
mark_edges_uninteresting(&revs, show_edge);
23822382
traverse_commit_list(&revs, show_commit, show_object, NULL);
23832383

23842384
if (keep_unreachable)

builtin/rev-list.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
336336
if (prepare_revision_walk(&revs))
337337
die("revision walk setup failed");
338338
if (revs.tree_objects)
339-
mark_edges_uninteresting(revs.commits, &revs, show_edge);
339+
mark_edges_uninteresting(&revs, show_edge);
340340

341341
if (bisect_list) {
342342
int reaches = reaches, all = all;

commit.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,10 @@ extern struct commit_list *get_shallow_commits(struct object_array *heads,
201201
int depth, int shallow_flag, int not_shallow_flag);
202202
extern void check_shallow_file_for_update(void);
203203
extern void set_alternate_shallow_file(const char *path);
204+
extern int write_shallow_commits(struct strbuf *out, int use_pack_protocol);
205+
extern void setup_alternate_shallow(struct lock_file *shallow_lock,
206+
const char **alternate_shallow_file);
207+
extern char *setup_temporary_shallow(void);
204208

205209
int is_descendant_of(struct commit *, struct commit_list *);
206210
int in_merge_bases(struct commit *, struct commit *);

fetch-pack.c

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -184,36 +184,6 @@ static void consume_shallow_list(struct fetch_pack_args *args, int fd)
184184
}
185185
}
186186

187-
struct write_shallow_data {
188-
struct strbuf *out;
189-
int use_pack_protocol;
190-
int count;
191-
};
192-
193-
static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
194-
{
195-
struct write_shallow_data *data = cb_data;
196-
const char *hex = sha1_to_hex(graft->sha1);
197-
data->count++;
198-
if (data->use_pack_protocol)
199-
packet_buf_write(data->out, "shallow %s", hex);
200-
else {
201-
strbuf_addstr(data->out, hex);
202-
strbuf_addch(data->out, '\n');
203-
}
204-
return 0;
205-
}
206-
207-
static int write_shallow_commits(struct strbuf *out, int use_pack_protocol)
208-
{
209-
struct write_shallow_data data;
210-
data.out = out;
211-
data.use_pack_protocol = use_pack_protocol;
212-
data.count = 0;
213-
for_each_commit_graft(write_one_shallow, &data);
214-
return data.count;
215-
}
216-
217187
static enum ack_type get_ack(int fd, unsigned char *result_sha1)
218188
{
219189
int len;
@@ -795,27 +765,6 @@ static int cmp_ref_by_name(const void *a_, const void *b_)
795765
return strcmp(a->name, b->name);
796766
}
797767

798-
static void setup_alternate_shallow(void)
799-
{
800-
struct strbuf sb = STRBUF_INIT;
801-
int fd;
802-
803-
check_shallow_file_for_update();
804-
fd = hold_lock_file_for_update(&shallow_lock, git_path("shallow"),
805-
LOCK_DIE_ON_ERROR);
806-
if (write_shallow_commits(&sb, 0)) {
807-
if (write_in_full(fd, sb.buf, sb.len) != sb.len)
808-
die_errno("failed to write to %s", shallow_lock.filename);
809-
alternate_shallow_file = shallow_lock.filename;
810-
} else
811-
/*
812-
* is_repository_shallow() sees empty string as "no
813-
* shallow file".
814-
*/
815-
alternate_shallow_file = "";
816-
strbuf_release(&sb);
817-
}
818-
819768
static struct ref *do_fetch_pack(struct fetch_pack_args *args,
820769
int fd[2],
821770
const struct ref *orig_ref,
@@ -896,7 +845,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
896845
if (args->stateless_rpc)
897846
packet_flush(fd[1]);
898847
if (args->depth > 0)
899-
setup_alternate_shallow();
848+
setup_alternate_shallow(&shallow_lock, &alternate_shallow_file);
900849
else
901850
alternate_shallow_file = NULL;
902851
if (get_pack(args, fd, pack_lockfile))

http-push.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1976,7 +1976,7 @@ int main(int argc, char **argv)
19761976
pushing = 0;
19771977
if (prepare_revision_walk(&revs))
19781978
die("revision walk setup failed");
1979-
mark_edges_uninteresting(revs.commits, &revs, NULL);
1979+
mark_edges_uninteresting(&revs, NULL);
19801980
objects_to_send = get_delta(&revs, ref_lock);
19811981
finish_all_active_slots();
19821982

list-objects.c

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,19 +145,35 @@ static void mark_edge_parents_uninteresting(struct commit *commit,
145145
}
146146
}
147147

148-
void mark_edges_uninteresting(struct commit_list *list,
149-
struct rev_info *revs,
150-
show_edge_fn show_edge)
148+
void mark_edges_uninteresting(struct rev_info *revs, show_edge_fn show_edge)
151149
{
152-
for ( ; list; list = list->next) {
150+
struct commit_list *list;
151+
int i;
152+
153+
for (list = revs->commits; list; list = list->next) {
153154
struct commit *commit = list->item;
154155

155156
if (commit->object.flags & UNINTERESTING) {
156157
mark_tree_uninteresting(commit->tree);
158+
if (revs->edge_hint && !(commit->object.flags & SHOWN)) {
159+
commit->object.flags |= SHOWN;
160+
show_edge(commit);
161+
}
157162
continue;
158163
}
159164
mark_edge_parents_uninteresting(commit, revs, show_edge);
160165
}
166+
for (i = 0; i < revs->cmdline.nr; i++) {
167+
struct object *obj = revs->cmdline.rev[i].item;
168+
struct commit *commit = (struct commit *)obj;
169+
if (obj->type != OBJ_COMMIT || !(obj->flags & UNINTERESTING))
170+
continue;
171+
mark_tree_uninteresting(commit->tree);
172+
if (revs->edge_hint && !(obj->flags & SHOWN)) {
173+
obj->flags |= SHOWN;
174+
show_edge(commit);
175+
}
176+
}
161177
}
162178

163179
static void add_pending_tree(struct rev_info *revs, struct tree *tree)

list-objects.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ typedef void (*show_object_fn)(struct object *, const struct name_path *, const
66
void traverse_commit_list(struct rev_info *, show_commit_fn, show_object_fn, void *);
77

88
typedef void (*show_edge_fn)(struct commit *);
9-
void mark_edges_uninteresting(struct commit_list *, struct rev_info *, show_edge_fn);
9+
void mark_edges_uninteresting(struct rev_info *, show_edge_fn);
1010

1111
#endif

shallow.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "cache.h"
22
#include "commit.h"
33
#include "tag.h"
4+
#include "pkt-line.h"
45

56
static int is_shallow = -1;
67
static struct stat shallow_stat;
@@ -141,3 +142,81 @@ void check_shallow_file_for_update(void)
141142
)
142143
die("shallow file was changed during fetch");
143144
}
145+
146+
struct write_shallow_data {
147+
struct strbuf *out;
148+
int use_pack_protocol;
149+
int count;
150+
};
151+
152+
static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
153+
{
154+
struct write_shallow_data *data = cb_data;
155+
const char *hex = sha1_to_hex(graft->sha1);
156+
if (graft->nr_parent != -1)
157+
return 0;
158+
data->count++;
159+
if (data->use_pack_protocol)
160+
packet_buf_write(data->out, "shallow %s", hex);
161+
else {
162+
strbuf_addstr(data->out, hex);
163+
strbuf_addch(data->out, '\n');
164+
}
165+
return 0;
166+
}
167+
168+
int write_shallow_commits(struct strbuf *out, int use_pack_protocol)
169+
{
170+
struct write_shallow_data data;
171+
data.out = out;
172+
data.use_pack_protocol = use_pack_protocol;
173+
data.count = 0;
174+
for_each_commit_graft(write_one_shallow, &data);
175+
return data.count;
176+
}
177+
178+
char *setup_temporary_shallow(void)
179+
{
180+
struct strbuf sb = STRBUF_INIT;
181+
int fd;
182+
183+
if (write_shallow_commits(&sb, 0)) {
184+
struct strbuf path = STRBUF_INIT;
185+
strbuf_addstr(&path, git_path("shallow_XXXXXX"));
186+
fd = xmkstemp(path.buf);
187+
if (write_in_full(fd, sb.buf, sb.len) != sb.len)
188+
die_errno("failed to write to %s",
189+
path.buf);
190+
close(fd);
191+
strbuf_release(&sb);
192+
return strbuf_detach(&path, NULL);
193+
}
194+
/*
195+
* is_repository_shallow() sees empty string as "no shallow
196+
* file".
197+
*/
198+
return xstrdup("");
199+
}
200+
201+
void setup_alternate_shallow(struct lock_file *shallow_lock,
202+
const char **alternate_shallow_file)
203+
{
204+
struct strbuf sb = STRBUF_INIT;
205+
int fd;
206+
207+
check_shallow_file_for_update();
208+
fd = hold_lock_file_for_update(shallow_lock, git_path("shallow"),
209+
LOCK_DIE_ON_ERROR);
210+
if (write_shallow_commits(&sb, 0)) {
211+
if (write_in_full(fd, sb.buf, sb.len) != sb.len)
212+
die_errno("failed to write to %s",
213+
shallow_lock->filename);
214+
*alternate_shallow_file = shallow_lock->filename;
215+
} else
216+
/*
217+
* is_repository_shallow() sees empty string as "no
218+
* shallow file".
219+
*/
220+
*alternate_shallow_file = "";
221+
strbuf_release(&sb);
222+
}

t/t5500-fetch-pack.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,17 @@ test_expect_success 'fetch in shallow repo unreachable shallow objects' '
393393
git fsck --no-dangling
394394
)
395395
'
396+
test_expect_success 'fetch creating new shallow root' '
397+
(
398+
git clone "file://$(pwd)/." shallow10 &&
399+
git commit --allow-empty -m empty &&
400+
cd shallow10 &&
401+
git fetch --depth=1 --progress 2>actual &&
402+
# This should fetch only the empty commit, no tree or
403+
# blob objects
404+
grep "remote: Total 1" actual
405+
)
406+
'
396407

397408
test_expect_success 'setup tests for the --stdin parameter' '
398409
for head in C D E F

t/t5530-upload-pack-error.sh

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,6 @@ test_expect_success 'upload-pack fails due to error in rev-list' '
5454
printf "0032want %s\n0034shallow %s00000009done\n0000" \
5555
$(git rev-parse HEAD) $(git rev-parse HEAD^) >input &&
5656
test_must_fail git upload-pack . <input >/dev/null 2>output.err &&
57-
# pack-objects survived
58-
grep "Total.*, reused" output.err &&
59-
# but there was an error, which must have been in rev-list
6057
grep "bad tree object" output.err
6158
'
6259

0 commit comments

Comments
 (0)