Jeff King <peff@xxxxxxxx> writes: > Thanks, I was able to get it and reproduce your problem. The slowness is > in the expire-unreachable code. You can work around it with: > > git config gc.reflogExpireUnreachable never > > Obviously that's not really a fix, but it should let your "git gc" work. > > It looks like we do two merge-base calculations for each reflog entry, > which is what takes so long. Perhaps if we know we are going to do a > large number of reachability checks, we can pre-mark all reachable > commits, and then each reflog entry would just need to check the commit > mark. Thanks for the analysis, but expire_reflog() that is run for each ref already does that, I think. It first runs mark_reachable(), then walks each reflog entry for the ref to call expire_reflog_ent(), which in turn calls unreachable() that first checks if mark_reachable() has marked the commit, and if so we don't run in_merge_bases(). But if the commit in question is not reachable, then we end up running in_merge_bases() to double-check anyway, which is probably the symptom that was observed. So perhaps this is a workable compromise? builtin/reflog.c | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/builtin/reflog.c b/builtin/reflog.c index 64e45bd..7e278b8 100644 --- a/builtin/reflog.c +++ b/builtin/reflog.c @@ -230,6 +230,13 @@ static int unreachable(struct expire_reflog_cb *cb, struct commit *commit, unsig /* Reachable from the current ref? Don't prune. */ if (commit->object.flags & REACHABLE) return 0; + /* + * Unless there was a clock skew, younger ones that are + * reachable should have been marked by mark_reachable(). + */ + if (cb->cmd->expire_total < commit->date) + return 1; + if (in_merge_bases(commit, &cb->ref_commit, 1)) return 0; -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html