Repository files navigation

Git Workspace Manager

A minimalist desktop app for managing multiple Git repositories across branches. Switch an entire group of repos to the right branches and pull updates with one click.

Built with Electron and vanilla HTML/CSS/JS. No frameworks, no build tools, no complexity.

Preview

Screenshot 2026-03-24 172439image

Table of Contents


Installation

Option A: Portable Executable (recommended for daily use)

  1. Download Git Workspace Manager 1.0.0.exe from the dist/ folder.
  2. Place it anywhere (Desktop, USB drive, etc.).
  3. Double-click to run. No installation needed.

Prerequisite:Git must be installed and available on your system PATH.

Option B: Run from Source (for development)

Prerequisites:Node.js (v18+) and Git.

cd git-workspace
npm install
npm start

Getting Started

1. Register your repositories

Before you can create workspaces, the app needs to know where your repos live on disk.

  • Click Manage Registry in the sidebar.
  • Click Add Repository to pick a single repo folder, or Scan Folder to automatically find all repos inside a parent directory (e.g. C:\Repositories).
  • The app reads each repo's git remote origin URL and extracts an identifier like myorg/my-repo.

2. Create a workspace

A workspace is a named group of repositories, each with an optional target branch.

  • Click + New Workspace in the sidebar.
  • Give it a name (e.g. "Development", "Staging").
  • Check the repos you want to include.
  • For each repo, type a branch name (e.g. development) or leave blank to stay on whatever branch it's currently on.
  • Click Save.

3. Sync

  • Select a workspace from the sidebar.
  • Click Sync All.
  • The app will check each repo for uncommitted changes. If any are dirty, you'll see a warning and can choose to skip them.
  • For each clean repo, it will: fetch all remotes, checkout the target branch (if specified), and pull latest changes.
  • Progress and results are shown per-repo in the table.

Features

FeatureDescription
Workspace managementCreate, edit, and delete named groups of repos with target branches.
Sync AllFetch + checkout + pull for every repo in a workspace, with per-repo progress.
Dirty repo warningsRepos with uncommitted changes are flagged and skipped during sync.
Repository registryCentral list mapping org/repo identifiers to local paths.
Scan FolderBatch-add all repos from a parent directory.
Import / ExportMove workspace configs between machines without sharing local paths.
Status indicatorsGreen = clean, Red = dirty, Yellow = error/missing.

Import / Export

Exporting a workspace

  1. Select a workspace and click Export.
  2. Choose where to save the .json file.
  3. The exported file contains only repo identifiers (org/repo) and branch names. No local paths are included.

Example export file:

{
"name": "Development",
"exportedAt": "2026-03-18T12:00:00Z",
"repos": [
{ "id": "myorg/api-server", "branch": "development" },
{ "id": "myorg/web-client", "branch": "development" },
{ "id": "myorg/shared-lib", "branch": null }
]
}

Importing a workspace

  1. Click Import Workspace in the sidebar and select a .json file.
  2. The app checks that every repo in the file exists in your local registry.
  3. If all repos are found: The workspace is created.
  4. If any repos are missing: The import is blocked and you'll see a list of missing repos. Add them to your registry first, then try again.

This lets you share workspace configs between machines where the same repos may live at different paths.


Git Safety

This app is designed to be accident-proof. It only runs safe, read-or-pull git operations:

AllowedNOT allowed (not in the app at all)
git fetch --allgit merge
git checkout <branch>git rebase
git pullgit reset
git status --porcelaingit push
git rev-parse --abbrev-ref HEADgit clean
git remote get-url origingit stash
git branch -aAny --force flag

All git commands are executed via Node.js execFile with arguments passed as arrays (not shell strings), preventing command injection. There is no generic "run any git command" function.


Developer Guide

Project structure

git-workspace/
package.json # npm config, Electron version, build settings
main.js # Electron main process
preload.js # Context bridge (main <-> renderer)
git.js # Git command whitelist
index.html # UI markup
styles.css # Styling
renderer.js # UI logic
dist/ # Built executables (after npm run build)

How the code is organized

The app follows Electron's standard architecture with three layers:

  1. Main process (main.js) - Runs in Node.js. Handles file I/O, config persistence, native dialogs, and git operations. Exposes functionality to the renderer via IPC handlers.

  2. Preload (preload.js) - The bridge. Uses Electron's contextBridge to expose a safe window.api object to the renderer. The renderer cannot access Node.js directly.

  3. Renderer (renderer.js + index.html + styles.css) - Runs in the browser window. All UI logic: DOM manipulation, event handlers, view switching. Calls window.api.* methods to talk to the main process.

Running in development

npm start

This launches Electron and loads the app. Changes to renderer.js, index.html, or styles.css take effect after reloading the window (Ctrl+R). Changes to main.js, preload.js, or git.js require restarting the app.

Building the executable

npm run build

This uses electron-builder to create a portable .exe in the dist/ folder. The executable bundles the Electron runtime and all source files - no Node.js installation needed on the target machine.

Adding a new IPC handler

To add new functionality accessible from the UI:

  1. main.js - Add a handler: ipcMain.handle('my-action', async (_e, arg) => { ... })
  2. preload.js - Expose it: add myAction: (arg) => ipcRenderer.invoke('my-action', arg) to the contextBridge object
  3. renderer.js - Call it: const result = await window.api.myAction(arg)

File Reference

git.js - Git safety boundary

The only file that runs git commands. Contains a private run() function that calls execFile('git', args, { cwd }) and 7 public functions (gitFetch, gitCheckout, gitPull, gitStatus, gitCurrentBranch, gitRemoteUrl, gitBranchList) plus a parseRepoId helper. To audit git safety, you only need to read this one file.

main.js - Electron main process

Handles:

  • Config management - reads/writes config.json from %APPDATA%/git-workspace/. Config path is lazily initialized after Electron is ready.
  • IPC handlers - get-config, save-config, pick-repo-folder, scan-folder, repo-status, repo-branches, sync-repo, export-workspace, import-workspace, check-git.
  • Window creation - single window, no menu bar, context isolation enabled.

preload.js - Context bridge

Maps each IPC channel to a method on window.api. This is the complete list of what the renderer can do - nothing more.

index.html - UI structure

Single-page app with:

  • Sidebar - workspace list, new workspace button, registry and import buttons.
  • Three views - welcome (empty state), workspace (repo table + sync), registry (repo list + add/scan).
  • Four modals - workspace create/edit, dirty repo warning, import result, git-not-found overlay.

styles.css - Styling

Dark theme with Catppuccin-inspired colors. Defines CSS variables at :root for easy theming. Covers layout, sidebar, tables, buttons, modals, status indicators, and scrollbars.

renderer.js - UI logic

All DOM manipulation and event handling. Key functions:

  • init() - checks git availability, loads config, renders sidebar.
  • renderWorkspace() / fetchRepoStatus() - builds the repo table and fetches live status.
  • syncAll() - orchestrates the sync: checks dirty repos, shows warning, syncs sequentially.
  • openWorkspaceModal() - handles create/edit with registry-based repo picker.
  • importWorkspace() / exportWorkspace() - portable workspace transfer.
  • renderRegistry() / addRepoToRegistry() / scanFolderToRegistry() - registry management.

Config File

Location: %APPDATA%/git-workspace/config.json

{
"registry": [
{
"id": "myorg/my-repo",
"localPath": "C:\\Repositories\\my-repo"
}
],
"workspaces": [
{
"id": "ws-1710000000000",
"name": "Development",
"repos": [
{ "registryId": "myorg/my-repo", "branch": "development" },
{ "registryId": "myorg/other-repo", "branch": null }
]
}
]
}
  • registry - maps org/repo (from git remote URL) to local filesystem path.
  • workspaces - each has a unique ID, name, and list of repos referencing the registry.
  • branch: null means "stay on whatever branch is currently checked out."

If this file becomes corrupt, the app backs it up as config.json.backup and creates a fresh empty config.


Troubleshooting

ProblemSolution
App shows "Git Not Found"Install Git and make sure git --version works in your terminal.
Repo shows yellow dot in registryThe local path no longer exists or is not a git repo. Update or remove it.
Sync skips a repo as "dirty"That repo has uncommitted changes. Commit or stash them first.
Checkout fails during syncThe target branch may not exist. Check the branch name in workspace settings.
Config lost between restartsMake sure you're on version 1.0.0+. Earlier versions had a config path bug.
Import fails with missing reposAdd the listed repos to your registry first (Add Repository or Scan Folder).

About

