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:
+6
-22
@@ -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")
|
||||||
@@ -36,7 +33,7 @@ func GetStagedChanges() ([]FileChange, error) {
|
|||||||
|
|
||||||
files := strings.Split(strings.TrimSpace(string(output)), "\n")
|
files := strings.Split(strings.TrimSpace(string(output)), "\n")
|
||||||
if len(files) == 1 && files[0] == "" {
|
if len(files) == 1 && files[0] == "" {
|
||||||
return []FileChange{}, nil
|
return []FileChange{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var changes []FileChange
|
var changes []FileChange
|
||||||
@@ -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,18 +96,16 @@ func GetUnstagedChanges() ([]FileChange, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
changes = append(changes, FileChange{
|
changes = append(changes, FileChange{
|
||||||
Path: file,
|
Path: file,
|
||||||
Status: StatusUntracked,
|
Status: StatusUntracked,
|
||||||
LineRanges: []LineRange{},
|
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))
|
||||||
@@ -154,7 +143,7 @@ func ParseDiffUnified(diff string) ([]LineRange, error) {
|
|||||||
|
|
||||||
var newCount int
|
var newCount int
|
||||||
if matches[4] == "" {
|
if matches[4] == "" {
|
||||||
newCount = 1
|
newCount = 1
|
||||||
} else {
|
} else {
|
||||||
newCount, err = strconv.Atoi(matches[4])
|
newCount, err = strconv.Atoi(matches[4])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user