diff --git a/pkg/commands/git_commands/file_loader.go b/pkg/commands/git_commands/file_loader.go index 747572b38..7ec13836f 100644 --- a/pkg/commands/git_commands/file_loader.go +++ b/pkg/commands/git_commands/file_loader.go @@ -73,8 +73,16 @@ func (self *FileLoader) GetStatusFiles(opts GetStatusFileOptions) []*models.File continue } + // git status reports a directory that it doesn't descend into with a + // trailing slash. This is the case for a nested repository, and for + // any untracked directory if status.showUntrackedFiles is "normal". We + // take the slash off so that the file tree shows the directory as a + // single entry; it would otherwise split the path into a directory and + // a file without a name. + path := strings.TrimSuffix(status.Path, "/") + file := &models.File{ - Path: status.Path, + Path: path, PreviousPath: status.PreviousPath, DisplayString: status.StatusString, } diff --git a/pkg/commands/git_commands/file_loader_test.go b/pkg/commands/git_commands/file_loader_test.go index 23602ff9e..ad8882715 100644 --- a/pkg/commands/git_commands/file_loader_test.go +++ b/pkg/commands/git_commands/file_loader_test.go @@ -188,6 +188,26 @@ func TestFileGetStatusFiles(t *testing.T) { }, }, }, + { + testName: "Directory that git doesn't descend into", + similarityThreshold: 50, + runner: oscommands.NewFakeRunner(t). + ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z", "--find-renames=50%"}, "?? dir/nested/", nil), + expectedFiles: []*models.File{ + { + Path: "dir/nested", + HasStagedChanges: false, + HasUnstagedChanges: true, + Tracked: false, + Added: true, + Deleted: false, + HasMergeConflicts: false, + HasInlineMergeConflicts: false, + DisplayString: "?? dir/nested/", + ShortStatus: "??", + }, + }, + }, { testName: "Renamed files", similarityThreshold: 50, diff --git a/pkg/gui/controllers/helpers/refresh_helper.go b/pkg/gui/controllers/helpers/refresh_helper.go index 826d12400..0cbde1f70 100644 --- a/pkg/gui/controllers/helpers/refresh_helper.go +++ b/pkg/gui/controllers/helpers/refresh_helper.go @@ -1467,9 +1467,7 @@ func (self *RefreshHelper) refreshStateFiles(captured capturedFilesState, env re } // markWorktreeFiles marks the files that are linked worktrees of this repo, so -// that the files view can render them as such. `git status` reports a worktree -// as an untracked directory, i.e. with a trailing slash, which we take off: -// keeping it would build a directory node with a nameless file inside it. +// that the files view can render them as such. // // It must run on the UI thread, as it works on the model. Both models it needs // are written by refreshes of their own, so it is called after either of them @@ -1487,12 +1485,6 @@ func markWorktreeFiles(files []*models.File, worktrees []*models.Worktree, workt file.IsWorktree = isWorktree changed = true } - if isWorktree { - if trimmed := strings.TrimSuffix(file.Path, "/"); trimmed != file.Path { - file.Path = trimmed - changed = true - } - } } return changed diff --git a/pkg/gui/controllers/helpers/refresh_helper_test.go b/pkg/gui/controllers/helpers/refresh_helper_test.go index 5e58c56a3..1ef4b581a 100644 --- a/pkg/gui/controllers/helpers/refresh_helper_test.go +++ b/pkg/gui/controllers/helpers/refresh_helper_test.go @@ -309,12 +309,12 @@ func TestMarkWorktreeFiles(t *testing.T) { {Path: filepath.Join("/", "path", "to", "worktree3")}, } - t.Run("marks the files that are worktrees, and takes their slash off", func(t *testing.T) { + t.Run("marks the files that are worktrees", func(t *testing.T) { files := []*models.File{ {Path: "file"}, - {Path: "worktree1/"}, - {Path: "dir/worktree2/"}, - {Path: "dir/"}, + {Path: "worktree1"}, + {Path: "dir/worktree2"}, + {Path: "dir"}, } assert.True(t, markWorktreeFiles(files, worktrees, worktreePath)) @@ -322,12 +322,12 @@ func TestMarkWorktreeFiles(t *testing.T) { {Path: "file"}, {Path: "worktree1", IsWorktree: true}, {Path: "dir/worktree2", IsWorktree: true}, - {Path: "dir/"}, + {Path: "dir"}, }, files) }) t.Run("reports no change when there is nothing to mark", func(t *testing.T) { - files := []*models.File{{Path: "file"}, {Path: "dir/"}} + files := []*models.File{{Path: "file"}, {Path: "dir"}} assert.False(t, markWorktreeFiles(files, worktrees, worktreePath)) }) diff --git a/pkg/integration/tests/submodule/discard_removed_submodule.go b/pkg/integration/tests/submodule/discard_removed_submodule.go index 514f01900..b417a9953 100644 --- a/pkg/integration/tests/submodule/discard_removed_submodule.go +++ b/pkg/integration/tests/submodule/discard_removed_submodule.go @@ -26,12 +26,8 @@ var DiscardRemovedSubmodule = NewIntegrationTest(NewIntegrationTestArgs{ t.Views().Files(). IsFocused(). Lines( - /* EXPECTED: Equals("▼ modules").IsSelected(), Equals(" ?? sub"), - ACTUAL: */ - Equals("▼ modules/sub").IsSelected(), - Equals(" ?? "), ). Press(keys.Universal.Remove). Tap(func() { @@ -40,15 +36,7 @@ var DiscardRemovedSubmodule = NewIntegrationTest(NewIntegrationTestArgs{ Select(Contains("Discard all changes")). Confirm() }). - /* EXPECTED: IsFocused(). - ACTUAL: */ - Tap(func() { - t.ExpectPopup().Alert(). - Title(Equals("Error")). - Content(Equals("open modules/sub: no such file or directory")). - Confirm() - }). IsEmpty() t.FileSystem().PathNotPresent("modules/sub")