Skip to content

Commit 8cdf439

Browse files
authored
Merge pull request libgit2#4028 from chescock/improve-local-fetch
Transfer fewer objects on push and local fetch
2 parents 2b7a339 + 2dcfe51 commit 8cdf439

File tree

3 files changed

+25
-175
lines changed

3 files changed

+25
-175
lines changed

src/pack-objects.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1642,7 +1642,7 @@ int insert_tree(git_packbuilder *pb, git_tree *tree)
16421642
if ((error = retrieve_object(&obj, pb, git_tree_id(tree))) < 0)
16431643
return error;
16441644

1645-
if (obj->seen)
1645+
if (obj->seen || obj->uninteresting)
16461646
return 0;
16471647

16481648
obj->seen = 1;
@@ -1666,6 +1666,10 @@ int insert_tree(git_packbuilder *pb, git_tree *tree)
16661666

16671667
break;
16681668
case GIT_OBJ_BLOB:
1669+
if ((error = retrieve_object(&obj, pb, git_tree_id(tree))) < 0)
1670+
return error;
1671+
if (obj->uninteresting)
1672+
continue;
16691673
name = git_tree_entry_name(entry);
16701674
if ((error = git_packbuilder_insert(pb, entry_id, name)) < 0)
16711675
return error;

src/push.c

Lines changed: 2 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -263,12 +263,11 @@ static int enqueue_tag(git_object **out, git_push *push, git_oid *id)
263263
return error;
264264
}
265265

266-
static int revwalk(git_vector *commits, git_push *push)
266+
static int queue_objects(git_push *push)
267267
{
268268
git_remote_head *head;
269269
push_spec *spec;
270270
git_revwalk *rw;
271-
git_oid oid;
272271
unsigned int i;
273272
int error = -1;
274273

@@ -353,176 +352,10 @@ static int revwalk(git_vector *commits, git_push *push)
353352
git_revwalk_hide(rw, &head->oid);
354353
}
355354

356-
while ((error = git_revwalk_next(&oid, rw)) == 0) {
357-
git_oid *o = git__malloc(GIT_OID_RAWSZ);
358-
if (!o) {
359-
error = -1;
360-
goto on_error;
361-
}
362-
git_oid_cpy(o, &oid);
363-
if ((error = git_vector_insert(commits, o)) < 0)
364-
goto on_error;
365-
}
355+
error = git_packbuilder_insert_walk(push->pb, rw);
366356