Git Workspace Manager - manage multiple repos across branches

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Git Workspace Manager

A minimalist desktop app for managing multiple Git repositories across branches. Switch an entire group of repos to the right branches and pull updates with one click.

Built with Electron and vanilla HTML/CSS/JS. No frameworks, no build tools, no complexity.

Preview

Screenshot 2026-03-24 172439image

Table of Contents


Installation

Option A: Portable Executable (recommended for daily use)

  1. Download Git Workspace Manager 1.0.0.exe from the dist/ folder.
  2. Place it anywhere (Desktop, USB drive, etc.).
  3. Double-click to run. No installation needed.

Prerequisite:Git must be installed and available on your system PATH.

Option B: Run from Source (for development)

Prerequisites:Node.js (v18+) and Git.

cd git-workspace
npm install
npm start

Getting Started

1. Register your repositories

Before you can create workspaces, the app needs to know where your repos live on disk.

  • Click Manage Registry in the sidebar.
  • Click Add Repository to pick a single repo folder, or Scan Folder to automatically find all repos inside a parent directory (e.g. C:\Repositories).
  • The app reads each repo's git remote origin URL and extracts an identifier like myorg/my-repo.

2. Create a workspace

A workspace is a named group of repositories, each with an optional target branch.

  • Click + New Workspace in the sidebar.
  • Give it a name (e.g. "Development", "Staging").
  • Check the repos you want to include.
  • For each repo, type a branch name (e.g. development) or leave blank to stay on whatever branch it's currently on.
  • Click Save.

3. Sync

  • Select a workspace from the sidebar.
  • Click Sync All.
  • The app will check each repo for uncommitted changes. If any are dirty, you'll see a warning and can choose to skip them.
  • For each clean repo, it will: fetch all remotes, checkout the target branch (if specified), and pull latest changes.
  • Progress and results are shown per-repo in the table.

Features

FeatureDescription
Workspace managementCreate, edit, and delete named groups of repos with target branches.
Sync AllFetch + checkout + pull for every repo in a workspace, with per-repo progress.
Dirty repo warningsRepos with uncommitted changes are flagged and skipped during sync.
Repository registryCentral list mapping org/repo identifiers to local paths.
Scan FolderBatch-add all repos from a parent directory.
Import / ExportMove workspace configs between machines without sharing local paths.
Status indicatorsGreen = clean, Red = dirty, Yellow = error/missing.

Import / Export

Exporting a workspace

  1. Select a workspace and click Export.
  2. Choose where to save the .json file.
  3. The exported file contains only repo identifiers (org/repo) and branch names. No local paths are included.

Example export file:

{
"name": "Development",
"exportedAt": "2026-03-18T12:00:00Z",
"repos": [
{ "id": "myorg/api-server", "branch": "development" },
{ "id": "myorg/web-client", "branch": "development" },
{ "id": "myorg/shared-lib", "branch": null }
]
}

Importing a workspace

  1. Click Import Workspace in the sidebar and select a .json file.
  2. The app checks that every repo in the file exists in your local registry.
  3. If all repos are found: The workspace is created.
  4. If any repos are missing: The import is blocked and you'll see a list of missing repos. Add them to your registry first, then try again.

This lets you share workspace configs between machines where the same repos may live at different paths.


Git Safety

This app is designed to be accident-proof. It only runs safe, read-or-pull git operations:

AllowedNOT allowed (not in the app at all)
git fetch --allgit merge
git checkout <branch>git rebase
git pullgit reset
git status --porcelaingit push
git rev-parse --abbrev-ref HEADgit clean
git remote get-url origingit stash
git branch -aAny --force flag

All git commands are executed via Node.js execFile with arguments passed as arrays (not shell strings), preventing command injection. There is no generic "run any git command" function.


Developer Guide

Project structure

git-workspace/
package.json # npm config, Electron version, build settings
main.js # Electron main process
preload.js # Context bridge (main <-> renderer)
git.js # Git command whitelist
index.html # UI markup
styles.css # Styling
renderer.js # UI logic
dist/ # Built executables (after npm run build)

How the code is organized

The app follows Electron's standard architecture with three layers:

  1. Main process (main.js) - Runs in Node.js. Handles file I/O, config persistence, native dialogs, and git operations. Exposes functionality to the renderer via IPC handlers.

  2. Preload (preload.js) - The bridge. Uses Electron's contextBridge to expose a safe window.api object to the renderer. The renderer cannot access Node.js directly.

  3. Renderer (renderer.js + index.html + styles.css) - Runs in the browser window. All UI logic: DOM manipulation, event handlers, view switching. Calls window.api.* methods to talk to the main process.

Running in development

npm start

This launches Electron and loads the app. Changes to renderer.js, index.html, or styles.css take effect after reloading the window (Ctrl+R). Changes to main.js, preload.js, or git.js require restarting the app.

Building the executable

npm run build

This uses electron-builder to create a portable .exe in the dist/ folder. The executable bundles the Electron runtime and all source files - no Node.js installation needed on the target machine.

Adding a new IPC handler

To add new functionality accessible from the UI:

  1. main.js - Add a handler: ipcMain.handle('my-action', async (_e, arg) => { ... })
  2. preload.js - Expose it: add myAction: (arg) => ipcRenderer.invoke('my-action', arg) to the contextBridge object
  3. renderer.js - Call it: const result = await window.api.myAction(arg)

File Reference

git.js - Git safety boundary

The only file that runs git commands. Contains a private run() function that calls execFile('git', args, { cwd }) and 7 public functions (gitFetch, gitCheckout, gitPull, gitStatus, gitCurrentBranch, gitRemoteUrl, gitBranchList) plus a parseRepoId helper. To audit git safety, you only need to read this one file.

main.js - Electron main process

Handles:

  • Config management - reads/writes config.json from %APPDATA%/git-workspace/. Config path is lazily initialized after Electron is ready.
  • IPC handlers - get-config, save-config, pick-repo-folder, scan-folder, repo-status, repo-branches, sync-repo, export-workspace, import-workspace, check-git.
  • Window creation - single window, no menu bar, context isolation enabled.

preload.js - Context bridge

Maps each IPC channel to a method on window.api. This is the complete list of what the renderer can do - nothing more.

index.html - UI structure

Single-page app with:

  • Sidebar - workspace list, new workspace button, registry and import buttons.
  • Three views - welcome (empty state), workspace (repo table + sync), registry (repo list + add/scan).
  • Four modals - workspace create/edit, dirty repo warning, import result, git-not-found overlay.

styles.css - Styling

Dark theme with Catppuccin-inspired colors. Defines CSS variables at :root for easy theming. Covers layout, sidebar, tables, buttons, modals, status indicators, and scrollbars.

renderer.js - UI logic

All DOM manipulation and event handling. Key functions:

  • init() - checks git availability, loads config, renders sidebar.
  • renderWorkspace() / fetchRepoStatus() - builds the repo table and fetches live status.
  • syncAll() - orchestrates the sync: checks dirty repos, shows warning, syncs sequentially.
  • openWorkspaceModal() - handles create/edit with registry-based repo picker.
  • importWorkspace() / exportWorkspace() - portable workspace transfer.
  • renderRegistry() / addRepoToRegistry() / scanFolderToRegistry() - registry management.

Config File

Location: %APPDATA%/git-workspace/config.json

{
"registry": [
{
"id": "myorg/my-repo",
"localPath": "C:\\Repositories\\my-repo"
}
],
"workspaces": [
{
"id": "ws-1710000000000",
"name": "Development",
"repos": [
{ "registryId": "myorg/my-repo", "branch": "development" },
{ "registryId": "myorg/other-repo", "branch": null }
]
}
]
}
  • registry - maps org/repo (from git remote URL) to local filesystem path.
  • workspaces - each has a unique ID, name, and list of repos referencing the registry.
  • branch: null means "stay on whatever branch is currently checked out."

If this file becomes corrupt, the app backs it up as config.json.backup and creates a fresh empty config.


Troubleshooting

ProblemSolution
App shows "Git Not Found"Install Git and make sure git --version works in your terminal.
Repo shows yellow dot in registryThe local path no longer exists or is not a git repo. Update or remove it.
Sync skips a repo as "dirty"That repo has uncommitted changes. Commit or stash them first.
Checkout fails during syncThe target branch may not exist. Check the branch name in workspace settings.
Config lost between restartsMake sure you're on version 1.0.0+. Earlier versions had a config path bug.
Import fails with missing reposAdd the listed repos to your registry first (Add Repository or Scan Folder).

About

Git Workspace Manager - manage multiple repos across branches

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Git Workspace Manager

