From ef207d7d39bba47a9aab774c5c0a21909ad5de6b Mon Sep 17 00:00:00 2001 From: Alexander Shahorsky Date: Wed, 4 Feb 2026 20:38:23 +0100 Subject: [PATCH 1/5] Sync workspace branch from git status --- .../src/lib/trpc/routers/changes/status.ts | 108 ++++++++++++++++++ .../WorkspaceListItem/WorkspaceListItem.tsx | 11 +- .../RightSidebar/ChangesView/ChangesView.tsx | 9 ++ 3 files changed, 127 insertions(+), 1 deletion(-) diff --git a/apps/desktop/src/lib/trpc/routers/changes/status.ts b/apps/desktop/src/lib/trpc/routers/changes/status.ts index 43334e8ae03..c1b239ef90a 100644 --- a/apps/desktop/src/lib/trpc/routers/changes/status.ts +++ b/apps/desktop/src/lib/trpc/routers/changes/status.ts @@ -1,3 +1,6 @@ +import { projects, workspaces, worktrees } from "@superset/local-db"; +import { and, eq, isNull } from "drizzle-orm"; +import { localDb } from "main/lib/local-db"; import type { ChangedFile, GitChangesStatus } from "shared/changes-types"; import simpleGit from "simple-git"; import { z } from "zod"; @@ -30,6 +33,10 @@ export const createStatusRouter = () => { // Use --no-optional-locks to avoid holding locks on the repository const status = await getStatusNoLock(input.worktreePath); const parsed = parseGitStatus(status); + syncWorkspaceBranch({ + worktreePath: input.worktreePath, + currentBranch: parsed.branch, + }); // Run independent operations in parallel const [branchComparison, trackingStatus] = await Promise.all([ @@ -94,6 +101,107 @@ export const createStatusRouter = () => { }); }; +function syncWorkspaceBranch({ + worktreePath, + currentBranch, +}: { + worktreePath: string; + currentBranch: string; +}): void { + if (!currentBranch || currentBranch === "HEAD") { + return; + } + + try { + const worktree = localDb + .select() + .from(worktrees) + .where(eq(worktrees.path, worktreePath)) + .get(); + + if (worktree) { + if (worktree.branch !== currentBranch) { + localDb + .update(worktrees) + .set({ branch: currentBranch }) + .where(eq(worktrees.id, worktree.id)) + .run(); + } + + const workspacesForWorktree = localDb + .select({ branch: workspaces.branch }) + .from(workspaces) + .where( + and( + eq(workspaces.worktreeId, worktree.id), + isNull(workspaces.deletingAt), + ), + ) + .all(); + + const hasWorkspaceMismatch = workspacesForWorktree.some( + (ws) => ws.branch !== currentBranch, + ); + + if (hasWorkspaceMismatch) { + localDb + .update(workspaces) + .set({ branch: currentBranch }) + .where( + and( + eq(workspaces.worktreeId, worktree.id), + isNull(workspaces.deletingAt), + ), + ) + .run(); + } + + return; + } + + const project = localDb + .select() + .from(projects) + .where(eq(projects.mainRepoPath, worktreePath)) + .get(); + if (!project) { + return; + } + + const branchWorkspaces = localDb + .select({ branch: workspaces.branch }) + .from(workspaces) + .where( + and( + eq(workspaces.projectId, project.id), + eq(workspaces.type, "branch"), + isNull(workspaces.deletingAt), + ), + ) + .all(); + + const hasBranchMismatch = branchWorkspaces.some( + (ws) => ws.branch !== currentBranch, + ); + + if (hasBranchMismatch) { + localDb + .update(workspaces) + .set({ branch: currentBranch }) + .where( + and( + eq(workspaces.projectId, project.id), + eq(workspaces.type, "branch"), + isNull(workspaces.deletingAt), + ), + ) + .run(); + } + } catch (error) { + console.warn("[changes/status] Failed to sync branch:", error); + } +} + interface BranchComparison { commits: GitChangesStatus["commits"]; againstBase: ChangedFile[]; diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx index 9b34144a33c..a77b1f55a3a 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx @@ -15,7 +15,7 @@ import { toast } from "@superset/ui/sonner"; import { Tooltip, TooltipContent, TooltipTrigger } from "@superset/ui/tooltip"; import { cn } from "@superset/ui/utils"; import { useMatchRoute, useNavigate } from "@tanstack/react-router"; -import { useMemo, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { useDrag, useDrop } from "react-dnd"; import { HiMiniXMark } from "react-icons/hi2"; import { @@ -136,6 +136,15 @@ export function WorkspaceListItem({ }, ); + useEffect(() => { + const latestBranch = localChanges?.branch; + if (!latestBranch || latestBranch === "HEAD") return; + if (latestBranch !== branch) { + utils.workspaces.getAllGrouped.invalidate(); + utils.workspaces.get.invalidate({ id }); + } + }, [localChanges?.branch, branch, id, utils]); + // Calculate total local changes (staged + unstaged + untracked) const localDiffStats = useMemo(() => { if (!localChanges) return null; diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/ChangesView.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/ChangesView.tsx index 2d997692dbf..1198937fc4b 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/ChangesView.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/ChangesView.tsx @@ -33,6 +33,7 @@ interface ChangesViewProps { export function ChangesView({ onFileOpen, isExpandedView }: ChangesViewProps) { const { workspaceId } = useParams({ strict: false }); + const utils = electronTrpc.useUtils(); const { data: workspace } = electronTrpc.workspaces.get.useQuery( { id: workspaceId ?? "" }, { enabled: !!workspaceId }, @@ -69,6 +70,14 @@ export function ChangesView({ onFileOpen, isExpandedView }: ChangesViewProps) { }, ); + useEffect(() => { + if (!workspace || !status?.branch || status.branch === "HEAD") return; + if (workspace.branch !== status.branch) { + utils.workspaces.getAllGrouped.invalidate(); + utils.workspaces.get.invalidate({ id: workspace.id }); + } + }, [status?.branch, utils, workspace]); + const handleRefresh = () => { refetch(); refetchGithubStatus(); From 429faf0eac30229bcead861ffd372d086f449951 Mon Sep 17 00:00:00 2001 From: Alexander Shahorsky Date: Wed, 4 Feb 2026 20:46:13 +0100 Subject: [PATCH 2/5] Show actual branch in workspace hover card --- .../lib/trpc/routers/workspaces/procedures/git-status.ts | 2 ++ .../components/WorkspaceHoverCard/WorkspaceHoverCard.tsx | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/desktop/src/lib/trpc/routers/workspaces/procedures/git-status.ts b/apps/desktop/src/lib/trpc/routers/workspaces/procedures/git-status.ts index c17292d293b..1f978cb5200 100644 --- a/apps/desktop/src/lib/trpc/routers/workspaces/procedures/git-status.ts +++ b/apps/desktop/src/lib/trpc/routers/workspaces/procedures/git-status.ts @@ -131,9 +131,11 @@ export const createGitStatusProcedures = () => { // Extract worktree name from path (last segment) const worktreeName = worktree.path.split("/").pop() ?? worktree.branch; + const branchName = worktree.branch; return { worktreeName, + branchName, createdAt: worktree.createdAt, gitStatus: worktree.gitStatus ?? null, githubStatus: worktree.githubStatus ?? null, diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/WorkspaceHoverCard/WorkspaceHoverCard.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/WorkspaceHoverCard/WorkspaceHoverCard.tsx index 76942c2accc..aee13dfe0c2 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/WorkspaceHoverCard/WorkspaceHoverCard.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/WorkspaceHoverCard/WorkspaceHoverCard.tsx @@ -39,6 +39,7 @@ export function WorkspaceHoverCardContent({ const needsRebase = worktreeInfo?.gitStatus?.needsRebase; const worktreeName = worktreeInfo?.worktreeName; + const branchName = worktreeInfo?.branchName; const hasCustomAlias = workspaceAlias && worktreeName && workspaceAlias !== worktreeName; @@ -49,19 +50,19 @@ export function WorkspaceHoverCardContent({ {hasCustomAlias && (
{workspaceAlias}
)} - {worktreeName && ( + {branchName && (
Branch {repoUrl && branchExistsOnRemote ? ( - {worktreeName} + {branchName} - {worktreeName} + {branchName} )}
From 77798931f043ab07d8ec35589732a0c2169e48e3 Mon Sep 17 00:00:00 2001 From: Alexander Shahorsky Date: Wed, 4 Feb 2026 21:02:33 +0100 Subject: [PATCH 3/5] fix(desktop): refresh hover card branch after sync --- .../WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx | 1 + .../WorkspaceView/RightSidebar/ChangesView/ChangesView.tsx | 3 +++ 2 files changed, 4 insertions(+) diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx index a77b1f55a3a..dfa846c2a41 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx @@ -142,6 +142,7 @@ export function WorkspaceListItem({ if (latestBranch !== branch) { utils.workspaces.getAllGrouped.invalidate(); utils.workspaces.get.invalidate({ id }); + utils.workspaces.getWorktreeInfo.invalidate({ workspaceId: id }); } }, [localChanges?.branch, branch, id, utils]); diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/ChangesView.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/ChangesView.tsx index 1198937fc4b..c036164db02 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/ChangesView.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/ChangesView.tsx @@ -75,6 +75,9 @@ export function ChangesView({ onFileOpen, isExpandedView }: ChangesViewProps) { if (workspace.branch !== status.branch) { utils.workspaces.getAllGrouped.invalidate(); utils.workspaces.get.invalidate({ id: workspace.id }); + utils.workspaces.getWorktreeInfo.invalidate({ + workspaceId: workspace.id, + }); } }, [status?.branch, utils, workspace]); From 50ec29bce1d7cd49e708bc949384451eb4acdf5c Mon Sep 17 00:00:00 2001 From: Alexander Shahorsky Date: Wed, 4 Feb 2026 21:15:25 +0100 Subject: [PATCH 4/5] chore(desktop): add docstring for branch sync --- apps/desktop/src/lib/trpc/routers/changes/status.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/desktop/src/lib/trpc/routers/changes/status.ts b/apps/desktop/src/lib/trpc/routers/changes/status.ts index c1b239ef90a..d558b5cf184 100644 --- a/apps/desktop/src/lib/trpc/routers/changes/status.ts +++ b/apps/desktop/src/lib/trpc/routers/changes/status.ts @@ -101,6 +101,10 @@ export const createStatusRouter = () => { }); }; +/** + * Update local DB branch fields to match the current git branch for a worktree + * or main repo workspace path. + */ function syncWorkspaceBranch({ worktreePath, currentBranch, From 09f944fcdca98e934cd61eb454ee2b3d794af020 Mon Sep 17 00:00:00 2001 From: Satya Patel Date: Wed, 4 Feb 2026 14:16:41 -0800 Subject: [PATCH 5/5] refactor(desktop): extract shared hook and simplify branch sync - Extract duplicate useEffect cache invalidation logic from WorkspaceListItem and ChangesView into shared useBranchSyncInvalidation hook - Narrow useEffect dependencies to specific fields instead of full objects - Simplify syncWorkspaceBranch by using direct UPDATE with not(eq()) clause instead of SELECT-then-conditionally-UPDATE pattern, reducing DB queries on every 2.5s status poll --- .../src/lib/trpc/routers/changes/status.ts | 76 ++++++------------- .../WorkspaceListItem/WorkspaceListItem.tsx | 17 ++--- .../RightSidebar/ChangesView/ChangesView.tsx | 17 ++--- .../src/renderer/screens/main/hooks/index.ts | 1 + .../hooks/useBranchSyncInvalidation/index.ts | 1 + .../useBranchSyncInvalidation.ts | 29 +++++++ 6 files changed, 67 insertions(+), 74 deletions(-) create mode 100644 apps/desktop/src/renderer/screens/main/hooks/useBranchSyncInvalidation/index.ts create mode 100644 apps/desktop/src/renderer/screens/main/hooks/useBranchSyncInvalidation/useBranchSyncInvalidation.ts diff --git a/apps/desktop/src/lib/trpc/routers/changes/status.ts b/apps/desktop/src/lib/trpc/routers/changes/status.ts index d558b5cf184..cc4b1fea638 100644 --- a/apps/desktop/src/lib/trpc/routers/changes/status.ts +++ b/apps/desktop/src/lib/trpc/routers/changes/status.ts @@ -1,5 +1,5 @@ import { projects, workspaces, worktrees } from "@superset/local-db"; -import { and, eq, isNull } from "drizzle-orm"; +import { and, eq, isNull, not } from "drizzle-orm"; import { localDb } from "main/lib/local-db"; import type { ChangedFile, GitChangesStatus } from "shared/changes-types"; import simpleGit from "simple-git"; @@ -118,53 +118,40 @@ function syncWorkspaceBranch({ try { const worktree = localDb - .select() + .select({ id: worktrees.id }) .from(worktrees) .where(eq(worktrees.path, worktreePath)) .get(); if (worktree) { - if (worktree.branch !== currentBranch) { - localDb - .update(worktrees) - .set({ branch: currentBranch }) - .where(eq(worktrees.id, worktree.id)) - .run(); - } + localDb + .update(worktrees) + .set({ branch: currentBranch }) + .where( + and( + eq(worktrees.id, worktree.id), + not(eq(worktrees.branch, currentBranch)), + ), + ) + .run(); - const workspacesForWorktree = localDb - .select({ branch: workspaces.branch }) - .from(workspaces) + localDb + .update(workspaces) + .set({ branch: currentBranch }) .where( and( eq(workspaces.worktreeId, worktree.id), isNull(workspaces.deletingAt), + not(eq(workspaces.branch, currentBranch)), ), ) - .all(); - - const hasWorkspaceMismatch = workspacesForWorktree.some( - (ws) => ws.branch !== currentBranch, - ); - - if (hasWorkspaceMismatch) { - localDb - .update(workspaces) - .set({ branch: currentBranch }) - .where( - and( - eq(workspaces.worktreeId, worktree.id), - isNull(workspaces.deletingAt), - ), - ) - .run(); - } + .run(); return; } const project = localDb - .select() + .select({ id: projects.id }) .from(projects) .where(eq(projects.mainRepoPath, worktreePath)) .get(); @@ -172,35 +159,18 @@ function syncWorkspaceBranch({ return; } - const branchWorkspaces = localDb - .select({ branch: workspaces.branch }) - .from(workspaces) + localDb + .update(workspaces) + .set({ branch: currentBranch }) .where( and( eq(workspaces.projectId, project.id), eq(workspaces.type, "branch"), isNull(workspaces.deletingAt), + not(eq(workspaces.branch, currentBranch)), ), ) - .all(); - - const hasBranchMismatch = branchWorkspaces.some( - (ws) => ws.branch !== currentBranch, - ); - - if (hasBranchMismatch) { - localDb - .update(workspaces) - .set({ branch: currentBranch }) - .where( - and( - eq(workspaces.projectId, project.id), - eq(workspaces.type, "branch"), - isNull(workspaces.deletingAt), - ), - ) - .run(); - } + .run(); } catch (error) { console.warn("[changes/status] Failed to sync branch:", error); } diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx index dfa846c2a41..83d53e9cf29 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx @@ -15,7 +15,7 @@ import { toast } from "@superset/ui/sonner"; import { Tooltip, TooltipContent, TooltipTrigger } from "@superset/ui/tooltip"; import { cn } from "@superset/ui/utils"; import { useMatchRoute, useNavigate } from "@tanstack/react-router"; -import { useEffect, useMemo, useState } from "react"; +import { useMemo, useState } from "react"; import { useDrag, useDrop } from "react-dnd"; import { HiMiniXMark } from "react-icons/hi2"; import { @@ -36,6 +36,7 @@ import { import { navigateToWorkspace } from "renderer/routes/_authenticated/_dashboard/utils/workspace-navigation"; import { AsciiSpinner } from "renderer/screens/main/components/AsciiSpinner"; import { StatusIndicator } from "renderer/screens/main/components/StatusIndicator"; +import { useBranchSyncInvalidation } from "renderer/screens/main/hooks/useBranchSyncInvalidation"; import { useWorkspaceRename } from "renderer/screens/main/hooks/useWorkspaceRename"; import { useTabsStore } from "renderer/stores/tabs/store"; import { extractPaneIdsFromLayout } from "renderer/stores/tabs/utils"; @@ -136,15 +137,11 @@ export function WorkspaceListItem({ }, ); - useEffect(() => { - const latestBranch = localChanges?.branch; - if (!latestBranch || latestBranch === "HEAD") return; - if (latestBranch !== branch) { - utils.workspaces.getAllGrouped.invalidate(); - utils.workspaces.get.invalidate({ id }); - utils.workspaces.getWorktreeInfo.invalidate({ workspaceId: id }); - } - }, [localChanges?.branch, branch, id, utils]); + useBranchSyncInvalidation({ + gitBranch: localChanges?.branch, + workspaceBranch: branch, + workspaceId: id, + }); // Calculate total local changes (staged + unstaged + untracked) const localDiffStats = useMemo(() => { diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/ChangesView.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/ChangesView.tsx index c036164db02..7526e8b0d7a 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/ChangesView.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/ChangesView.tsx @@ -14,6 +14,7 @@ import { useEffect, useMemo, useState } from "react"; import { HiMiniMinus, HiMiniPlus } from "react-icons/hi2"; import { LuUndo2 } from "react-icons/lu"; import { electronTrpc } from "renderer/lib/electron-trpc"; +import { useBranchSyncInvalidation } from "renderer/screens/main/hooks/useBranchSyncInvalidation"; import { useChangesStore } from "renderer/stores/changes"; import type { ChangeCategory, ChangedFile } from "shared/changes-types"; import { CategorySection } from "./components/CategorySection"; @@ -33,7 +34,6 @@ interface ChangesViewProps { export function ChangesView({ onFileOpen, isExpandedView }: ChangesViewProps) { const { workspaceId } = useParams({ strict: false }); - const utils = electronTrpc.useUtils(); const { data: workspace } = electronTrpc.workspaces.get.useQuery( { id: workspaceId ?? "" }, { enabled: !!workspaceId }, @@ -70,16 +70,11 @@ export function ChangesView({ onFileOpen, isExpandedView }: ChangesViewProps) { }, ); - useEffect(() => { - if (!workspace || !status?.branch || status.branch === "HEAD") return; - if (workspace.branch !== status.branch) { - utils.workspaces.getAllGrouped.invalidate(); - utils.workspaces.get.invalidate({ id: workspace.id }); - utils.workspaces.getWorktreeInfo.invalidate({ - workspaceId: workspace.id, - }); - } - }, [status?.branch, utils, workspace]); + useBranchSyncInvalidation({ + gitBranch: status?.branch, + workspaceBranch: workspace?.branch, + workspaceId: workspaceId ?? "", + }); const handleRefresh = () => { refetch(); diff --git a/apps/desktop/src/renderer/screens/main/hooks/index.ts b/apps/desktop/src/renderer/screens/main/hooks/index.ts index 8b8a83fbc13..b6ab6ddd54e 100644 --- a/apps/desktop/src/renderer/screens/main/hooks/index.ts +++ b/apps/desktop/src/renderer/screens/main/hooks/index.ts @@ -1,2 +1,3 @@ +export { useBranchSyncInvalidation } from "./useBranchSyncInvalidation"; export { usePRStatus } from "./usePRStatus"; export { useWorkspaceRename } from "./useWorkspaceRename"; diff --git a/apps/desktop/src/renderer/screens/main/hooks/useBranchSyncInvalidation/index.ts b/apps/desktop/src/renderer/screens/main/hooks/useBranchSyncInvalidation/index.ts new file mode 100644 index 00000000000..c96f630a162 --- /dev/null +++ b/apps/desktop/src/renderer/screens/main/hooks/useBranchSyncInvalidation/index.ts @@ -0,0 +1 @@ +export { useBranchSyncInvalidation } from "./useBranchSyncInvalidation"; diff --git a/apps/desktop/src/renderer/screens/main/hooks/useBranchSyncInvalidation/useBranchSyncInvalidation.ts b/apps/desktop/src/renderer/screens/main/hooks/useBranchSyncInvalidation/useBranchSyncInvalidation.ts new file mode 100644 index 00000000000..6f8425c92c6 --- /dev/null +++ b/apps/desktop/src/renderer/screens/main/hooks/useBranchSyncInvalidation/useBranchSyncInvalidation.ts @@ -0,0 +1,29 @@ +import { useEffect } from "react"; +import { electronTrpc } from "renderer/lib/electron-trpc"; + +/** + * Invalidates workspace-related caches when the git branch (from status polling) + * diverges from the branch stored in the local DB workspace record. + * + * This keeps sidebar labels and hover cards in sync after external `git switch`. + */ +export function useBranchSyncInvalidation({ + gitBranch, + workspaceBranch, + workspaceId, +}: { + gitBranch: string | undefined; + workspaceBranch: string | undefined; + workspaceId: string; +}) { + const utils = electronTrpc.useUtils(); + + useEffect(() => { + if (!gitBranch || gitBranch === "HEAD" || !workspaceBranch) return; + if (gitBranch !== workspaceBranch) { + utils.workspaces.getAllGrouped.invalidate(); + utils.workspaces.get.invalidate({ id: workspaceId }); + utils.workspaces.getWorktreeInfo.invalidate({ workspaceId }); + } + }, [gitBranch, workspaceBranch, workspaceId, utils]); +}