fast-import: do less work when given "from" matches current branch head

When building a fast-import stream, it's easy to forget the fact that for non-merge commits happening on top of the current branch head, there is no need for a "from" command. That is corroborated by the fact that at least git-p4, hg-fast-export and felipec's git-remote-hg all unconditionally use a "from" command. Unfortunately, giving a "from" command always resets the branch tree, forcing it to be re-read, and in many cases, the pack is also closed and reopened through gfi_unpack_entry. Both are unnecessary overhead, and the latter is particularly slow at least on OSX. Avoid resetting the tree when it's unmodified, and avoid calling gfi_unpack_entry when the given mark points to the same commit as the current branch head. Signed-off-by: Mike Hommey <mh@glandium.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Mike Hommey committed Jul 9, 2015 at 15:50 UTC 0df3245721580a3d48c9766a311dd0e3367844b8
1 file changed +17 -12
fast-import.c
+17 -12
@@ -2588,14 +2588,12 @@ static int parse_from(struct branch *b)
2588 {
2589 const char *from;
2590 struct branch *s;
2591 + unsigned char sha1[20];
2592
2593 if (!skip_prefix(command_buf.buf, "from ", &from))
2594 return 0;
2595
2595 - if (b->branch_tree.tree) {
2596 - release_tree_content_recursive(b->branch_tree.tree);
2597 - b->branch_tree.tree = NULL;
2598 - }
2596 + hashcpy(sha1, b->branch_tree.versions[1].sha1);
2597
2598 s = lookup_branch(from);
2599 if (b == s)
@@ -2610,14 +2608,16 @@ static int parse_from(struct branch *b)
2608 struct object_entry *oe = find_mark(idnum);
2609 if (oe->type != OBJ_COMMIT)
2610 die("Mark :%" PRIuMAX " not a commit", idnum);
2613 - hashcpy(b->sha1, oe->idx.sha1);
2614 - if (oe->pack_id != MAX_PACK_ID) {
2615 - unsigned long size;
2616 - char *buf = gfi_unpack_entry(oe, &size);
2617 - parse_from_commit(b, buf, size);
2618 - free(buf);
2619 - } else
2620 - parse_from_existing(b);
2611 + if (hashcmp(b->sha1, oe->idx.sha1)) {
2612 + hashcpy(b->sha1, oe->idx.sha1);
2613 + if (oe->pack_id != MAX_PACK_ID) {
2614 + unsigned long size;
2615 + char *buf = gfi_unpack_entry(oe, &size);
2616 + parse_from_commit(b, buf, size);
2617 + free(buf);
2618 + } else
2619 + parse_from_existing(b);
2620 + }
2621 } else if (!get_sha1(from, b->sha1)) {
2622 parse_from_existing(b);
2623 if (is_null_sha1(b->sha1))
@@ -2626,6 +2626,11 @@ static int parse_from(struct branch *b)
2626 else
2627 die("Invalid ref name or SHA1 expression: %s", from);
2628
2629 + if (b->branch_tree.tree && hashcmp(sha1, b->branch_tree.versions[1].sha1)) {
2630 + release_tree_content_recursive(b->branch_tree.tree);
2631 + b->branch_tree.tree = NULL;
2632 + }
2633 +
2634 read_next_command();
2635 return 1;
2636 }