Skip to content

Commit fa1c18f

Browse files
authored
feat: clean untracked files (#2237)
Updates #1682
1 parent cb44b42 commit fa1c18f

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

internal/gitrepo/gitrepo.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"log/slog"
2222
"os"
2323
"os/exec"
24+
"path/filepath"
2425
"strings"
2526
"time"
2627

@@ -46,6 +47,7 @@ type Repository interface {
4647
CreateBranchAndCheckout(name string) error
4748
Push(branchName string) error
4849
Restore(paths []string) error
50+
CleanUntracked(paths []string) error
4951
pushRefSpec(refSpec string) error
5052
}
5153

@@ -479,3 +481,33 @@ func (r *LocalRepository) Restore(paths []string) error {
479481
cmd.Dir = r.Dir
480482
return cmd.Run()
481483
}
484+
485+
// CleanUntracked removes untracked files within the given paths.
486+
func (r *LocalRepository) CleanUntracked(paths []string) error {
487+
slog.Info("Cleaning untracked files", "paths", strings.Join(paths, ","))
488+
worktree, err := r.repo.Worktree()
489+
if err != nil {
490+
return err
491+
}
492+
493+
status, err := worktree.Status()
494+
if err != nil {
495+
return err
496+
}
497+
498+
// Remove an untracked file if it lives within one of the given paths.
499+
for _, path := range paths {
500+
for file, fileStatue := range status {
501+
if !strings.Contains(file, path) || fileStatue.Worktree != git.Untracked {
502+
continue
503+
}
504+
505+
relPath := filepath.Join(r.Dir, file)
506+
if err := os.Remove(relPath); err != nil {
507+
return fmt.Errorf("failed to remove untracked file, %s: %q", relPath, err)
508+
}
509+
}
510+
}
511+
512+
return nil
513+
}

internal/gitrepo/gitrepo_test.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,6 +1192,78 @@ func TestRestore(t *testing.T) {
11921192
}
11931193
}
11941194

1195+
func TestCleanUntracked(t *testing.T) {
1196+
t.Parallel()
1197+
for _, test := range []struct {
1198+
name string
1199+
paths []string
1200+
}{
1201+
{
1202+
name: "remove_untracked_files_in_paths",
1203+
paths: []string{
1204+
"first/path",
1205+
"second/path",
1206+
},
1207+
},
1208+
} {
1209+
t.Run(test.name, func(t *testing.T) {
1210+
t.Parallel()
1211+
repo, dir := initTestRepo(t)
1212+
localRepo := &LocalRepository{
1213+
Dir: dir,
1214+
repo: repo,
1215+
}
1216+
1217+
// Create tracked files.
1218+
for _, path := range test.paths {
1219+
relPath := filepath.Join(dir, path)
1220+
if err := os.MkdirAll(relPath, 0755); err != nil {
1221+
t.Fatal(err)
1222+
}
1223+
trackedFile := filepath.Join(relPath, "tracked.txt")
1224+
if err := os.WriteFile(trackedFile, []byte("new content"), 0755); err != nil {
1225+
t.Fatal(err)
1226+
}
1227+
}
1228+
1229+
if _, err := localRepo.AddAll(); err != nil {
1230+
t.Fatal(err)
1231+
}
1232+
1233+
// Create untracked files.
1234+
for _, path := range test.paths {
1235+
relPath := filepath.Join(dir, path)
1236+
if err := os.MkdirAll(relPath, 0755); err != nil {
1237+
t.Fatal(err)
1238+
}
1239+
untrackedFile := filepath.Join(relPath, "untracked.txt")
1240+
if err := os.WriteFile(untrackedFile, []byte("new content"), 0755); err != nil {
1241+
t.Fatal(err)
1242+
}
1243+
}
1244+
1245+
if err := localRepo.CleanUntracked(test.paths); err != nil {
1246+
t.Error(err)
1247+
1248+
return
1249+
}
1250+
1251+
for _, path := range test.paths {
1252+
// Verify the untracked files are removed.
1253+
untrackedFile := filepath.Join(dir, path, "untracked.txt")
1254+
if _, err := os.Stat(untrackedFile); !os.IsNotExist(err) {
1255+
t.Errorf("untracked file, %s should be removed", untrackedFile)
1256+
}
1257+
// Verify the tracked files are untouched.
1258+
trackedFile := filepath.Join(dir, path, "tracked.txt")
1259+
if _, err := os.Stat(trackedFile); err != nil {
1260+
t.Errorf("tracked file, %s should not be touched: %q", trackedFile, err)
1261+
}
1262+
}
1263+
})
1264+
}
1265+
}
1266+
11951267
// initTestRepo creates a new git repository in a temporary directory.
11961268
func initTestRepo(t *testing.T) (*git.Repository, string) {
11971269
t.Helper()

0 commit comments

Comments
 (0)