Skip to content

Commit 238504b

Browse files
committed
Merge branch 'nd/fetch-into-shallow'
When there is no sufficient overlap between old and new history during a fetch into a shallow repository, we unnecessarily sent objects the sending side knows the receiving end has. * 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 79e46c9 + f21d2a7 commit 238504b

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
@@ -185,36 +185,6 @@ static void consume_shallow_list(struct fetch_pack_args *args, int fd)
185185
}
186186
}
187187

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

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

http-push.c

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

list-objects.c

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

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

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

162178
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

0 commit comments

Comments
 (0)