A minimalist desktop app for managing multiple Git repositories across branches. Switch an entire group of repos to the right branches and pull updates with one click.

Built with Electron and vanilla HTML/CSS/JS. No frameworks, no build tools, no complexity.

Preview

Screenshot 2026-03-24 172439image

Table of Contents


Installation

Option A: Portable Executable (recommended for daily use)

  1. Download Git Workspace Manager 1.0.0.exe from the dist/ folder.
  2. Place it anywhere (Desktop, USB drive, etc.).
  3. Double-click to run. No installation needed.

Prerequisite:Git must be installed and available on your system PATH.

Option B: Run from Source (for development)

Prerequisites:Node.js (v18+) and Git.

cd git-workspace
npm install
npm start

Getting Started

1. Register your repositories

Before you can create workspaces, the app needs to know where your repos live on disk.

  • Click Manage Registry in the sidebar.
  • Click Add Repository to pick a single repo folder, or Scan Folder to automatically find all repos inside a parent directory (e.g. C:\Repositories).
  • The app reads each repo's git remote origin URL and extracts an identifier like myorg/my-repo.

2. Create a workspace

A workspace is a named group of repositories, each with an optional target branch.

  • Click + New Workspace in the sidebar.
  • Give it a name (e.g. "Development", "Staging").
  • Check the repos you want to include.
  • For each repo, type a branch name (e.g. development) or leave blank to stay on whatever branch it's currently on.
  • Click Save.

3. Sync

  • Select a workspace from the sidebar.
  • Click Sync All.
  • The app will check each repo for uncommitted changes. If any are dirty, you'll see a warning and can choose to skip them.
  • For each clean repo, it will: fetch all remotes, checkout the target branch (if specified), and pull latest changes.
  • Progress and results are shown per-repo in the table.

Features

FeatureDescription
Workspace managementCreate, edit, and delete named groups of repos with target branches.
Sync AllFetch + checkout + pull for every repo in a workspace, with per-repo progress.
Dirty repo warningsRepos with uncommitted changes are flagged and skipped during sync.
Repository registryCentral list mapping org/repo identifiers to local paths.
Scan FolderBatch-add all repos from a parent directory.
Import / ExportMove workspace configs between machines without sharing local paths.
Status indicatorsGreen = clean, Red = dirty, Yellow = error/missing.

Import / Export

Exporting a workspace

  1. Select a workspace and click Export.
  2. Choose where to save the .json file.
  3. The exported file contains only repo identifiers (org/repo) and branch names. No local paths are included.

Example export file:

{
"name": "Development",
"exportedAt": "2026-03-18T12:00:00Z",
"repos": [
{ "id": "myorg/api-server", "branch": "development" },
{ "id": "myorg/web-client", "branch": "development" },
{ "id": "myorg/shared-lib", "branch": null }
]
}

Importing a workspace

  1. Click Import Workspace in the sidebar and select a .json file.
  2. The app checks that every repo in the file exists in your local registry.
  3. If all repos are found: The workspace is created.
  4. If any repos are missing: The import is blocked and you'll see a list of missing repos. Add them to your registry first, then try again.

This lets you share workspace configs between machines where the same repos may live at different paths.


Git Safety

This app is designed to be accident-proof. It only runs safe, read-or-pull git operations:

AllowedNOT allowed (not in the app at all)
git fetch --allgit merge
git checkout <branch>git rebase
git pullgit reset
git status --porcelaingit push
git rev-parse --abbrev-ref HEADgit clean
git remote get-url origingit stash
git branch -aAny --force flag

All git commands are executed via Node.js execFile with arguments passed as arrays (not shell strings), preventing command injection. There is no generic "run any git command" function.


Developer Guide

Project structure

git-workspace/
package.json # npm config, Electron version, build settings
main.js # Electron main process
preload.js # Context bridge (main <-> renderer)
git.js # Git command whitelist
index.html # UI markup
styles.css # Styling
renderer.js # UI logic
dist/ # Built executables (after npm run build)

How the code is organized

The app follows Electron's standard architecture with three layers:

  1. Main process (main.js) - Runs in Node.js. Handles file I/O, config persistence, native dialogs, and git operations. Exposes functionality to the renderer via IPC handlers.

  2. Preload (preload.js) - The bridge. Uses Electron's contextBridge to expose a safe window.api object to the renderer. The renderer cannot access Node.js directly.

  3. Renderer (renderer.js + index.html + styles.css) - Runs in the browser window. All UI logic: DOM manipulation, event handlers, view switching. Calls window.api.* methods to talk to the main process.

Running in development

npm start

This launches Electron and loads the app. Changes to renderer.js, index.html, or styles.css take effect after reloading the window (Ctrl+R). Changes to main.js, preload.js, or git.js require restarting the app.

Building the executable

npm run build

This uses electron-builder to create a portable .exe in the dist/ folder. The executable bundles the Electron runtime and all source files - no Node.js installation needed on the target machine.

Adding a new IPC handler

To add new functionality accessible from the UI:

  1. main.js - Add a handler: ipcMain.handle('my-action', async (_e, arg) => { ... })
  2. preload.js - Expose it: add myAction: (arg) => ipcRenderer.invoke('my-action', arg) to the contextBridge object
  3. renderer.js - Call it: const result = await window.api.myAction(arg)

File Reference

git.js - Git safety boundary

The only file that runs git commands. Contains a private run() function that calls execFile('git', args, { cwd }) and 7 public functions (gitFetch, gitCheckout, gitPull, gitStatus, gitCurrentBranch, gitRemoteUrl, gitBranchList) plus a parseRepoId helper. To audit git safety, you only need to read this one file.

main.js - Electron main process

Handles:

  • Config management - reads/writes config.json from %APPDATA%/git-workspace/. Config path is lazily initialized after Electron is ready.
  • IPC handlers - get-config, save-config, pick-repo-folder, scan-folder, repo-status, repo-branches, sync-repo, export-workspace, import-workspace, check-git.
  • Window creation - single window, no menu bar, context isolation enabled.

preload.js - Context bridge

Maps each IPC channel to a method on window.api. This is the complete list of what the renderer can do - nothing more.

index.html - UI structure

Single-page app with:

  • Sidebar - workspace list, new workspace button, registry and import buttons.
  • Three views - welcome (empty state), workspace (repo table + sync), registry (repo list + add/scan).
  • Four modals - workspace create/edit, dirty repo warning, import result, git-not-found overlay.

styles.css - Styling

Dark theme with Catppuccin-inspired colors. Defines CSS variables at :root for easy theming. Covers layout, sidebar, tables, buttons, modals, status indicators, and scrollbars.

renderer.js - UI logic

All DOM manipulation and event handling. Key functions:

  • init() - checks git availability, loads config, renders sidebar.
  • renderWorkspace() / fetchRepoStatus() - builds the repo table and fetches live status.
  • syncAll() - orchestrates the sync: checks dirty repos, shows warning, syncs sequentially.
  • openWorkspaceModal() - handles create/edit with registry-based repo picker.
  • importWorkspace() / exportWorkspace() - portable workspace transfer.
  • renderRegistry() / addRepoToRegistry() / scanFolderToRegistry() - registry management.

Config File

Location: %APPDATA%/git-workspace/config.json

{
"registry": [
{
"id": "myorg/my-repo",
"localPath": "C:\\Repositories\\my-repo"
}
],
"workspaces": [
{
"id": "ws-1710000000000",
"name": "Development",
"repos": [
{ "registryId": "myorg/my-repo", "branch": "development" },
{ "registryId": "myorg/other-repo", "branch": null }
]
}
]
}
  • registry - maps org/repo (from git remote URL) to local filesystem path.
  • workspaces - each has a unique ID, name, and list of repos referencing the registry.
  • branch: null means "stay on whatever branch is currently checked out."

If this file becomes corrupt, the app backs it up as config.json.backup and creates a fresh empty config.


Troubleshooting

ProblemSolution
App shows "Git Not Found"Install Git and make sure git --version works in your terminal.
Repo shows yellow dot in registryThe local path no longer exists or is not a git repo. Update or remove it.
Sync skips a repo as "dirty"That repo has uncommitted changes. Commit or stash them first.
Checkout fails during syncThe target branch may not exist. Check the branch name in workspace settings.
Config lost between restartsMake sure you're on version 1.0.0+. Earlier versions had a config path bug.
Import fails with missing reposAdd the listed repos to your registry first (Add Repository or Scan Folder).

About

Git Workspace Manager - manage multiple repos across branches

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Git Workspace Manager

