From 44055cec847fcdd43f5abd6095e798a3b92b39ce Mon Sep 17 00:00:00 2001 From: Kyle Rader Date: Fri, 22 May 2026 17:41:07 -0700 Subject: [PATCH 1/2] feat(repo stats): default to walking all commits with patch-id dedup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flip the default commit walk from `--first-parent` back to all commits. The `--first-parent` default was introduced as a workaround for inflated contributor counts after the cross-repo-history merge in a downstream Microsoft repo, but the workaround over-corrected — it silently dropped all authorship from history that was merged in via a side-parent. Now that patch-id dedup (v2.5.0) handles duplicate-commit inflation properly, restoring the all-commits default gives a much more accurate picture of who actually contributed to a repo. Concrete impact in the case-study repo: Before this PR (default = --first-parent): Kyle Rader: 131 commits over 6.1 months (drops 14+ months of work) After this PR (default = all + dedup): Kyle Rader: 413 commits over 1.2 years (matches reality) --no-dedup (raw SHA counts, for reference): Kyle Rader: 704 commits over 1.2 years (inflated by ~290 dup patches) The `--first-parent` behavior remains available as an opt-in flag for users who want one-tally-per-PR (e.g. mainline-merge release-history view). The deprecated `--all` flag is kept as a hidden no-op so existing scripts and muscle memory don't break — walking all commits is now the default. Bumps the crate version 2.5.0 -> 2.6.0 (backward-compatible default flip). --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- src/main.rs | 23 +++++++++++++++++------ 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03e99ea..3df0860 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -237,7 +237,7 @@ checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "loki-cli" -version = "2.5.0" +version = "2.6.0" dependencies = [ "chrono", "clap", diff --git a/Cargo.toml b/Cargo.toml index 85afd07..1e9dfeb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "loki-cli" -version = "2.5.0" +version = "2.6.0" authors = ["Kyle W. Rader"] description = "Loki: 🚀 A Git productivity tool" homepage = "https://github.com/kyle-rader/loki-cli" diff --git a/README.md b/README.md index 61b9eef..0310289 100644 --- a/README.md +++ b/README.md @@ -182,7 +182,7 @@ Analyze commits reachable from HEAD to see who has been landing work in a reposi - `--name` filters by author display name (repeatable, case-insensitive). - `--email` filters by author email (repeatable, case-insensitive). -- `--all` includes all commits (default is first-parent only). +- `--first-parent` restricts the walk to the first-parent chain of HEAD (one tally per merge commit). Default walks all commits reachable from HEAD, relying on patch-id dedup to handle rebased / cherry-picked / migrated history. - `--no-dedup` disables patch-id deduplication (see below). #### Patch-id deduplication diff --git a/src/main.rs b/src/main.rs index 31b829b..589e0a7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -75,8 +75,19 @@ struct RepoStatsOptions { #[clap(long, default_value_t = 20)] top: usize, - /// Include all commits (disables first-parent-only filtering). - #[clap(long, default_value = "false")] + /// Only count commits on the first-parent chain of HEAD. + /// + /// By default `lk repo stats` walks every commit reachable from HEAD + /// (with patch-id deduplication applied so logically-identical commits + /// from rebases / cherry-picks / cross-repo migrations are counted + /// once). Pass `--first-parent` to restrict the walk to the mainline + /// of merges into HEAD — useful when each PR is merged with a merge + /// commit and you want one tally per PR. + #[clap(long, default_value_t = false)] + first_parent: bool, + + /// Deprecated: walking all commits is now the default; this flag is a no-op. + #[clap(long, default_value_t = false, hide = true)] all: bool, /// Only include commits authored by these names (repeatable, case-insensitive fuzzy match). @@ -384,14 +395,14 @@ fn repo_stats(options: &RepoStatsOptions) -> Result<(), String> { progress.finish(); if totals.is_empty() { - if options.all { + if options.first_parent { println!( - "No commits found between {} and {}.", + "No first-parent commits found between {} and {}.", range.start_label, range.end_label ); } else { println!( - "No first-parent commits found between {} and {}.", + "No commits found between {} and {}.", range.start_label, range.end_label ); } @@ -464,7 +475,7 @@ fn collect_raw_commits( range: &TimeRange, ) -> Result, String> { let mut git_args: Vec = vec!["log".to_string()]; - if !options.all { + if options.first_parent { git_args.push("--first-parent".to_string()); } git_args.push("--pretty=format:%H%x09%ct%x09%an%x09%ae".to_string()); From 0e5a1b09cef2812d945ece592b6d9ffd6f84b47c Mon Sep 17 00:00:00 2001 From: Kyle Rader Date: Fri, 22 May 2026 17:42:07 -0700 Subject: [PATCH 2/2] Remove deprecated --all no-op flag Since we're introducing --first-parent as the opt-in toggle in the same release, just drop --all entirely rather than carrying a no-op deprecation shim. --- src/main.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index 589e0a7..2a744bc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -86,10 +86,6 @@ struct RepoStatsOptions { #[clap(long, default_value_t = false)] first_parent: bool, - /// Deprecated: walking all commits is now the default; this flag is a no-op. - #[clap(long, default_value_t = false, hide = true)] - all: bool, - /// Only include commits authored by these names (repeatable, case-insensitive fuzzy match). #[clap(long = "name", value_name = "NAME")] names: Vec,