# IMPLEMENT_GIT ## Goal Implement a VS Code-like Git sidebar workflow for the current project in bDS with: - Left sidebar rail sync icon (bottom section, directly above Settings) - Sidebar split into upper **Open Changes** and lower **Version History** - File click to open diff view against repository in editor tabs with transient/persistent behavior - `Initialize Git` action when no repo exists - Periodic status polling and remote fetch polling - Fetch / Pull / Push actions in repo header - Commit message input + `Commit` button (add-all + commit) This plan is scoped to the existing Electron architecture: - Main process business logic in `src/main/engine` - IPC handlers in `src/main/ipc` - Typed bridge in `src/main/preload.ts` and `src/main/shared/electronApi` - Renderer state/UI in `src/renderer/store` and `src/renderer/components` --- ## External Requirements ## 1) Runtime Dependencies - **Primary library**: `simple-git` - **System requirement**: `git` CLI installed and available in PATH - **System requirement**: `git-lfs` CLI installed and available in PATH - **Optional later**: fallback to bundled Git binary for users without system Git ## 2) OS / Packaging - Support macOS, Linux, Windows path handling and quoting. - If bundling Git later, include signing/notarization and license notices in release pipeline. ## 3) Performance Requirements - Must handle large change sets without list jump/reflow issues. - Polling and fetch operations must be background/non-blocking and cancellable. ## 4) Security Requirements - Run all Git commands in main process only. - Validate project root path before command execution. - Never allow arbitrary command injection via renderer inputs. --- ## UX and Behavioral Requirements (from spec) ## Sidebar Rail Button - Add a new Git sync icon button in the left sidebar rail bottom section, directly above the Settings icon. - Clicking icon opens/closes Git sidebar view similarly to existing views. ## Sidebar Layout (Git view) - Upper half: **Open Changes** list. - Lower half: **Version History** list. - Repo actions in header: **Fetch**, **Pull**, **Push** icons. - Open Changes area includes: - Commit message input field - Commit button (does add-all + commit) ## No Repository State - If current project is not a git repo: - show `Initialize Git` button. - action runs `git init`, then enables Git LFS for this repository only (`git lfs install --local`, no global hook installation) and tracks image file types (e.g. `*.png`, `*.jpg`, `*.jpeg`, `*.gif`, `*.webp`, `*.svg`, `*.avif`, `*.heic`) so binary image assets are excluded from normal Git object/version storage. - if git executable not found, show explicit install guidance message. - if Git LFS executable not found, show explicit install guidance message and block completion of initialization. ## Diff Behavior - Diff views open in tabs in the editor area. - Single-click on a changed file opens a diff in a transient tab (reused for subsequent single-clicks), matching post transient tab behavior. - Double-click on a changed file opens a dedicated non-transient diff tab that remains open until explicitly closed by the user. - Dedicated diff tabs stay open even when other files are clicked in the sidebar. - Open diff tabs are persisted in app tab state and restored on next app start, same persistence model as post tabs. - Clicking a changed file opens diff view of working tree vs repository (HEAD/index depending file state). - Committing changes automatically closes all open diff tabs because the compared diff baseline no longer applies. ## Polling Behavior - Poll git status regularly (VS Code-like freshness). - Refresh should be incremental (preserve list item identity/order strategy where possible). - Preserve scroll position for large lists; avoid jump-to-top. ## Remote Awareness - If remote exists, perform regular `git fetch` polling. - Show upstream relationship in version history section: - current local HEAD - upstream branch tip - ahead/behind indicators --- ## Proposed Architecture ## Main Process (new engine) Create `src/main/engine/GitEngine.ts` with focused methods: - `checkAvailability(): Promise<{ gitFound: boolean; version?: string }>` - `getRepoState(projectPath): Promise` - `initializeRepo(projectPath): Promise` - `getStatus(projectPath): Promise` - `getDiff(projectPath, filePath): Promise` - `getHistory(projectPath, limit, cursor?): Promise` - `getRemoteState(projectPath): Promise` - `fetch(projectPath): Promise` - `pull(projectPath): Promise` - `push(projectPath): Promise` - `commitAll(projectPath, message): Promise` Implementation notes: - Use `simple-git` instance rooted at active project path. - Distinguish error classes: - git missing - not a repo - auth/network/merge conflict - detached HEAD / no upstream - Normalize file paths to repo-relative format for renderer stability. ## IPC Layer Add handlers in `src/main/ipc/handlers.ts` and type contracts in shared API: - `git:checkAvailability` - `git:getRepoState` - `git:init` - `git:status` - `git:diff` - `git:history` - `git:remoteState` - `git:fetch` - `git:pull` - `git:push` - `git:commitAll` Expose via `src/main/preload.ts`: - `window.electronAPI.git.*` methods. ## Renderer State Extend `src/renderer/store/appStore.ts` with Git slice: - `activeView` union includes `'git'` - `git: {` - `availability` - `repoState` - `status` (files + counts) - `history` - `remoteState` (branch, upstream, ahead, behind, lastFetchAt) - `selectedDiffFile` - `commitMessage` - `loading/action flags` - `error` - `}` Store actions: - `setGitStatus`, `mergeGitStatusIncremental`, `setGitHistory`, `setGitRemoteState` - `setSelectedDiffFile`, `setCommitMessage` - `setGitPollingState` Tab behavior extensions: - Extend `TabType` with `'git-diff'`. - Use existing transient tab mechanics for single-click diff open. - Add/ensure explicit pinning path for double-click diff tabs (`isTransient: false`). - Include diff tabs in persisted tab state (`getTabState` / `restoreTabState`) so they reopen after restart. - On successful commit action, remove all open `'git-diff'` tabs and clear selected diff state. ## Renderer Components - Update `src/renderer/components/ActivityBar/ActivityBar.tsx` to place Git icon in the bottom rail group above Settings and wire view toggle. - Add Git section to `src/renderer/components/Sidebar/Sidebar.tsx` render switch. - Add dedicated presentational components: - `src/renderer/components/GitSidebar/GitSidebar.tsx` - `src/renderer/components/GitSidebar/OpenChangesList.tsx` - `src/renderer/components/GitSidebar/VersionHistoryList.tsx` - `src/renderer/components/GitSidebar/RepoActions.tsx` - Add diff tab rendering in editor area: - new tab type `'git-diff'` - diff viewer component `GitDiffView`. - single-click handler opens/reuses transient diff tab. - double-click handler opens persistent diff tab. --- ## Polling and Update Strategy ## Status Polling (fast) - Interval: ~2s when Git view visible, ~5–10s when hidden. - Trigger immediate refresh after commit/fetch/pull/push/init. - Use in-flight guard to avoid concurrent status calls. ## Remote Polling (slower) - Run only when remote exists and git is available. - Interval: ~30–60s with backoff on errors. - Use `git fetch --prune` equivalent through `simple-git`. ## Scroll/Render Stability - Keep stable `key` = repo-relative file path. - Preserve existing array reference for unchanged items when merging updates. - Update only changed/added/removed entries in store (incremental diff merge). - Use virtualization (`react-window`) if list grows beyond threshold (e.g., >300 entries). - Preserve scrollTop by storing/restoring container position if full list replacement is unavoidable. ## Repositioning Rules - Do not auto-sort on every tick if sort key not changed. - Insert new items predictably (status-group + path order) to minimize movement. - Never auto-scroll on status update. --- ## History Model (lower half) Each history item should include: - `commitHash` - `author` - `date` - `subject` - `isHead` - `isRemoteHead` (where applicable) - `refs` (branch/tag labels) Remote awareness section: - Show `localBranch -> upstreamBranch` - Show `ahead N / behind M` - Show last fetch timestamp and fetch errors (if any) --- ## Error Handling UX ## Git Missing - Detect once on startup/opening Git view and before actions. - Display clear CTA text: install Git and restart app. ## Not a Repo - Show empty state with `Initialize Git` button. - After successful init, auto-refresh status/history. ## Action Failures - Show concise toast + inline error in Git panel section. - Keep previous state rendered (no hard reset). ## Auth/Conflict Cases - For pull/push conflicts/auth failures, show actionable message; do not hide current status/history. --- ## Test-First Delivery Plan (TDD) Follow strict red-green-refactor per project rules. ## Phase 1: Contracts and engine scaffolding 1. Add failing tests for `GitEngine` availability/repo detection/status parsing. 2. Implement minimal engine methods. 3. Add IPC contract tests for new `git:*` handlers. ## Phase 2: No-repo + init workflow 1. Add renderer tests for no-repo state and `Initialize Git` button. 2. Implement init action and git-missing messaging. 3. Validate with integration-style IPC mock tests. ## Phase 3: Open changes + diff 1. Add tests for open changes list rendering and file selection. 2. Add tests for opening `git-diff` tab and loading diff. 3. Add tests for single-click transient tab reuse and double-click persistent tab behavior. 4. Implement diff component and tab behavior. ## Phase 3b: Diff tab persistence and commit cleanup 1. Add tests to verify `git-diff` tabs are persisted/restored via tab state. 2. Add tests to verify successful commit closes all open `git-diff` tabs. 3. Implement store and commit-flow wiring for cleanup behavior. ## Phase 4: Commit + repo actions 1. Add tests for commit message entry and commit action (`addAll + commit`). 2. Add tests for fetch/pull/push button wiring and disabled/loading states. 3. Implement action handlers with refresh chaining. ## Phase 5: Polling and stability 1. Add tests for polling intervals and in-flight guards (fake timers). 2. Add tests for incremental list updates preserving scroll/identity. 3. Implement merge strategy + optional virtualization threshold. ## Phase 6: Remote tracking in history 1. Add tests for ahead/behind and upstream marker rendering. 2. Implement periodic fetch + remote state projection. 3. Validate remote indicators against mocked git responses. ## Phase 7: Hardening 1. Add tests for error surfaces (git missing, auth fail, merge conflict). 2. Verify all tests pass. 3. Run full build and fix regressions. --- ## Suggested File-Level Work Breakdown Main process: - `src/main/engine/GitEngine.ts` (new) - `src/main/engine/index.ts` (export) - `src/main/ipc/handlers.ts` (new handlers) - `src/main/shared/electronApi.ts` (API types) - `src/main/preload.ts` (bridge methods) Renderer: - `src/renderer/store/appStore.ts` (Git state/actions) - `src/renderer/components/ActivityBar/ActivityBar.tsx` (Git icon entry in bottom rail, above Settings) - `src/renderer/components/Sidebar/Sidebar.tsx` (Git view integration) - `src/renderer/components/GitSidebar/*` (new) - `src/renderer/components/Editor/*` or new `GitDiffView` component Tests: - `tests/engine/GitEngine.test.ts` (new) - `tests/ipc/handlers.test.ts` (extend) - `tests/renderer/components/GitSidebar.test.tsx` (new) - `tests/renderer/store/appStore.git.test.ts` (new) --- ## Milestones and Acceptance Criteria ## Milestone A: Basic Git UX - Git sync icon appears in left sidebar rail bottom section above Settings. - Git sidebar opens with no-repo empty state. - `Initialize Git` works and transitions to repo state. ## Milestone B: Changes + Diff - Open Changes list renders tracked/untracked/modified/deleted files. - Single-click opens/reuses transient diff tab and renders correct patch. - Double-click opens persistent diff tab that remains until user closes it. - Diff tabs persist across app restarts. ## Milestone C: Commit and Repo Actions - Commit message + Commit button performs add-all + commit. - Successful commit closes all open diff tabs automatically. - Fetch/Pull/Push actions execute with visible status feedback. ## Milestone D: Polling + Remote - Status polling updates changes without scroll jump. - Remote fetch polling updates ahead/behind and remote markers. - History clearly shows local/remote relation. ## Milestone E: Quality Gate - All tests pass. - Full build passes. - No console spam, no renderer freeze on large change sets. --- ## Implementation Order Recommendation 1. Contracts + GitEngine + IPC 2. No-repo/init UX 3. Open changes list + diff viewer 4. Commit + fetch/pull/push actions 5. Polling + incremental list merge + scroll stability 6. Remote-aware history refinement and hardening This order minimizes risk and delivers user-visible value early while preserving room for performance optimization in later iterations.