A minimalist desktop app for managing multiple Git repositories across branches. Switch an entire group of repos to the right branches and pull updates with one click.

Built with Electron and vanilla HTML/CSS/JS. No frameworks, no build tools, no complexity.

Preview

Screenshot 2026-03-24 172439image

Table of Contents


Installation

Option A: Portable Executable (recommended for daily use)

  1. Download Git Workspace Manager 1.0.0.exe from the dist/ folder.
  2. Place it anywhere (Desktop, USB drive, etc.).
  3. Double-click to run. No installation needed.

Prerequisite:Git must be installed and available on your system PATH.

Option B: Run from Source (for development)

Prerequisites:Node.js (v18+) and Git.

cd git-workspace
npm install
npm start

Getting Started

1. Register your repositories

Before you can create workspaces, the app needs to know where your repos live on disk.

  • Click Manage Registry in the sidebar.
  • Click Add Repository to pick a single repo folder, or Scan Folder to automatically find all repos inside a parent directory (e.g. C:\Repositories).
  • The app reads each repo's git remote origin URL and extracts an identifier like myorg/my-repo.

2. Create a workspace

A workspace is a named group of repositories, each with an optional target branch.

  • Click + New Workspace in the sidebar.
  • Give it a name (e.g. "Development", "Staging").
  • Check the repos you want to include.
  • For each repo, type a branch name (e.g. development) or leave blank to stay on whatever branch it's currently on.
  • Click Save.

3. Sync

  • Select a workspace from the sidebar.
  • Click Sync All.
  • The app will check each repo for uncommitted changes. If any are dirty, you'll see a warning and can choose to skip them.
  • For each clean repo, it will: fetch all remotes, checkout the target branch (if specified), and pull latest changes.
  • Progress and results are shown per-repo in the table.

Features

FeatureDescription
Workspace managementCreate, edit, and delete named groups of repos with target branches.
Sync AllFetch + checkout + pull for every repo in a workspace, with per-repo progress.
Dirty repo warningsRepos with uncommitted changes are flagged and skipped during sync.
Repository registryCentral list mapping org/repo identifiers to local paths.
Scan FolderBatch-add all repos from a parent directory.
Import / ExportMove workspace configs between machines without sharing local paths.
Status indicatorsGreen = clean, Red = dirty, Yellow = error/missing.

Import / Export

Exporting a workspace

  1. Select a workspace and click Export.
  2. Choose where to save the .json file.
  3. The exported file contains only repo identifiers (org/repo) and branch names. No local paths are included.

Example export file:

{
"name": "Development",
"exportedAt": "2026-03-18T12:00:00Z",
"repos": [
{ "id": "myorg/api-server", "branch": "development" },
{ "id": "myorg/web-client", "branch": "development" },
{ "id": "myorg/shared-lib", "branch": null }
]
}

Importing a workspace

  1. Click Import Workspace in the sidebar and select a .json file.
  2. The app checks that every repo in the file exists in your local registry.
  3. If all repos are found: The workspace is created.
  4. If any repos are missing: The import is blocked and you'll see a list of missing repos. Add them to your registry first, then try again.

This lets you share workspace configs between machines where the same repos may live at different paths.


Git Safety

This app is designed to be accident-proof. It only runs safe, read-or-pull git operations:

AllowedNOT allowed (not in the app at all)
git fetch --allgit merge
git checkout <branch>git rebase
git pullgit reset
git status --porcelaingit push
git rev-parse --abbrev-ref HEADgit clean
git remote get-url origingit stash
git branch -aAny --force flag

All git commands are executed via Node.js execFile with arguments passed as arrays (not shell strings), preventing command injection. There is no generic "run any git command" function.


Developer Guide

Project structure

git-workspace/
package.json # npm config, Electron version, build settings
main.js # Electron main process
preload.js # Context bridge (main <-> renderer)
git.js # Git command whitelist
index.html # UI markup
styles.css # Styling
renderer.js # UI logic
dist/ # Built executables (after npm run build)

How the code is organized

The app follows Electron's standard architecture with three layers:

  1. Main process (main.js) - Runs in Node.js. Handles file I/O, config persistence, native dialogs, and git operations. Exposes functionality to the renderer via IPC handlers.

  2. Preload (preload.js) - The bridge. Uses Electron's contextBridge to expose a safe window.api object to the renderer. The renderer cannot access Node.js directly.

  3. Renderer (renderer.js + index.html + styles.css) - Runs in the browser window. All UI logic: DOM manipulation, event handlers, view switching. Calls window.api.* methods to talk to the main process.

Running in development

npm start

This launches Electron and loads the app. Changes to renderer.js, index.html, or styles.css take effect after reloading the window (Ctrl+R). Changes to main.js, preload.js, or git.js require restarting the app.

Building the executable

npm run build

This uses electron-builder to create a portable .exe in the dist/ folder. The executable bundles the Electron runtime and all source files - no Node.js installation needed on the target machine.

Adding a new IPC handler

To add new functionality accessible from the UI:

  1. main.js - Add a handler: ipcMain.handle('my-action', async (_e, arg) => { ... })
  2. preload.js - Expose it: add myAction: (arg) => ipcRenderer.invoke('my-action', arg) to the contextBridge object
  3. renderer.js - Call it: const result = await window.api.myAction(arg)

File Reference

git.js - Git safety boundary

The only file that runs git commands. Contains a private run() function that calls execFile('git', args, { cwd }) and 7 public functions (gitFetch, gitCheckout, gitPull, gitStatus, gitCurrentBranch, gitRemoteUrl, gitBranchList) plus a parseRepoId helper. To audit git safety, you only need to read this one file.

main.js - Electron main process

Handles:

  • Config management - reads/writes config.json from %APPDATA%/git-workspace/. Config path is lazily initialized after Electron is ready.
  • IPC handlers - get-config, save-config, pick-repo-folder, scan-folder, repo-status, repo-branches, sync-repo, export-workspace, import-workspace, check-git.
  • Window creation - single window, no menu bar, context isolation enabled.

preload.js - Context bridge

Maps each IPC channel to a method on window.api. This is the complete list of what the renderer can do - nothing more.

index.html - UI structure

Single-page app with:

  • Sidebar - workspace list, new workspace button, registry and import buttons.
  • Three views - welcome (empty state), workspace (repo table + sync), registry (repo list + add/scan).
  • Four modals - workspace create/edit, dirty repo warning, import result, git-not-found overlay.

styles.css - Styling

Dark theme with Catppuccin-inspired colors. Defines CSS variables at :root for easy theming. Covers layout, sidebar, tables, buttons, modals, status indicators, and scrollbars.

renderer.js - UI logic

All DOM manipulation and event handling. Key functions:

  • init() - checks git availability, loads config, renders sidebar.
  • renderWorkspace() / fetchRepoStatus() - builds the repo table and fetches live status.
  • syncAll() - orchestrates the sync: checks dirty repos, shows warning, syncs sequentially.
  • openWorkspaceModal() - handles create/edit with registry-based repo picker.
  • importWorkspace() / exportWorkspace() - portable workspace transfer.
  • renderRegistry() / addRepoToRegistry() / scanFolderToRegistry() - registry management.

Config File

Location: %APPDATA%/git-workspace/config.json

{
"registry": [
{
"id": "myorg/my-repo",
"localPath": "C:\\Repositories\\my-repo"
}
],
"workspaces": [
{
"id": "ws-1710000000000",
"name": "Development",
"repos": [
{ "registryId": "myorg/my-repo", "branch": "development" },
{ "registryId": "myorg/other-repo", "branch": null }
]
}
]
}
  • registry - maps org/repo (from git remote URL) to local filesystem path.
  • workspaces - each has a unique ID, name, and list of repos referencing the registry.
  • branch: null means "stay on whatever branch is currently checked out."

If this file becomes corrupt, the app backs it up as config.json.backup and creates a fresh empty config.


Troubleshooting

ProblemSolution
App shows "Git Not Found"Install Git and make sure git --version works in your terminal.
Repo shows yellow dot in registryThe local path no longer exists or is not a git repo. Update or remove it.
Sync skips a repo as "dirty"That repo has uncommitted changes. Commit or stash them first.
Checkout fails during syncThe target branch may not exist. Check the branch name in workspace settings.
Config lost between restartsMake sure you're on version 1.0.0+. Earlier versions had a config path bug.
Import fails with missing reposAdd the listed repos to your registry first (Add Repository or Scan Folder).

About

Git Workspace Manager - manage multiple repos across branches

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Git Workspace Manager

