fix(git): handle non-tracked files gracefully in diff operations

- Return empty line ranges when git diff fails for non-tracked files
- Prevents hook failures on .claude/settings.local.json and similar files
- Improves robustness when processing files outside git tracking
This commit is contained in:
carraes
2025-07-05 23:44:10 -03:00
parent 20135b3a7f
commit 62790b245e
+3 -19
View File
@@ -9,8 +9,6 @@ import (
"strings" "strings"
) )
func DetectRepo() (*GitStatus, error) { func DetectRepo() (*GitStatus, error) {
cmd := exec.Command("git", "rev-parse", "--show-toplevel") cmd := exec.Command("git", "rev-parse", "--show-toplevel")
output, err := cmd.Output() output, err := cmd.Output()
@@ -25,7 +23,6 @@ func DetectRepo() (*GitStatus, error) {
}, nil }, nil
} }
func GetStagedChanges() ([]FileChange, error) { func GetStagedChanges() ([]FileChange, error) {
cmd := exec.Command("git", "diff", "--cached", "--name-only") cmd := exec.Command("git", "diff", "--cached", "--name-only")
@@ -45,7 +42,6 @@ return []FileChange{}, nil
continue continue
} }
lineRanges, err := getLineRangesFromDiff(file, true) lineRanges, err := getLineRangesFromDiff(file, true)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get line ranges for %s: %v", file, err) return nil, fmt.Errorf("failed to get line ranges for %s: %v", file, err)
@@ -61,11 +57,9 @@ return []FileChange{}, nil
return changes, nil return changes, nil
} }
func GetUnstagedChanges() ([]FileChange, error) { func GetUnstagedChanges() ([]FileChange, error) {
var changes []FileChange var changes []FileChange
cmd := exec.Command("git", "diff", "--name-only") cmd := exec.Command("git", "diff", "--name-only")
output, err := cmd.Output() output, err := cmd.Output()
if err != nil { if err != nil {
@@ -78,7 +72,6 @@ func GetUnstagedChanges() ([]FileChange, error) {
continue continue
} }
lineRanges, err := getLineRangesFromDiff(file, false) lineRanges, err := getLineRangesFromDiff(file, false)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get line ranges for %s: %v", file, err) return nil, fmt.Errorf("failed to get line ranges for %s: %v", file, err)
@@ -91,7 +84,6 @@ func GetUnstagedChanges() ([]FileChange, error) {
}) })
} }
cmd = exec.Command("git", "ls-files", "--others", "--exclude-standard") cmd = exec.Command("git", "ls-files", "--others", "--exclude-standard")
output, err = cmd.Output() output, err = cmd.Output()
if err != nil { if err != nil {
@@ -104,7 +96,6 @@ func GetUnstagedChanges() ([]FileChange, error) {
continue continue
} }
changes = append(changes, FileChange{ changes = append(changes, FileChange{
Path: file, Path: file,
Status: StatusUntracked, Status: StatusUntracked,
@@ -115,7 +106,6 @@ LineRanges: []LineRange{},
return changes, nil return changes, nil
} }
func getLineRangesFromDiff(file string, staged bool) ([]LineRange, error) { func getLineRangesFromDiff(file string, staged bool) ([]LineRange, error) {
var cmd *exec.Cmd var cmd *exec.Cmd
if staged { if staged {
@@ -126,18 +116,17 @@ func getLineRangesFromDiff(file string, staged bool) ([]LineRange, error) {
output, err := cmd.Output() output, err := cmd.Output()
if err != nil { if err != nil {
return nil, err
return []LineRange{}, nil
} }
return ParseDiffUnified(string(output)) return ParseDiffUnified(string(output))
} }
func ParseDiffUnified(diff string) ([]LineRange, error) { func ParseDiffUnified(diff string) ([]LineRange, error) {
var ranges []LineRange var ranges []LineRange
headerRegex := regexp.MustCompile(`@@\s+-(\d+)(?:,(\d+))?\s+\+(\d+)(?:,(\d+))?\s+@@`) headerRegex := regexp.MustCompile(`@@\s+-(\d+)(?:,(\d+))?\s+\+(\d+)(?:,(\d+))?\s+@@`)
scanner := bufio.NewScanner(strings.NewReader(diff)) scanner := bufio.NewScanner(strings.NewReader(diff))
@@ -162,7 +151,6 @@ newCount = 1
} }
} }
if newCount > 0 { if newCount > 0 {
ranges = append(ranges, LineRange{ ranges = append(ranges, LineRange{
Start: newStart, Start: newStart,
@@ -175,7 +163,6 @@ newCount = 1
return ranges, scanner.Err() return ranges, scanner.Err()
} }
func IsInLineRanges(lineNum int, ranges []LineRange) bool { func IsInLineRanges(lineNum int, ranges []LineRange) bool {
for _, r := range ranges { for _, r := range ranges {
if lineNum >= r.Start && lineNum <= r.End { if lineNum >= r.Start && lineNum <= r.End {
@@ -185,18 +172,15 @@ func IsInLineRanges(lineNum int, ranges []LineRange) bool {
return false return false
} }
func GetChangesOnly() ([]FileChange, error) { func GetChangesOnly() ([]FileChange, error) {
var allChanges []FileChange var allChanges []FileChange
staged, err := GetStagedChanges() staged, err := GetStagedChanges()
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get staged changes: %v", err) return nil, fmt.Errorf("failed to get staged changes: %v", err)
} }
allChanges = append(allChanges, staged...) allChanges = append(allChanges, staged...)
unstaged, err := GetUnstagedChanges() unstaged, err := GetUnstagedChanges()
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get unstaged changes: %v", err) return nil, fmt.Errorf("failed to get unstaged changes: %v", err)