From 2d6ef56b38385f5ee87bfec9c5e0f8f7ddc60f7c Mon Sep 17 00:00:00 2001 From: BryanFRD Date: Wed, 15 Jul 2026 22:34:26 +0200 Subject: [PATCH] perf(monorepo): reuse the tag index ancestor set instead of walking twice --- src/monorepo/run/mod.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/monorepo/run/mod.rs b/src/monorepo/run/mod.rs index 4aa0f6f..4f6d5ad 100644 --- a/src/monorepo/run/mod.rs +++ b/src/monorepo/run/mod.rs @@ -142,18 +142,16 @@ pub(super) fn run_release_logic( .unwrap_or_default(); let all_tags = collect_all_tags(&repo); - // Build the HEAD ancestor set once so the per-package find_*_tag calls - // below can skip their per-tag graph_descendant_of walk. On dense - // monorepos (mono-large: 200 pkg × 10k commits) this is the - // difference between 1.8 s and a couple hundred ms for the tag-bound - // commands. - let head_ancestors = crate::git::build_head_ancestors(&repo).ok(); // Pre-collect all tags + their commit OIDs in one tag_foreach scan // so the per-package find_*_tag / get_*_since_tag calls below don't // each repeat that scan. Coupled with the ancestor set, the per-pkg // lookups collapse from O(tags) callbacks + O(commits) walk to O(1) // hash hits. let tag_index = timing.stage("build TagIndex", || crate::git::TagIndex::build(&repo).ok()); + let fallback_ancestors = match &tag_index { + Some(_) => None, + None => crate::git::build_head_ancestors(&repo).ok(), + }; let target_branch = if prerelease_ctx.is_prerelease() { current_branch.clone() @@ -195,7 +193,10 @@ pub(super) fn run_release_logic( config, root, tag_index: tag_index.as_ref(), - head_ancestors: head_ancestors.as_ref(), + head_ancestors: tag_index + .as_ref() + .map(|idx| &idx.ancestors) + .or(fallback_ancestors.as_ref()), all_tags: &all_tags, prerelease_ctx: &prerelease_ctx, forced: &forced,