A minimalist desktop app for managing multiple Git repositories across branches. Switch an entire group of repos to the right branches and pull updates with one click.

Built with Electron and vanilla HTML/CSS/JS. No frameworks, no build tools, no complexity.

Preview

Screenshot 2026-03-24 172439image

Table of Contents


Installation

Option A: Portable Executable (recommended for daily use)

  1. Download Git Workspace Manager 1.0.0.exe from the dist/ folder.
  2. Place it anywhere (Desktop, USB drive, etc.).
  3. Double-click to run. No installation needed.

Prerequisite:Git must be installed and available on your system PATH.

Option B: Run from Source (for development)

Prerequisites:Node.js (v18+) and Git.

cd git-workspace
npm install
npm start

Getting Started

1. Register your repositories

Before you can create workspaces, the app needs to know where your repos live on disk.

  • Click Manage Registry in the sidebar.
  • Click Add Repository to pick a single repo folder, or Scan Folder to automatically find all repos inside a parent directory (e.g. C:\Repositories).
  • The app reads each repo's git remote origin URL and extracts an identifier like myorg/my-repo.

2. Create a workspace

A workspace is a named group of repositories, each with an optional target branch.

  • Click + New Workspace in the sidebar.
  • Give it a name (e.g. "Development", "Staging").
  • Check the repos you want to include.
  • For each repo, type a branch name (e.g. development) or leave blank to stay on whatever branch it's currently on.
  • Click Save.

3. Sync

  • Select a workspace from the sidebar.
  • Click Sync All.
  • The app will check each repo for uncommitted changes. If any are dirty, you'll see a warning and can choose to skip them.
  • For each clean repo, it will: fetch all remotes, checkout the target branch (if specified), and pull latest changes.
  • Progress and results are shown per-repo in the table.

Features

FeatureDescription
Workspace managementCreate, edit, and delete named groups of repos with target branches.
Sync AllFetch + checkout + pull for every repo in a workspace, with per-repo progress.
Dirty repo warningsRepos with uncommitted changes are flagged and skipped during sync.
Repository registryCentral list mapping org/repo identifiers to local paths.
Scan FolderBatch-add all repos from a parent directory.
Import / ExportMove workspace configs between machines without sharing local paths.
Status indicatorsGreen = clean, Red = dirty, Yellow = error/missing.

Import / Export

Exporting a workspace

  1. Select a workspace and click Export.
  2. Choose where to save the .json file.
  3. The exported file contains only repo identifiers (org/repo) and branch names. No local paths are included.

Example export file:

{
"name": "Development",
"exportedAt": "2026-03-18T12:00:00Z",
"repos": [
{ "id": "myorg/api-server", "branch": "development" },
{ "id": "myorg/web-client", "branch": "development" },
{ "id": "myorg/shared-lib", "branch": null }
]
}

Importing a workspace

  1. Click Import Workspace in the sidebar and select a .json file.
  2. The app checks that every repo in the file exists in your local registry.
  3. If all repos are found: The workspace is created.
  4. If any repos are missing: The import is blocked and you'll see a list of missing repos. Add them to your registry first, then try again.

This lets you share workspace configs between machines where the same repos may live at different paths.


Git Safety

This app is designed to be accident-proof. It only runs safe, read-or-pull git operations:

AllowedNOT allowed (not in the app at all)
git fetch --allgit merge
git checkout <branch>git rebase
git pullgit reset
git status --porcelaingit push
git rev-parse --abbrev-ref HEADgit clean
git remote get-url origingit stash
git branch -aAny --force flag

All git commands are executed via Node.js execFile with arguments passed as arrays (not shell strings), preventing command injection. There is no generic "run any git command" function.


Developer Guide

Project structure

git-workspace/
package.json # npm config, Electron version, build settings
main.js # Electron main process
preload.js # Context bridge (main <-> renderer)
git.js # Git command whitelist
index.html # UI markup
styles.css # Styling
renderer.js # UI logic
dist/ # Built executables (after npm run build)

How the code is organized

The app follows Electron's standard architecture with three layers:

  1. Main process (main.js) - Runs in Node.js. Handles file I/O, config persistence, native dialogs, and git operations. Exposes functionality to the renderer via IPC handlers.

  2. Preload (preload.js) - The bridge. Uses Electron's contextBridge to expose a safe window.api object to the renderer. The renderer cannot access Node.js directly.

  3. Renderer (renderer.js + index.html + styles.css) - Runs in the browser window. All UI logic: DOM manipulation, event handlers, view switching. Calls window.api.* methods to talk to the main process.

Running in development

npm start

This launches Electron and loads the app. Changes to renderer.js, index.html, or styles.css take effect after reloading the window (Ctrl+R). Changes to main.js, preload.js, or git.js require restarting the app.

Building the executable

npm run build

This uses electron-builder to create a portable .exe in the dist/ folder. The executable bundles the Electron runtime and all source files - no Node.js installation needed on the target machine.

Adding a new IPC handler

To add new functionality accessible from the UI:

  1. main.js - Add a handler: ipcMain.handle('my-action', async (_e, arg) => { ... })
  2. preload.js - Expose it: add myAction: (arg) => ipcRenderer.invoke('my-action', arg) to the contextBridge object
  3. renderer.js - Call it: const result = await window.api.myAction(arg)

File Reference

git.js - Git safety boundary

The only file that runs git commands. Contains a private run() function that calls execFile('git', args, { cwd }) and 7 public functions (gitFetch, gitCheckout, gitPull, gitStatus, gitCurrentBranch, gitRemoteUrl, gitBranchList) plus a parseRepoId helper. To audit git safety, you only need to read this one file.

main.js - Electron main process

Handles:

  • Config management - reads/writes config.json from %APPDATA%/git-workspace/. Config path is lazily initialized after Electron is ready.
  • IPC handlers - get-config, save-config, pick-repo-folder, scan-folder, repo-status, repo-branches, sync-repo, export-workspace, import-workspace, check-git.
  • Window creation - single window, no menu bar, context isolation enabled.

preload.js - Context bridge

Maps each IPC channel to a method on window.api. This is the complete list of what the renderer can do - nothing more.

index.html - UI structure

Single-page app with:

  • Sidebar - workspace list, new workspace button, registry and import buttons.
  • Three views - welcome (empty state), workspace (repo table + sync), registry (repo list + add/scan).
  • Four modals - workspace create/edit, dirty repo warning, import result, git-not-found overlay.

styles.css - Styling

Dark theme with Catppuccin-inspired colors. Defines CSS variables at :root for easy theming. Covers layout, sidebar, tables, buttons, modals, status indicators, and scrollbars.

renderer.js - UI logic

All DOM manipulation and event handling. Key functions:

  • init() - checks git availability, loads config, renders sidebar.
  • renderWorkspace() / fetchRepoStatus() - builds the repo table and fetches live status.
  • syncAll() - orchestrates the sync: checks dirty repos, shows warning, syncs sequentially.
  • openWorkspaceModal() - handles create/edit with registry-based repo picker.
  • importWorkspace() / exportWorkspace() - portable workspace transfer.
  • renderRegistry() / addRepoToRegistry() / scanFolderToRegistry() - registry management.

Config File

Location: %APPDATA%/git-workspace/config.json

{
"registry": [
{
"id": "myorg/my-repo",
"localPath": "C:\\Repositories\\my-repo"
}
],
"workspaces": [
{
"id": "ws-1710000000000",
"name": "Development",
"repos": [
{ "registryId": "myorg/my-repo", "branch": "development" },
{ "registryId": "myorg/other-repo", "branch": null }
]
}
]
}
  • registry - maps org/repo (from git remote URL) to local filesystem path.
  • workspaces - each has a unique ID, name, and list of repos referencing the registry.
  • branch: null means "stay on whatever branch is currently checked out."

If this file becomes corrupt, the app backs it up as config.json.backup and creates a fresh empty config.


Troubleshooting

ProblemSolution
App shows "Git Not Found"Install Git and make sure git --version works in your terminal.
Repo shows yellow dot in registryThe local path no longer exists or is not a git repo. Update or remove it.
Sync skips a repo as "dirty"That repo has uncommitted changes. Commit or stash them first.
Checkout fails during syncThe target branch may not exist. Check the branch name in workspace settings.
Config lost between restartsMake sure you're on version 1.0.0+. Earlier versions had a config path bug.
Import fails with missing reposAdd the listed repos to your registry first (Add Repository or Scan Folder).

About

Git Workspace Manager - manage multiple repos across branches

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Git Workspace Manager

