Parse files from a git diff. For each changed file we capture: - The operation type (Added / Modified / Deleted / Renamed / Copied) - The new file content (for adds/modifies) - The old file content (for modifies/deletes) - The exact diff lines that git computed, so Phase 2 can build BranchOps directly from git's diff rather than re-diffing.
(
git_repo: &GitRepository,
diff: &Diff,
tree: &Tree,
parent_tree: Option<&Tree>,
capture_diff_lines: bool,
)
| 4282 | /// - The exact diff lines that git computed, so Phase 2 can build |
| 4283 | /// BranchOps directly from git's diff rather than re-diffing. |
| 4284 | fn parse_diff_files( |
| 4285 | git_repo: &GitRepository, |
| 4286 | diff: &Diff, |
| 4287 | tree: &Tree, |
| 4288 | parent_tree: Option<&Tree>, |
| 4289 | capture_diff_lines: bool, |
| 4290 | ) -> CliResult<Vec<ParsedFile>> { |
| 4291 | use std::collections::HashMap; |
| 4292 | |
| 4293 | // ── Step 1: collect per-file diff lines via diff.foreach ──────────── |
| 4294 | // |
| 4295 | // git2::Diff::foreach gives us each DiffLine with its origin (`+`/`-`/` `), |
| 4296 | // raw bytes, and old/new line numbers — exactly what `git diff` outputs. |
| 4297 | // We key by file path so we can attach them to the ParsedFile below. |
| 4298 | |
| 4299 | // Map from file path → accumulated diff lines for that file. |
| 4300 | let mut lines_by_path: HashMap<String, Vec<GitDiffLine>> = HashMap::new(); |
| 4301 | |
| 4302 | if capture_diff_lines { |
| 4303 | let _ = diff.foreach( |
| 4304 | &mut |_delta, _progress| true, // file_cb (no-op) |
| 4305 | None, // binary_cb |
| 4306 | None, // hunk_cb |
| 4307 | Some(&mut |delta, _hunk, line| { |
| 4308 | let origin = line.origin(); |
| 4309 | // We only keep `+`, `-`, and context (` `) lines. |
| 4310 | if origin != '+' && origin != '-' && origin != ' ' { |
| 4311 | return true; |
| 4312 | } |
| 4313 | let path = delta |
| 4314 | .new_file() |
| 4315 | .path() |
| 4316 | .or_else(|| delta.old_file().path()) |
| 4317 | .map(|p| p.to_string_lossy().to_string()) |
| 4318 | .unwrap_or_default(); |
| 4319 | |
| 4320 | lines_by_path.entry(path).or_default().push(GitDiffLine { |
| 4321 | origin, |
| 4322 | content: line.content().to_vec(), |
| 4323 | old_lineno: line.old_lineno(), |
| 4324 | new_lineno: line.new_lineno(), |
| 4325 | }); |
| 4326 | true |
| 4327 | }), |
| 4328 | ); |
| 4329 | } |
| 4330 | |
| 4331 | // ── Step 2: build ParsedFile entries from the delta list ───────────── |
| 4332 | |
| 4333 | let mut files = Vec::new(); |
| 4334 | |
| 4335 | for delta in diff.deltas() { |
| 4336 | let new_file = delta.new_file(); |
| 4337 | let old_file = delta.old_file(); |
| 4338 | |
| 4339 | // Skip submodules silently (warnings printed during Phase 2) |
| 4340 | if new_file.mode() == git2::FileMode::Commit || old_file.mode() == git2::FileMode::Commit { |
| 4341 | continue; |
no test coverage detected