Mark untracked directories that are git repositories

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-21 20:12:13 +02:00
co-authored by Claude Sonnet 5.5
parent 69d0f9b704
commit af6d03a5b1
7 changed files with 45 additions and 3 deletions
+3
View File
@@ -387,6 +387,9 @@ func changes(ctx context.Context, dir string, entries []entry) (*submodule.Chang
c.Added += n.added
c.Removed += n.removed
}
if e.kind == submodule.ChangeUntracked && strings.HasSuffix(e.path, "/") {
f.Repo = initialized(filepath.Join(dir, filepath.FromSlash(e.path)))
}
if e.kind != submodule.ChangeRemoved {
if fi, err := os.Stat(filepath.Join(dir, filepath.FromSlash(e.path))); err == nil {
f.Modified = fi.ModTime()
+1
View File
@@ -132,6 +132,7 @@ type FileChange struct {
Removed int // removed lines
Binary bool // line counts are unknown
Submodule bool // a nested submodule pointer changed
Repo bool // an untracked directory that is a git repository itself
Modified time.Time // modification time of the file; zero if it doesn't exist
}
+16 -1
View File
@@ -55,7 +55,7 @@ func (s *Status) Issues() []Issue {
case WorktreeModified:
out = append(out, Issue{IssueChanged, LevelWarn, "uncommitted changes"})
case WorktreeUntracked:
out = append(out, Issue{IssueChanged, LevelWarn, "untracked files"})
out = append(out, Issue{IssueChanged, LevelWarn, s.untrackedText()})
}
return out
}
@@ -79,3 +79,18 @@ func Walk(mods []*Submodule, fn func(*Submodule)) {
Walk(m.Children, fn)
}
}
// untrackedText words the untracked-files issue: "untracked repository" if
// everything untracked is a git repository of its own, e.g. a clone that was
// never added as a submodule.
func (s *Status) untrackedText() string {
if s.Changes == nil || s.Changes.Total != len(s.Changes.Files) {
return "untracked files"
}
for _, f := range s.Changes.Files {
if f.Kind != ChangeUntracked || !f.Repo {
return "untracked files"
}
}
return "untracked repository"
}
+19
View File
@@ -50,3 +50,22 @@ func TestHiddenIssues(t *testing.T) {
t.Errorf("HiddenIssues() = %d, %v; want 2, LevelDanger", count, worst)
}
}
func TestUntrackedRepositoryWording(t *testing.T) {
repo := FileChange{Path: "lib/x/", Kind: ChangeUntracked, Repo: true}
file := FileChange{Path: "a.txt", Kind: ChangeUntracked}
for _, c := range []struct {
files []FileChange
want string
}{
{[]FileChange{repo}, "untracked repository"},
{[]FileChange{repo, file}, "untracked files"},
{[]FileChange{file}, "untracked files"},
} {
s := &Status{Worktree: WorktreeUntracked, Changes: &Changes{Total: len(c.files), Files: c.files}}
got := s.Issues()
if len(got) == 0 || got[len(got)-1].Detail != c.want {
t.Errorf("%v: got %v, want %q", c.files, got, c.want)
}
}
}