A minimalist desktop app for managing multiple Git repositories across branches. Switch an entire group of repos to the right branches and pull updates with one click.

Built with Electron and vanilla HTML/CSS/JS. No frameworks, no build tools, no complexity.

Preview

Screenshot 2026-03-24 172439image

Table of Contents


Installation

Option A: Portable Executable (recommended for daily use)

  1. Download Git Workspace Manager 1.0.0.exe from the dist/ folder.
  2. Place it anywhere (Desktop, USB drive, etc.).
  3. Double-click to run. No installation needed.

Prerequisite:Git must be installed and available on your system PATH.

Option B: Run from Source (for development)

Prerequisites:Node.js (v18+) and Git.

cd git-workspace
npm install
npm start

Getting Started

1. Register your repositories

Before you can create workspaces, the app needs to know where your repos live on disk.

  • Click Manage Registry in the sidebar.
  • Click Add Repository to pick a single repo folder, or Scan Folder to automatically find all repos inside a parent directory (e.g. C:\Repositories).
  • The app reads each repo's git remote origin URL and extracts an identifier like myorg/my-repo.

2. Create a workspace

A workspace is a named group of repositories, each with an optional target branch.

  • Click + New Workspace in the sidebar.
  • Give it a name (e.g. "Development", "Staging").
  • Check the repos you want to include.
  • For each repo, type a branch name (e.g. development) or leave blank to stay on whatever branch it's currently on.
  • Click Save.

3. Sync

  • Select a workspace from the sidebar.
  • Click Sync All.
  • The app will check each repo for uncommitted changes. If any are dirty, you'll see a warning and can choose to skip them.
  • For each clean repo, it will: fetch all remotes, checkout the target branch (if specified), and pull latest changes.
  • Progress and results are shown per-repo in the table.

Features

FeatureDescription
Workspace managementCreate, edit, and delete named groups of repos with target branches.
Sync AllFetch + checkout + pull for every repo in a workspace, with per-repo progress.
Dirty repo warningsRepos with uncommitted changes are flagged and skipped during sync.
Repository registryCentral list mapping org/repo identifiers to local paths.
Scan FolderBatch-add all repos from a parent directory.
Import / ExportMove workspace configs between machines without sharing local paths.
Status indicatorsGreen = clean, Red = dirty, Yellow = error/missing.

Import / Export

Exporting a workspace

  1. Select a workspace and click Export.
  2. Choose where to save the .json file.
  3. The exported file contains only repo identifiers (org/repo) and branch names. No local paths are included.

Example export file:

{
"name": "Development",
"exportedAt": "2026-03-18T12:00:00Z",
"repos": [
{ "id": "myorg/api-server", "branch": "development" },
{ "id": "myorg/web-client", "branch": "development" },
{ "id": "myorg/shared-lib", "branch": null }
]
}

Importing a workspace

  1. Click Import Workspace in the sidebar and select a .json file.
  2. The app checks that every repo in the file exists in your local registry.
  3. If all repos are found: The workspace is created.
  4. If any repos are missing: The import is blocked and you'll see a list of missing repos. Add them to your registry first, then try again.

This lets you share workspace configs between machines where the same repos may live at different paths.


Git Safety

This app is designed to be accident-proof. It only runs safe, read-or-pull git operations:

AllowedNOT allowed (not in the app at all)
git fetch --allgit merge
git checkout <branch>git rebase
git pullgit reset
git status --porcelaingit push
git rev-parse --abbrev-ref HEADgit clean
git remote get-url origingit stash
git branch -aAny --force flag

All git commands are executed via Node.js execFile with arguments passed as arrays (not shell strings), preventing command injection. There is no generic "run any git command" function.


Developer Guide

Project structure

git-workspace/
package.json # npm config, Electron version, build settings
main.js # Electron main process
preload.js # Context bridge (main <-> renderer)
git.js # Git command whitelist
index.html # UI markup
styles.css # Styling
renderer.js # UI logic
dist/ # Built executables (after npm run build)

How the code is organized

The app follows Electron's standard architecture with three layers:

  1. Main process (main.js) - Runs in Node.js. Handles file I/O, config persistence, native dialogs, and git operations. Exposes functionality to the renderer via IPC handlers.

  2. Preload (preload.js) - The bridge. Uses Electron's contextBridge to expose a safe window.api object to the renderer. The renderer cannot access Node.js directly.

  3. Renderer (renderer.js + index.html + styles.css) - Runs in the browser window. All UI logic: DOM manipulation, event handlers, view switching. Calls window.api.* methods to talk to the main process.

Running in development

npm start

This launches Electron and loads the app. Changes to renderer.js, index.html, or styles.css take effect after reloading the window (Ctrl+R). Changes to main.js, preload.js, or git.js require restarting the app.

Building the executable

npm run build

This uses electron-builder to create a portable .exe in the dist/ folder. The executable bundles the Electron runtime and all source files - no Node.js installation needed on the target machine.

Adding a new IPC handler

To add new functionality accessible from the UI:

  1. main.js - Add a handler: ipcMain.handle('my-action', async (_e, arg) => { ... })
  2. preload.js - Expose it: add myAction: (arg) => ipcRenderer.invoke('my-action', arg) to the contextBridge object
  3. renderer.js - Call it: const result = await window.api.myAction(arg)

File Reference

git.js - Git safety boundary

The only file that runs git commands. Contains a private run() function that calls execFile('git', args, { cwd }) and 7 public functions (gitFetch, gitCheckout, gitPull, gitStatus, gitCurrentBranch, gitRemoteUrl, gitBranchList) plus a parseRepoId helper. To audit git safety, you only need to read this one file.

main.js - Electron main process

Handles:

  • Config management - reads/writes config.json from %APPDATA%/git-workspace/. Config path is lazily initialized after Electron is ready.
  • IPC handlers - get-config, save-config, pick-repo-folder, scan-folder, repo-status, repo-branches, sync-repo, export-workspace, import-workspace, check-git.
  • Window creation - single window, no menu bar, context isolation enabled.

preload.js - Context bridge

Maps each IPC channel to a method on window.api. This is the complete list of what the renderer can do - nothing more.

index.html - UI structure

Single-page app with:

  • Sidebar - workspace list, new workspace button, registry and import buttons.
  • Three views - welcome (empty state), workspace (repo table + sync), registry (repo list + add/scan).
  • Four modals - workspace create/edit, dirty repo warning, import result, git-not-found overlay.

styles.css - Styling

Dark theme with Catppuccin-inspired colors. Defines CSS variables at :root for easy theming. Covers layout, sidebar, tables, buttons, modals, status indicators, and scrollbars.

renderer.js - UI logic

All DOM manipulation and event handling. Key functions:

  • init() - checks git availability, loads config, renders sidebar.
  • renderWorkspace() / fetchRepoStatus() - builds the repo table and fetches live status.
  • syncAll() - orchestrates the sync: checks dirty repos, shows warning, syncs sequentially.
  • openWorkspaceModal() - handles create/edit with registry-based repo picker.
  • importWorkspace() / exportWorkspace() - portable workspace transfer.
  • renderRegistry() / addRepoToRegistry() / scanFolderToRegistry() - registry management.

Config File

Location: %APPDATA%/git-workspace/config.json

{
"registry": [
{
"id": "myorg/my-repo",
"localPath": "C:\\Repositories\\my-repo"
}
],
"workspaces": [
{
"id": "ws-1710000000000",
"name": "Development",
"repos": [
{ "registryId": "myorg/my-repo", "branch": "development" },
{ "registryId": "myorg/other-repo", "branch": null }
]
}
]
}
  • registry - maps org/repo (from git remote URL) to local filesystem path.
  • workspaces - each has a unique ID, name, and list of repos referencing the registry.
  • branch: null means "stay on whatever branch is currently checked out."

If this file becomes corrupt, the app backs it up as config.json.backup and creates a fresh empty config.


Troubleshooting

ProblemSolution
App shows "Git Not Found"Install Git and make sure git --version works in your terminal.
Repo shows yellow dot in registryThe local path no longer exists or is not a git repo. Update or remove it.
Sync skips a repo as "dirty"That repo has uncommitted changes. Commit or stash them first.
Checkout fails during syncThe target branch may not exist. Check the branch name in workspace settings.
Config lost between restartsMake sure you're on version 1.0.0+. Earlier versions had a config path bug.
Import fails with missing reposAdd the listed repos to your registry first (Add Repository or Scan Folder).

About

Git Workspace Manager - manage multiple repos across branches

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Git Workspace Manager

