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,
)
| 3883 | /// - The exact diff lines that git computed, so Phase 2 can build |
| 3884 | /// BranchOps directly from git's diff rather than re-diffing. |
| 3885 | fn parse_diff_files( |
| 3886 | git_repo: &GitRepository, |
| 3887 | diff: &Diff, |
| 3888 | tree: &Tree, |
| 3889 | parent_tree: Option<&Tree>, |
| 3890 | capture_diff_lines: bool, |
| 3891 | ) -> CliResult<Vec<ParsedFile>> { |
| 3892 | use std::collections::HashMap; |
| 3893 | |
| 3894 | // ── Step 1: collect per-file diff lines via diff.foreach ──────────── |
| 3895 | // |
| 3896 | // git2::Diff::foreach gives us each DiffLine with its origin (`+`/`-`/` `), |
| 3897 | // raw bytes, and old/new line numbers — exactly what `git diff` outputs. |
| 3898 | // We key by file path so we can attach them to the ParsedFile below. |
| 3899 | |
| 3900 | // Map from file path → accumulated diff lines for that file. |
| 3901 | let mut lines_by_path: HashMap<String, Vec<GitDiffLine>> = HashMap::new(); |
| 3902 | |
| 3903 | if capture_diff_lines { |
| 3904 | let _ = diff.foreach( |
| 3905 | &mut |_delta, _progress| true, // file_cb (no-op) |
| 3906 | None, // binary_cb |
| 3907 | None, // hunk_cb |
| 3908 | Some(&mut |delta, _hunk, line| { |
| 3909 | let origin = line.origin(); |
| 3910 | // We only keep `+`, `-`, and context (` `) lines. |
| 3911 | if origin != '+' && origin != '-' && origin != ' ' { |
| 3912 | return true; |
| 3913 | } |
| 3914 | let path = delta |
| 3915 | .new_file() |
| 3916 | .path() |
| 3917 | .or_else(|| delta.old_file().path()) |
| 3918 | .map(|p| p.to_string_lossy().to_string()) |
| 3919 | .unwrap_or_default(); |
| 3920 | |
| 3921 | lines_by_path.entry(path).or_default().push(GitDiffLine { |
| 3922 | origin, |
| 3923 | content: line.content().to_vec(), |
| 3924 | old_lineno: line.old_lineno(), |
| 3925 | new_lineno: line.new_lineno(), |
| 3926 | }); |
| 3927 | true |
| 3928 | }), |
| 3929 | ); |
| 3930 | } |
| 3931 | |
| 3932 | // ── Step 2: build ParsedFile entries from the delta list ───────────── |
| 3933 | |
| 3934 | let mut files = Vec::new(); |
| 3935 | |
| 3936 | for delta in diff.deltas() { |
| 3937 | let new_file = delta.new_file(); |
| 3938 | let old_file = delta.old_file(); |
| 3939 | |
| 3940 | // Skip submodules silently (warnings printed during Phase 2) |
| 3941 | if new_file.mode() == git2::FileMode::Commit || old_file.mode() == git2::FileMode::Commit { |
| 3942 | continue; |
no test coverage detected