When performing a 'git commit-graph write' with '--split', the commit-graph machinery calls 'merge_commit_graph()' after deciding on a split strategy to optionally clean up any existing commit-graph layers that were made obsolete by the split strategy [1]. At this time, 'merge_commit_graph()' checks each commit that it writes into the merged graph to make sure that it still exists in the object store. To do this, it uses 'lookup_commit_reference_gently()', which accepts either a commit object, or a tag that refers to a commit. However, since all 'oid' arguments passed to this function are from within the commit-graphs being merged, we never pass a commit reference, and so any time we spend in 'deref_tag()' is wasted. Improve the situation by using 'repo_has_object_file' to check if the object still exists, and '{lookup,repo_parse}_commit()' to turn it into a bona-fide 'struct commit *'. In my testing environment, this improves the time to "merge" a split commit-graph containing all reachable commits in the kernel by re-writing the same commit-graph (effectively measuring the time it takes to check that all of those commits still exist) from: Attempt 1: 9.614 Attempt 2: 10.984 Attempt 3: 10.39 Attempt 4: 9.14 Attempt 5: 9.439 real 0m9.140s user 0m8.207s sys 0m0.602s to: Attempt 1: 9.12 Attempt 2: 8.904 Attempt 3: 9.361 Attempt 4: 9.288 Attempt 5: 9.677 real 0m8.904s user 0m8.208s sys 0m0.596s yielding a modest ~2.6% improvement in the best timings from each run, and ~7.4% improvement on average. [1]: This can happen if, for example, the new commit-graph exceeds the maximum allowed factor on the number of commits. Co-authored-by: Jeff King <peff@xxxxxxxx> Signed-off-by: Jeff King <peff@xxxxxxxx> Signed-off-by: Taylor Blau <me@xxxxxxxxxxxx> --- commit-graph.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/commit-graph.c b/commit-graph.c index f013a84e29..c7cfadc786 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -1599,14 +1599,18 @@ static void merge_commit_graph(struct write_commit_graph_context *ctx, for (i = 0; i < g->num_commits; i++) { struct object_id oid; - struct commit *result; + struct commit *result = NULL; display_progress(ctx->progress, i + 1); load_oid_from_graph(g, i + offset, &oid); /* only add commits if they still exist in the repo */ - result = lookup_commit_reference_gently(ctx->r, &oid, 1); + if (repo_has_object_file(ctx->r, &oid)) { + result = lookup_commit(ctx->r, &oid); + if (repo_parse_commit(ctx->r, result)) + result = NULL; + } if (result) { ctx->commits.list[ctx->commits.nr] = result; -- 2.26.0.rc2.311.g8e52d2684b