From 132f21a711f88d2b4723dfec9e33b016185aa7c3 Mon Sep 17 00:00:00 2001 From: Satyam Kumar Date: Sat, 17 Jan 2026 14:23:33 +0530 Subject: [PATCH] fix: filter out non-existent commits in grep_ai_notes for shallow clones MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes orphaned git notes issue where git-ai stats would fail or return 0 AI lines when some commits referenced in git notes don't exist locally. This happens in: - Shallow clones (--depth=N) - Partial clones missing commits from other branches - Repos after force-push/rebase where old commits are gone The fix: 1. Use git cat-file -e to verify each commit exists before sorting 2. Filter out non-existent commits from the list 3. Only pass existing commits to git log --no-walk 4. Handle edge cases (no commits exist, only one exists) Tested with deputydev-spectator repo shallow clone where 2 out of 4 commits with a prompt were missing. After fix: - Before: 0 prompts loaded, ai_accepted: 0 - After: 1 prompt loaded, ai_accepted: 30 ✅ --- src/git/refs.rs | 62 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/src/git/refs.rs b/src/git/refs.rs index 71fe425db..cc9dc14cf 100644 --- a/src/git/refs.rs +++ b/src/git/refs.rs @@ -325,12 +325,51 @@ pub fn grep_ai_notes(repo: &Repository, pattern: &str) -> Result, Gi // If we have multiple results, sort by commit date (newest first) if shas.len() > 1 { let sha_vec: Vec = shas.into_iter().collect(); + + eprintln!("[DEBUG] Found {} commits with pattern '{}' in git notes", sha_vec.len(), pattern); + for sha in &sha_vec { + eprintln!("[DEBUG] - {}", sha); + } + + // FILTER OUT NON-EXISTENT COMMITS using git cat-file -e + let existing_shas: Vec = sha_vec + .into_iter() + .filter(|sha| { + let mut args = repo.global_args_for_exec(); + args.push("cat-file".to_string()); + args.push("-e".to_string()); + args.push(sha.clone()); + + let exists = exec_git(&args).is_ok(); + if !exists { + eprintln!("[DEBUG] Filtering out non-existent commit: {}", sha); + } + exists + }) + .collect(); + + eprintln!("[DEBUG] After filtering: {} existing commits", existing_shas.len()); + for sha in &existing_shas { + eprintln!("[DEBUG] - {}", sha); + } + + if existing_shas.is_empty() { + return Err(GitAiError::Generic( + "No existing commits found in git notes for pattern".to_string() + )); + } + + if existing_shas.len() == 1 { + return Ok(existing_shas); + } + + // Sort only existing commits by date let mut args = repo.global_args_for_exec(); args.push("log".to_string()); args.push("--format=%H".to_string()); args.push("--date-order".to_string()); args.push("--no-walk".to_string()); - for sha in &sha_vec { + for sha in &existing_shas { args.push(sha.clone()); } @@ -340,6 +379,25 @@ pub fn grep_ai_notes(repo: &Repository, pattern: &str) -> Result, Gi Ok(stdout.lines().map(|s| s.to_string()).collect()) } else { - Ok(shas.into_iter().collect()) + // Single or no result - verify it exists + let sha_vec: Vec = shas.into_iter().collect(); + if !sha_vec.is_empty() { + let sha = &sha_vec[0]; + let mut args = repo.global_args_for_exec(); + args.push("cat-file".to_string()); + args.push("-e".to_string()); + args.push(sha.clone()); + + if exec_git(&args).is_ok() { + Ok(sha_vec) + } else { + eprintln!("[DEBUG] Single commit {} does not exist", sha); + Err(GitAiError::Generic( + "Commit referenced in git notes does not exist".to_string() + )) + } + } else { + Ok(sha_vec) + } } }