diff --git a/src-tauri/src/commands/folders.rs b/src-tauri/src/commands/folders.rs index 9b5155d..5e7a6df 100644 --- a/src-tauri/src/commands/folders.rs +++ b/src-tauri/src/commands/folders.rs @@ -1075,7 +1075,7 @@ pub async fn git_stash_show( pub async fn git_status(path: String) -> Result, AppCommandError> { let output = crate::process::tokio_command("git") .args(["-c", "core.quotePath=false"]) - .args(["status", "--porcelain=v1", "-uall"]) + .args(["status", "--porcelain=v1", "-unormal"]) .current_dir(&path) .output() .await diff --git a/src/components/layout/aux-panel-file-tree-tab.tsx b/src/components/layout/aux-panel-file-tree-tab.tsx index 09de0f0..6875666 100644 --- a/src/components/layout/aux-panel-file-tree-tab.tsx +++ b/src/components/layout/aux-panel-file-tree-tab.tsx @@ -409,8 +409,10 @@ interface RenderNodeProps { gitEnabled: boolean gitStatusByPath: ReadonlyMap gitChangedDirPaths: ReadonlySet + untrackedDirPaths: ReadonlySet gitignoreIgnoredPaths: ReadonlySet ancestorGitignoreIgnored: boolean + ancestorUntracked: boolean onOpenFilePreview: (path: string) => void onOpenFileDiff: (path: string) => void onOpenDirDiff: (path: string) => void @@ -433,8 +435,10 @@ function RenderNode({ gitEnabled, gitStatusByPath, gitChangedDirPaths, + untrackedDirPaths, gitignoreIgnoredPaths, ancestorGitignoreIgnored, + ancestorUntracked, onOpenFilePreview, onOpenFileDiff, onOpenDirDiff, @@ -465,7 +469,8 @@ function RenderNode({ })() if (node.kind === "file") { - const gitStatusCode = gitStatusByPath.get(node.path) + const gitStatusCode = + gitStatusByPath.get(node.path) ?? (ancestorUntracked ? "??" : undefined) const absolutePath = joinFsPath(workspacePath, node.path) const dirPath = parentDir(absolutePath) const isGitMenuDisabled = !gitEnabled || isGitignoreIgnored @@ -599,7 +604,11 @@ function RenderNode({ } const absolutePath = joinFsPath(workspacePath, node.path) - const dirHasChanges = !isGitignoreIgnored && gitChangedDirPaths.has(node.path) + const isThisDirUntracked = + ancestorUntracked || untrackedDirPaths.has(node.path) + const dirHasChanges = + !isGitignoreIgnored && + (gitChangedDirPaths.has(node.path) || isThisDirUntracked) const isGitMenuDisabled = !gitEnabled || isGitignoreIgnored const shouldRenderChildren = expandedPaths.has(node.path) @@ -638,8 +647,10 @@ function RenderNode({ gitEnabled={gitEnabled} gitStatusByPath={gitStatusByPath} gitChangedDirPaths={gitChangedDirPaths} + untrackedDirPaths={untrackedDirPaths} gitignoreIgnoredPaths={gitignoreIgnoredPaths} ancestorGitignoreIgnored={isGitignoreIgnored} + ancestorUntracked={isThisDirUntracked} onOpenFilePreview={onOpenFilePreview} onOpenFileDiff={onOpenFileDiff} onOpenDirDiff={onOpenDirDiff} @@ -908,7 +919,10 @@ export function FileTreeTab() { (entries: { file: string; status: string }[]) => { const nextStatusByPath = new Map() for (const entry of entries) { - const normalizedPath = normalizeGitStatusPath(entry.file) + const raw = normalizeGitStatusPath(entry.file) + if (!raw) continue + // Strip trailing slash (directory entries from -unormal) + const normalizedPath = raw.replace(/\/+$/, "") if (!normalizedPath) continue nextStatusByPath.set(normalizedPath, entry.status) } @@ -1182,6 +1196,20 @@ export function FileTreeTab() { return dirs }, [gitStatusByPath]) + // Directories that are entirely untracked (from git status -unormal) + const untrackedDirPaths = useMemo(() => { + const dirs = new Set() + for (const [path, status] of gitStatusByPath.entries()) { + if (status.trim() === "??") { + // Check if this path is a directory in the file tree + if (dirChildrenByPath.has(path)) { + dirs.add(path) + } + } + } + return dirs + }, [gitStatusByPath, dirChildrenByPath]) + const handleTreeSelect = useCallback( (path: string) => { if (!filePathSet.has(path)) return @@ -2163,8 +2191,10 @@ export function FileTreeTab() { gitEnabled={gitEnabled} gitStatusByPath={gitStatusByPath} gitChangedDirPaths={gitChangedDirPaths} + untrackedDirPaths={untrackedDirPaths} gitignoreIgnoredPaths={gitignoreIgnoredPaths} ancestorGitignoreIgnored={false} + ancestorUntracked={false} onOpenFilePreview={(path) => { void openFilePreview(path) }} diff --git a/src/components/layout/aux-panel-git-changes-tab.tsx b/src/components/layout/aux-panel-git-changes-tab.tsx index 4c67dbb..eb4d578 100644 --- a/src/components/layout/aux-panel-git-changes-tab.tsx +++ b/src/components/layout/aux-panel-git-changes-tab.tsx @@ -147,7 +147,7 @@ function normalizePathSegments(path: string): string[] { } function normalizeGitStatusPath(path: string): string { - const normalized = path.trim() + const normalized = path.trim().replace(/\/+$/, "") const renameSeparator = " -> " const renameIndex = normalized.lastIndexOf(renameSeparator) if (renameIndex < 0) return normalized