GetCommitRangeFileStats returns statistics (additions/deletions) for files changed between two commits. Returns a map from absolute file paths to their FileStats.
(repoPath, fromCommit, toCommit string)
| 210 | // GetCommitRangeFileStats returns statistics (additions/deletions) for files changed between two commits. |
| 211 | // Returns a map from absolute file paths to their FileStats. |
| 212 | func GetCommitRangeFileStats(repoPath, fromCommit, toCommit string) (map[string]vcs.FileStats, error) { |
| 213 | // Validate the repository path exists |
| 214 | if _, err := os.Stat(repoPath); os.IsNotExist(err) { |
| 215 | return nil, fmt.Errorf("repository path does not exist: %s", repoPath) |
| 216 | } |
| 217 | |
| 218 | // Verify it's a git repository |
| 219 | if !isGitRepository(repoPath) { |
| 220 | return nil, fmt.Errorf("%s is not a git repository", repoPath) |
| 221 | } |
| 222 | |
| 223 | // Validate both commits exist |
| 224 | if err := validateCommit(repoPath, fromCommit); err != nil { |
| 225 | return nil, err |
| 226 | } |
| 227 | if err := validateCommit(repoPath, toCommit); err != nil { |
| 228 | return nil, err |
| 229 | } |
| 230 | |
| 231 | // Get the repository root |
| 232 | repoRoot, err := GetRepositoryRoot(repoPath) |
| 233 | if err != nil { |
| 234 | return nil, fmt.Errorf("failed to get repository root: %w", err) |
| 235 | } |
| 236 | |
| 237 | // Run git diff --numstat to get stats for the range |
| 238 | stdout, stderr, err := runGitCommand(repoPath, "diff", "--numstat", fromCommit, toCommit) |
| 239 | if err != nil { |
| 240 | return nil, gitCommandError(err, stderr) |
| 241 | } |
| 242 | |
| 243 | // Get file statuses to determine if files are new |
| 244 | statusMap, err := getCommitRangeFileStatuses(repoPath, fromCommit, toCommit) |
| 245 | if err != nil { |
| 246 | return nil, err |
| 247 | } |
| 248 | |
| 249 | // Parse the numstat output |
| 250 | stats := make(map[string]vcs.FileStats) |
| 251 | lines := strings.Split(string(stdout), "\n") |
| 252 | for _, line := range lines { |
| 253 | line = strings.TrimSpace(line) |
| 254 | if line == "" { |
| 255 | continue |
| 256 | } |
| 257 | |
| 258 | // Format: additions deletions filename |
| 259 | parts := strings.Fields(line) |
| 260 | if len(parts) < 3 { |
| 261 | continue |
| 262 | } |
| 263 | |
| 264 | additions := 0 |
| 265 | deletions := 0 |
| 266 | |
| 267 | // Parse additions (may be "-" for binary files) |
| 268 | if parts[0] != "-" { |
| 269 | additions, _ = strconv.Atoi(parts[0]) |