From 843641a959b1c7aa5f7c53b82545790676fb7c85 Mon Sep 17 00:00:00 2001 From: Syed Alam Shah Bukhari <161896817+syedalamshah@users.noreply.github.com> Date: Sun, 23 Nov 2025 00:19:44 +0000 Subject: [PATCH 1/3] Annotate object/commit lookup errors with referencing commit id --- src/git/repo.rs | 48 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/src/git/repo.rs b/src/git/repo.rs index db5fe08..382d208 100644 --- a/src/git/repo.rs +++ b/src/git/repo.rs @@ -128,7 +128,7 @@ impl GitRepo { let meta = if let Some(cached) = commit_cache.get(&commit_id) { cached.clone() } else { - let commit = self.repo.find_commit(commit_id)?; + let commit = self.find_commit_with_context(commit_id, None)?; let secs = commit.time()?.seconds; let timestamp = Utc.timestamp_opt(secs, 0) .single() @@ -203,9 +203,10 @@ impl GitRepo { parent_id: Option, binary: bool, ) -> Result { - let commit_tree = self.repo.find_commit(commit_id)?.tree()?; + let commit = self.find_commit_with_context(commit_id, Some(&commit_info.id))?; + let commit_tree = commit.tree()?; let parent_tree = if let Some(pid) = parent_id { - Some(self.repo.find_commit(pid)?.tree()?) + Some(self.find_commit_with_context(pid, Some(&commit_info.id))?.tree()?) } else { None }; @@ -213,7 +214,7 @@ impl GitRepo { self.repo.diff_tree_to_tree(parent_tree.as_ref(), Some(&commit_tree), None)?; let mut files = Vec::new(); for change in changes { - self.handle_change(change, binary, &mut files)?; + self.handle_change(change, binary, &mut files, &commit_info.id)?; } Ok(CommitStats { @@ -227,10 +228,11 @@ impl GitRepo { change: ChangeDetached, binary: bool, files: &mut Vec, + from_commit: &str, ) -> Result<()> { match change { ChangeDetached::Addition { id, location, .. } => { - let (is_binary, lines, _) = self.inspect_object(id)?; + let (is_binary, lines, _) = self.inspect_object(id, Some(from_commit))?; if binary || !is_binary { files.push(FileStats { path: location.to_string(), @@ -241,7 +243,7 @@ impl GitRepo { } } ChangeDetached::Deletion { id, location, .. } => { - let (is_binary, lines, _) = self.inspect_object(id)?; + let (is_binary, lines, _) = self.inspect_object(id, Some(from_commit))?; if binary || !is_binary { files.push(FileStats { path: location.to_string(), @@ -257,8 +259,8 @@ impl GitRepo { location, .. } => { - let (old_is_binary, _, old_obj) = self.inspect_object(previous_id)?; - let (new_is_binary, _, new_obj) = self.inspect_object(id)?; + let (old_is_binary, _, old_obj) = self.inspect_object(previous_id, Some(from_commit))?; + let (new_is_binary, _, new_obj) = self.inspect_object(id, Some(from_commit))?; let is_binary = old_is_binary || new_is_binary; if binary || !is_binary { let (added, deleted) = if is_binary { @@ -282,8 +284,8 @@ impl GitRepo { copy, .. } => { - let (old_is_binary, _, old_obj) = self.inspect_object(source_id)?; - let (new_is_binary, _, new_obj) = self.inspect_object(id)?; + let (old_is_binary, _, old_obj) = self.inspect_object(source_id, Some(from_commit))?; + let (new_is_binary, _, new_obj) = self.inspect_object(id, Some(from_commit))?; let is_binary = old_is_binary || new_is_binary; if binary || !is_binary { let (added, deleted) = if is_binary { @@ -309,13 +311,29 @@ impl GitRepo { Ok(()) } - fn inspect_object(&self, id: gix::ObjectId) -> Result<(bool, u32, gix::Object<'_>)> { - let obj = self.repo.find_object(id)?; + fn inspect_object(&self, id: gix::ObjectId, from_commit: Option<&str>) -> Result<(bool, u32, gix::Object<'_>)> { + let obj = self.repo.find_object(id).map_err(|e| { + if let Some(from) = from_commit { + GmapError::Other(format!("Object find error: {} (referenced from commit {})", e, from)) + } else { + GmapError::from(e) + } + })?; let is_binary = self.is_binary_object(&obj); let lines = if is_binary { 0 } else { self.count_lines(&obj)? }; Ok((is_binary, lines, obj)) } + fn find_commit_with_context<'a>(&'a self, id: ObjectId, from_commit: Option<&str>) -> Result> { + self.repo.find_commit(id).map_err(|e| { + if let Some(from) = from_commit { + GmapError::Other(format!("Object find error: {} (referenced from commit {})", e, from)) + } else { + GmapError::from(e) + } + }) + } + fn is_binary_object(&self, object: &gix::Object) -> bool { object.data.as_slice().iter().take(8192).any(|&b| b == 0) } @@ -422,12 +440,12 @@ impl GitRepo { /// Compute commit stats for a single commit by ID, using first parent when present. pub fn compute_commit_stats_for(&self, commit_id: ObjectId, binary: bool) -> Result { - let commit = self.repo.find_commit(commit_id)?; + let commit = self.find_commit_with_context(commit_id, None)?; let parent_id: Option = commit.parent_ids().next().map(|id| id.into()); let commit_tree = commit.tree()?; let parent_tree = if let Some(pid) = parent_id { - Some(self.repo.find_commit(pid)?.tree()?) + Some(self.find_commit_with_context(pid, Some(&commit.id.to_string()))?.tree()?) } else { None }; @@ -436,7 +454,7 @@ impl GitRepo { self.repo.diff_tree_to_tree(parent_tree.as_ref(), Some(&commit_tree), None)?; let mut files = Vec::new(); for change in changes { - self.handle_change(change, binary, &mut files)?; + self.handle_change(change, binary, &mut files, &commit.id.to_string())?; } Ok(CommitStats { commit_id: commit.id.to_string(), files }) From 1cea51d1b207a480eae6ec05cddf47cb9dd17465 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 30 Nov 2025 22:52:21 +0000 Subject: [PATCH 2/3] Initial plan From f77ba0fcb2c40d8ad14de444f8484d713fda4836 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 30 Nov 2025 22:58:00 +0000 Subject: [PATCH 3/3] Fix merge conflict and update gix::Commit type Co-authored-by: syedalamshah <161896817+syedalamshah@users.noreply.github.com> --- src/git/repo.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/git/repo.rs b/src/git/repo.rs index 92a5d0b..a1c2512 100644 --- a/src/git/repo.rs +++ b/src/git/repo.rs @@ -330,7 +330,7 @@ impl GitRepo { Ok((is_binary, lines, obj)) } - fn find_commit_with_context<'a>(&'a self, id: ObjectId, from_commit: Option<&str>) -> Result> { + fn find_commit_with_context<'a>(&'a self, id: ObjectId, from_commit: Option<&str>) -> Result> { self.repo.find_commit(id).map_err(|e| { if let Some(from) = from_commit { GmapError::Other(format!("Object find error: {} (referenced from commit {})", e, from)) @@ -450,10 +450,6 @@ impl GitRepo { } /// Compute commit stats for a single commit by ID, using first parent when present. - - pub fn compute_commit_stats_for(&self, commit_id: ObjectId, binary: bool) -> Result { - let commit = self.find_commit_with_context(commit_id, None)?; -======= pub fn compute_commit_stats_for( &self, commit_id: ObjectId,