A minimalist desktop app for managing multiple Git repositories across branches. Switch an entire group of repos to the right branches and pull updates with one click.

Built with Electron and vanilla HTML/CSS/JS. No frameworks, no build tools, no complexity.

Preview

Screenshot 2026-03-24 172439image

Table of Contents


Installation

Option A: Portable Executable (recommended for daily use)

  1. Download Git Workspace Manager 1.0.0.exe from the dist/ folder.
  2. Place it anywhere (Desktop, USB drive, etc.).
  3. Double-click to run. No installation needed.

Prerequisite:Git must be installed and available on your system PATH.

Option B: Run from Source (for development)

Prerequisites:Node.js (v18+) and Git.

cd git-workspace
npm install
npm start

Getting Started

1. Register your repositories

Before you can create workspaces, the app needs to know where your repos live on disk.

  • Click Manage Registry in the sidebar.
  • Click Add Repository to pick a single repo folder, or Scan Folder to automatically find all repos inside a parent directory (e.g. C:\Repositories).
  • The app reads each repo's git remote origin URL and extracts an identifier like myorg/my-repo.

2. Create a workspace

A workspace is a named group of repositories, each with an optional target branch.

  • Click + New Workspace in the sidebar.
  • Give it a name (e.g. "Development", "Staging").
  • Check the repos you want to include.
  • For each repo, type a branch name (e.g. development) or leave blank to stay on whatever branch it's currently on.
  • Click Save.

3. Sync

  • Select a workspace from the sidebar.
  • Click Sync All.
  • The app will check each repo for uncommitted changes. If any are dirty, you'll see a warning and can choose to skip them.
  • For each clean repo, it will: fetch all remotes, checkout the target branch (if specified), and pull latest changes.
  • Progress and results are shown per-repo in the table.

Features

FeatureDescription
Workspace managementCreate, edit, and delete named groups of repos with target branches.
Sync AllFetch + checkout + pull for every repo in a workspace, with per-repo progress.
Dirty repo warningsRepos with uncommitted changes are flagged and skipped during sync.
Repository registryCentral list mapping org/repo identifiers to local paths.
Scan FolderBatch-add all repos from a parent directory.
Import / ExportMove workspace configs between machines without sharing local paths.
Status indicatorsGreen = clean, Red = dirty, Yellow = error/missing.

Import / Export

Exporting a workspace

  1. Select a workspace and click Export.
  2. Choose where to save the .json file.
  3. The exported file contains only repo identifiers (org/repo) and branch names. No local paths are included.

Example export file:

{
"name": "Development",
"exportedAt": "2026-03-18T12:00:00Z",
"repos": [
{ "id": "myorg/api-server", "branch": "development" },
{ "id": "myorg/web-client", "branch": "development" },
{ "id": "myorg/shared-lib", "branch": null }
]
}

Importing a workspace

  1. Click Import Workspace in the sidebar and select a .json file.
  2. The app checks that every repo in the file exists in your local registry.
  3. If all repos are found: The workspace is created.
  4. If any repos are missing: The import is blocked and you'll see a list of missing repos. Add them to your registry first, then try again.

This lets you share workspace configs between machines where the same repos may live at different paths.


Git Safety

This app is designed to be accident-proof. It only runs safe, read-or-pull git operations:

AllowedNOT allowed (not in the app at all)
git fetch --allgit merge
git checkout <branch>git rebase
git pullgit reset
git status --porcelaingit push
git rev-parse --abbrev-ref HEADgit clean
git remote get-url origingit stash
git branch -aAny --force flag

All git commands are executed via Node.js execFile with arguments passed as arrays (not shell strings), preventing command injection. There is no generic "run any git command" function.


Developer Guide

Project structure

git-workspace/
package.json # npm config, Electron version, build settings
main.js # Electron main process
preload.js # Context bridge (main <-> renderer)
git.js # Git command whitelist
index.html # UI markup
styles.css # Styling
renderer.js # UI logic
dist/ # Built executables (after npm run build)

How the code is organized

The app follows Electron's standard architecture with three layers:

  1. Main process (main.js) - Runs in Node.js. Handles file I/O, config persistence, native dialogs, and git operations. Exposes functionality to the renderer via IPC handlers.

  2. Preload (preload.js) - The bridge. Uses Electron's contextBridge to expose a safe window.api object to the renderer. The renderer cannot access Node.js directly.

  3. Renderer (renderer.js + index.html + styles.css) - Runs in the browser window. All UI logic: DOM manipulation, event handlers, view switching. Calls window.api.* methods to talk to the main process.

Running in development

npm start

This launches Electron and loads the app. Changes to renderer.js, index.html, or styles.css take effect after reloading the window (Ctrl+R). Changes to main.js, preload.js, or git.js require restarting the app.

Building the executable

npm run build

This uses electron-builder to create a portable .exe in the dist/ folder. The executable bundles the Electron runtime and all source files - no Node.js installation needed on the target machine.

Adding a new IPC handler

To add new functionality accessible from the UI:

  1. main.js - Add a handler: ipcMain.handle('my-action', async (_e, arg) => { ... })
  2. preload.js - Expose it: add myAction: (arg) => ipcRenderer.invoke('my-action', arg) to the contextBridge object
  3. renderer.js - Call it: const result = await window.api.myAction(arg)

File Reference

git.js - Git safety boundary

The only file that runs git commands. Contains a private run() function that calls execFile('git', args, { cwd }) and 7 public functions (gitFetch, gitCheckout, gitPull, gitStatus, gitCurrentBranch, gitRemoteUrl, gitBranchList) plus a parseRepoId helper. To audit git safety, you only need to read this one file.

main.js - Electron main process

Handles:

  • Config management - reads/writes config.json from %APPDATA%/git-workspace/. Config path is lazily initialized after Electron is ready.
  • IPC handlers - get-config, save-config, pick-repo-folder, scan-folder, repo-status, repo-branches, sync-repo, export-workspace, import-workspace, check-git.
  • Window creation - single window, no menu bar, context isolation enabled.

preload.js - Context bridge

Maps each IPC channel to a method on window.api. This is the complete list of what the renderer can do - nothing more.

index.html - UI structure

Single-page app with:

  • Sidebar - workspace list, new workspace button, registry and import buttons.
  • Three views - welcome (empty state), workspace (repo table + sync), registry (repo list + add/scan).
  • Four modals - workspace create/edit, dirty repo warning, import result, git-not-found overlay.

styles.css - Styling

Dark theme with Catppuccin-inspired colors. Defines CSS variables at :root for easy theming. Covers layout, sidebar, tables, buttons, modals, status indicators, and scrollbars.

renderer.js - UI logic

All DOM manipulation and event handling. Key functions:

  • init() - checks git availability, loads config, renders sidebar.
  • renderWorkspace() / fetchRepoStatus() - builds the repo table and fetches live status.
  • syncAll() - orchestrates the sync: checks dirty repos, shows warning, syncs sequentially.
  • openWorkspaceModal() - handles create/edit with registry-based repo picker.
  • importWorkspace() / exportWorkspace() - portable workspace transfer.
  • renderRegistry() / addRepoToRegistry() / scanFolderToRegistry() - registry management.

Config File

Location: %APPDATA%/git-workspace/config.json

{
"registry": [
{
"id": "myorg/my-repo",
"localPath": "C:\\Repositories\\my-repo"
}
],
"workspaces": [
{
"id": "ws-1710000000000",
"name": "Development",
"repos": [
{ "registryId": "myorg/my-repo", "branch": "development" },
{ "registryId": "myorg/other-repo", "branch": null }
]
}
]
}
  • registry - maps org/repo (from git remote URL) to local filesystem path.
  • workspaces - each has a unique ID, name, and list of repos referencing the registry.
  • branch: null means "stay on whatever branch is currently checked out."

If this file becomes corrupt, the app backs it up as config.json.backup and creates a fresh empty config.


Troubleshooting

ProblemSolution
App shows "Git Not Found"Install Git and make sure git --version works in your terminal.
Repo shows yellow dot in registryThe local path no longer exists or is not a git repo. Update or remove it.
Sync skips a repo as "dirty"That repo has uncommitted changes. Commit or stash them first.
Checkout fails during syncThe target branch may not exist. Check the branch name in workspace settings.
Config lost between restartsMake sure you're on version 1.0.0+. Earlier versions had a config path bug.
Import fails with missing reposAdd the listed repos to your registry first (Add Repository or Scan Folder).

About

Git Workspace Manager - manage multiple repos across branches

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Git Workspace Manager

