Run ``git diff --unified=0`` and extract changed line ranges per file. Args: repo_root: Absolute path to the repository root. base: Git ref to diff against (default: ``HEAD~1``). Returns: Mapping of file paths to lists of ``(start_line, end_line)`` tuples. R
(
repo_root: str,
base: str = "HEAD~1",
)
| 31 | |
| 32 | |
| 33 | def parse_git_diff_ranges( |
| 34 | repo_root: str, |
| 35 | base: str = "HEAD~1", |
| 36 | ) -> dict[str, list[tuple[int, int]]]: |
| 37 | """Run ``git diff --unified=0`` and extract changed line ranges per file. |
| 38 | |
| 39 | Args: |
| 40 | repo_root: Absolute path to the repository root. |
| 41 | base: Git ref to diff against (default: ``HEAD~1``). |
| 42 | |
| 43 | Returns: |
| 44 | Mapping of file paths to lists of ``(start_line, end_line)`` tuples. |
| 45 | Returns an empty dict on error. |
| 46 | """ |
| 47 | if not _SAFE_GIT_REF.match(base): |
| 48 | logger.warning("Invalid git ref rejected: %s", base) |
| 49 | return {} |
| 50 | try: |
| 51 | result = subprocess.run( |
| 52 | ["git", "diff", "--unified=0", base, "--"], |
| 53 | capture_output=True, |
| 54 | stdin=subprocess.DEVNULL, |
| 55 | text=True, |
| 56 | encoding="utf-8", |
| 57 | errors="replace", |
| 58 | cwd=repo_root, |
| 59 | timeout=_GIT_TIMEOUT, |
| 60 | ) |
| 61 | if result.returncode != 0: |
| 62 | logger.warning("git diff failed (rc=%d): %s", result.returncode, result.stderr[:200]) |
| 63 | return {} |
| 64 | except (OSError, subprocess.SubprocessError) as exc: |
| 65 | logger.warning("git diff error: %s", exc) |
| 66 | return {} |
| 67 | |
| 68 | return _parse_unified_diff(result.stdout) |
| 69 | |
| 70 | |
| 71 | def parse_svn_diff_ranges( |