367357
on_error:
368358
git_revwalk_free(rw);
369-
return error == GIT_ITEROVER ? 0 : error;
370-
}
371-
372-
static int enqueue_object(
373-
const git_tree_entry *entry,
374-
git_packbuilder *pb)
375-
{
376-
switch (git_tree_entry_type(entry)) {
377-
case GIT_OBJ_COMMIT:
378-
return 0;
379-
case GIT_OBJ_TREE:
380-
return git_packbuilder_insert_tree(pb, entry->oid);
381-
default:
382-
return git_packbuilder_insert(pb, entry->oid, entry->filename);
383-
}
384-
}
385-
386-
static int queue_differences(
387-
git_tree *base,
388-
git_tree *delta,
389-
git_packbuilder *pb)
390-
{
391-
git_tree *b_child = NULL, *d_child = NULL;
392-
size_t b_length = git_tree_entrycount(base);
393-
size_t d_length = git_tree_entrycount(delta);
394-
size_t i = 0, j = 0;
395-
int error;
396-
397-
while (i < b_length && j < d_length) {
398-
const git_tree_entry *b_entry = git_tree_entry_byindex(base, i);
399-
const git_tree_entry *d_entry = git_tree_entry_byindex(delta, j);
400-
int cmp = 0;
401-
402-
if (!git_oid__cmp(b_entry->oid, d_entry->oid))
403-
goto loop;
404-
405-
cmp = strcmp(b_entry->filename, d_entry->filename);
406-
407-
/* If the entries are both trees and they have the same name but are
408-
* different, then we'll recurse after adding the right-hand entry */
409-
if (!cmp &&
410-
git_tree_entry__is_tree(b_entry) &&
411-
git_tree_entry__is_tree(d_entry)) {
412-
/* Add the right-hand entry */
413-
if ((error = git_packbuilder_insert(pb, d_entry->oid,
414-
d_entry->filename)) < 0)
415-
goto on_error;
416-
417-
/* Acquire the subtrees and recurse */
418-
if ((error = git_tree_lookup(&b_child,
419-
git_tree_owner(base), b_entry->oid)) < 0 ||
420-
(error = git_tree_lookup(&d_child,
421-
git_tree_owner(delta), d_entry->oid)) < 0 ||
422-
(error = queue_differences(b_child, d_child, pb)) < 0)
423-
goto on_error;
424-
425-
git_tree_free(b_child); b_child = NULL;
426-
git_tree_free(d_child); d_child = NULL;
427-
}
428-
/* If the object is new or different in the right-hand tree,
429-
* then enumerate it */
430-
else if (cmp >= 0 &&
431-
(error = enqueue_object(d_entry, pb)) < 0)
432-
goto on_error;
433-
434-
loop:
435-
if (cmp <= 0) i++;
436-
if (cmp >= 0) j++;
437-
}
438-
439-
/* Drain the right-hand tree of entries */
440-
for (; j < d_length; j++)
441-
if ((error = enqueue_object(git_tree_entry_byindex(delta, j), pb)) < 0)
442-
goto on_error;
443-
444-
error = 0;
445-
446-
on_error:
447-
if (b_child)
448-
git_tree_free(b_child);
449-
450-
if (d_child)
451-
git_tree_free(d_child);
452-
453-
return error;
454-
}
455-
456-
static int queue_objects(git_push *push)
457-
{
458-
git_vector commits = GIT_VECTOR_INIT;
459-
git_oid *oid;
460-
size_t i;
461-
unsigned j;
462-
int error;
463-
464-
if ((error = revwalk(&commits, push)) < 0)
465-
goto on_error;
466-
467-
git_vector_foreach(&commits, i, oid) {
468-
git_commit *parent = NULL, *commit;
469-
git_tree *tree = NULL, *ptree = NULL;
470-
size_t parentcount;
471-
472-
if ((error = git_commit_lookup(&commit, push->repo, oid)) < 0)
473-
goto on_error;
474-
475-
/* Insert the commit */
476-
if ((error = git_packbuilder_insert(push->pb, oid, NULL)) < 0)
477-
goto loop_error;
478-
479-
parentcount = git_commit_parentcount(commit);
480-
481-
if (!parentcount) {
482-
if ((error = git_packbuilder_insert_tree(push->pb,
483-
git_commit_tree_id(commit))) < 0)
484-
goto loop_error;
485-
} else {
486-
if ((error = git_tree_lookup(&tree, push->repo,
487-
git_commit_tree_id(commit))) < 0 ||
488-
(error = git_packbuilder_insert(push->pb,
489-
git_commit_tree_id(commit), NULL)) < 0)
490-
goto loop_error;
491-
492-
/* For each parent, add the items which are different */
493-
for (j = 0; j < parentcount; j++) {
494-
if ((error = git_commit_parent(&parent, commit, j)) < 0 ||
495-
(error = git_commit_tree(&ptree, parent)) < 0 ||
496-
(error = queue_differences(ptree, tree, push->pb)) < 0)
497-
goto loop_error;
498-
499-
git_tree_free(ptree); ptree = NULL;
500-
git_commit_free(parent); parent = NULL;
501-
}
502-
}
503-
504-
error = 0;
505-
506-
loop_error:
507-
if (tree)
508-
git_tree_free(tree);
509-
510-
if (ptree)
511-
git_tree_free(ptree);
512-
513-
if (parent)
514-
git_commit_free(parent);
515-
516-
git_commit_free(commit);
517-
518-
if (error < 0)
519-
goto on_error;
520-
}
521-
522-
error = 0;
523-
524-
on_error:
525-
git_vector_free_deep(&commits);
526359
return error;
527360
}
528361

src/transports/local.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,21 @@ static int local_counting(int stage, unsigned int current, unsigned int total, v
507507
return error;
508508
}
509509

510+
static int foreach_reference_cb(git_reference *reference, void *payload)
511+
{
512+
git_revwalk *walk = (git_revwalk *)payload;
513+
514+
int error = git_revwalk_hide(walk, git_reference_target(reference));
515+
/* The reference is in the local repository, so the target may not
516+
* exist on the remote. It also may not be a commit. */
517+
if (error == GIT_ENOTFOUND || error == GITERR_INVALID) {
518+
giterr_clear();
519+
error = 0;
520+
}
521+
522+
return error;
523+
}
524+
510525
static int local_download_pack(
511526
git_transport *transport,
512527
git_repository *repo,
@@ -546,11 +561,6 @@ static int local_download_pack(
546561
if (git_object_type(obj) == GIT_OBJ_COMMIT) {
547562
/* Revwalker includes only wanted commits */
548563
error = git_revwalk_push(walk, &rhead->oid);
549-
if (!error && !git_oid_iszero(&rhead->loid)) {
550-
error = git_revwalk_hide(walk, &rhead->loid);
551-
if (error == GIT_ENOTFOUND)
552-
error = 0;
553-
}
554564
} else {
555565
/* Tag or some other wanted object. Add it on its own */
556566
error = git_packbuilder_insert_recur(pack, &rhead->oid, rhead->name);
@@ -560,6 +570,9 @@ static int local_download_pack(
560570
goto cleanup;
561571
}
562572

573+
if ((error = git_reference_foreach(repo, foreach_reference_cb, walk)))
574+
goto cleanup;
575+
563576
if ((error = git_packbuilder_insert_walk(pack, walk)))
564577
goto cleanup;
565578

0 commit comments

Comments
 (0)