A minimalist desktop app for managing multiple Git repositories across branches. Switch an entire group of repos to the right branches and pull updates with one click.

Built with Electron and vanilla HTML/CSS/JS. No frameworks, no build tools, no complexity.

Preview

Screenshot 2026-03-24 172439image

Table of Contents


Installation

Option A: Portable Executable (recommended for daily use)

  1. Download Git Workspace Manager 1.0.0.exe from the dist/ folder.
  2. Place it anywhere (Desktop, USB drive, etc.).
  3. Double-click to run. No installation needed.

Prerequisite:Git must be installed and available on your system PATH.

Option B: Run from Source (for development)

Prerequisites:Node.js (v18+) and Git.

cd git-workspace
npm install
npm start

Getting Started

1. Register your repositories

Before you can create workspaces, the app needs to know where your repos live on disk.

  • Click Manage Registry in the sidebar.
  • Click Add Repository to pick a single repo folder, or Scan Folder to automatically find all repos inside a parent directory (e.g. C:\Repositories).
  • The app reads each repo's git remote origin URL and extracts an identifier like myorg/my-repo.

2. Create a workspace

A workspace is a named group of repositories, each with an optional target branch.

  • Click + New Workspace in the sidebar.
  • Give it a name (e.g. "Development", "Staging").
  • Check the repos you want to include.
  • For each repo, type a branch name (e.g. development) or leave blank to stay on whatever branch it's currently on.
  • Click Save.

3. Sync

  • Select a workspace from the sidebar.
  • Click Sync All.
  • The app will check each repo for uncommitted changes. If any are dirty, you'll see a warning and can choose to skip them.
  • For each clean repo, it will: fetch all remotes, checkout the target branch (if specified), and pull latest changes.
  • Progress and results are shown per-repo in the table.

Features

FeatureDescription
Workspace managementCreate, edit, and delete named groups of repos with target branches.
Sync AllFetch + checkout + pull for every repo in a workspace, with per-repo progress.
Dirty repo warningsRepos with uncommitted changes are flagged and skipped during sync.
Repository registryCentral list mapping org/repo identifiers to local paths.
Scan FolderBatch-add all repos from a parent directory.
Import / ExportMove workspace configs between machines without sharing local paths.
Status indicatorsGreen = clean, Red = dirty, Yellow = error/missing.

Import / Export

Exporting a workspace

  1. Select a workspace and click Export.
  2. Choose where to save the .json file.
  3. The exported file contains only repo identifiers (org/repo) and branch names. No local paths are included.

Example export file:

{
"name": "Development",
"exportedAt": "2026-03-18T12:00:00Z",
"repos": [
{ "id": "myorg/api-server", "branch": "development" },
{ "id": "myorg/web-client", "branch": "development" },
{ "id": "myorg/shared-lib", "branch": null }
]
}

Importing a workspace

  1. Click Import Workspace in the sidebar and select a .json file.
  2. The app checks that every repo in the file exists in your local registry.
  3. If all repos are found: The workspace is created.
  4. If any repos are missing: The import is blocked and you'll see a list of missing repos. Add them to your registry first, then try again.

This lets you share workspace configs between machines where the same repos may live at different paths.


Git Safety

This app is designed to be accident-proof. It only runs safe, read-or-pull git operations:

AllowedNOT allowed (not in the app at all)
git fetch --allgit merge
git checkout <branch>git rebase
git pullgit reset
git status --porcelaingit push
git rev-parse --abbrev-ref HEADgit clean
git remote get-url origingit stash
git branch -aAny --force flag

All git commands are executed via Node.js execFile with arguments passed as arrays (not shell strings), preventing command injection. There is no generic "run any git command" function.


Developer Guide

Project structure

git-workspace/
package.json # npm config, Electron version, build settings
main.js # Electron main process
preload.js # Context bridge (main <-> renderer)
git.js # Git command whitelist
index.html # UI markup
styles.css # Styling
renderer.js # UI logic
dist/ # Built executables (after npm run build)

How the code is organized

The app follows Electron's standard architecture with three layers:

  1. Main process (main.js) - Runs in Node.js. Handles file I/O, config persistence, native dialogs, and git operations. Exposes functionality to the renderer via IPC handlers.

  2. Preload (preload.js) - The bridge. Uses Electron's contextBridge to expose a safe window.api object to the renderer. The renderer cannot access Node.js directly.

  3. Renderer (renderer.js + index.html + styles.css) - Runs in the browser window. All UI logic: DOM manipulation, event handlers, view switching. Calls window.api.* methods to talk to the main process.

Running in development

npm start

This launches Electron and loads the app. Changes to renderer.js, index.html, or styles.css take effect after reloading the window (Ctrl+R). Changes to main.js, preload.js, or git.js require restarting the app.

Building the executable

npm run build

This uses electron-builder to create a portable .exe in the dist/ folder. The executable bundles the Electron runtime and all source files - no Node.js installation needed on the target machine.

Adding a new IPC handler

To add new functionality accessible from the UI:

  1. main.js - Add a handler: ipcMain.handle('my-action', async (_e, arg) => { ... })
  2. preload.js - Expose it: add myAction: (arg) => ipcRenderer.invoke('my-action', arg) to the contextBridge object
  3. renderer.js - Call it: const result = await window.api.myAction(arg)

File Reference

git.js - Git safety boundary

The only file that runs git commands. Contains a private run() function that calls execFile('git', args, { cwd }) and 7 public functions (gitFetch, gitCheckout, gitPull, gitStatus, gitCurrentBranch, gitRemoteUrl, gitBranchList) plus a parseRepoId helper. To audit git safety, you only need to read this one file.

main.js - Electron main process

Handles:

  • Config management - reads/writes config.json from %APPDATA%/git-workspace/. Config path is lazily initialized after Electron is ready.
  • IPC handlers - get-config, save-config, pick-repo-folder, scan-folder, repo-status, repo-branches, sync-repo, export-workspace, import-workspace, check-git.
  • Window creation - single window, no menu bar, context isolation enabled.

preload.js - Context bridge

Maps each IPC channel to a method on window.api. This is the complete list of what the renderer can do - nothing more.

index.html - UI structure

Single-page app with:

  • Sidebar - workspace list, new workspace button, registry and import buttons.
  • Three views - welcome (empty state), workspace (repo table + sync), registry (repo list + add/scan).
  • Four modals - workspace create/edit, dirty repo warning, import result, git-not-found overlay.

styles.css - Styling

Dark theme with Catppuccin-inspired colors. Defines CSS variables at :root for easy theming. Covers layout, sidebar, tables, buttons, modals, status indicators, and scrollbars.

renderer.js - UI logic

All DOM manipulation and event handling. Key functions:

  • init() - checks git availability, loads config, renders sidebar.
  • renderWorkspace() / fetchRepoStatus() - builds the repo table and fetches live status.
  • syncAll() - orchestrates the sync: checks dirty repos, shows warning, syncs sequentially.
  • openWorkspaceModal() - handles create/edit with registry-based repo picker.
  • importWorkspace() / exportWorkspace() - portable workspace transfer.
  • renderRegistry() / addRepoToRegistry() / scanFolderToRegistry() - registry management.

Config File

Location: %APPDATA%/git-workspace/config.json

{
"registry": [
{
"id": "myorg/my-repo",
"localPath": "C:\\Repositories\\my-repo"
}
],
"workspaces": [
{
"id": "ws-1710000000000",
"name": "Development",
"repos": [
{ "registryId": "myorg/my-repo", "branch": "development" },
{ "registryId": "myorg/other-repo", "branch": null }
]
}
]
}
  • registry - maps org/repo (from git remote URL) to local filesystem path.
  • workspaces - each has a unique ID, name, and list of repos referencing the registry.
  • branch: null means "stay on whatever branch is currently checked out."

If this file becomes corrupt, the app backs it up as config.json.backup and creates a fresh empty config.


Troubleshooting

ProblemSolution
App shows "Git Not Found"Install Git and make sure git --version works in your terminal.
Repo shows yellow dot in registryThe local path no longer exists or is not a git repo. Update or remove it.
Sync skips a repo as "dirty"That repo has uncommitted changes. Commit or stash them first.
Checkout fails during syncThe target branch may not exist. Check the branch name in workspace settings.
Config lost between restartsMake sure you're on version 1.0.0+. Earlier versions had a config path bug.
Import fails with missing reposAdd the listed repos to your registry first (Add Repository or Scan Folder).

About

Git Workspace Manager - manage multiple repos across branches

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages