Summary
When a repository is opened via the CLI (github-desktop-plus-cli <path>, which boils down to open -n … --args --cli-open=<path>), the app always routes the open action to the currently-focused window and switches that window's repository — even when another already-open window is showing the requested repository.
In my case it was triggered via an editor-integrated "Open in GitHub Desktop" command (that I have added via this extension), but it's reproducible via the CLI directly.
Compare with the reverse behavior: "Open in Editor", where typically editors will bring up the existing window rather than switch the most recent window to a different project.
Steps to reproduce
- Open repo A in one window.
- Open repo B in a second window, and leave it focused.
- From outside the app, run
github-desktop-plus-cli /path/to/A
Expected: the window already showing A is restored/focused.
Actual: the focused window (showing B) is switched to A; the original A window is left as-is.
Investigation
I asked Claude to look into it, these were the results. Happy to prototype a PR, just wanted to make sure there is alignment on the direction.
Where it happens
Both the second-instance handler and the CLI dispatch resolve their target through getTargetWindow(), which returns the focused window (or the first window) — it never considers which window already has the requested repository:
- The window picker:
|
function getTargetWindow() { |
|
const focusedWindow = BrowserWindow.getFocusedWindow() |
|
const focusedAppWindow = getAppWindowFromBrowserWindow(focusedWindow) |
|
|
|
if (focusedAppWindow !== null) { |
|
return focusedAppWindow |
|
} |
|
|
|
return getAppWindows()[0] ?? null |
|
} |
second-instance handler routes through it:
|
app.on('second-instance', (event, args, workingDirectory) => { |
|
// Someone tried to run a second instance, we should focus our window. |
|
const targetWindow = getTargetWindow() |
|
if (targetWindow) { |
|
if (targetWindow.isMinimized()) { |
|
targetWindow.restore() |
|
} |
|
|
|
if (!targetWindow.isVisible()) { |
|
targetWindow.show() |
|
} |
|
|
|
targetWindow.focus() |
|
} |
|
|
|
handleCommandLineArguments(args) |
|
}) |
|
|
--cli-open dispatch:
|
if (typeof args['cli-open'] === 'string') { |
|
handleCLIAction({ kind: 'open-repository', path: args['cli-open'] }) |
handleCLIAction → onDidLoad → getLoadedTargetWindow → getTargetWindow:
|
function handleCLIAction(action: CLIAction) { |
|
onDidLoad(window => { |
|
// This manual focus call _shouldn't_ be necessary, but is for Chrome on |
|
// macOS. See https://github.com/desktop/desktop/issues/973. |
|
window.focus() |
|
window.sendCLIAction(action) |
|
}) |
|
} |
and
|
function onDidLoad(fn: OnDidLoadFn) { |
|
const loadedWindow = getLoadedTargetWindow() |
|
if (loadedWindow !== null) { |
|
fn(loadedWindow) |
|
return |
|
} |
|
|
|
pendingOnDidLoadFns.push(fn) |
|
} |
I searched the source for any "find the window already showing repo X" logic and there's none — the CLI / second-instance path has no notion of which window holds which repository.
Suggested fix
Before routing open-repository to getTargetWindow(), search the open windows for one whose currently-selected repository matches the requested path; if found, restore/focus that window instead of changing the focused one. Falls back to current behavior when no window has it.
The main process doesn't currently track a window→repository mapping (windows report titles but not their selected repo path), so this likely needs each window to report its selected repository path to main so the lookup can be done there. A path-normalization step (resolve symlinks / trailing slashes / case) would make the match robust.
Environment
- GitHub Desktop Plus 3.5.7.2
- macOS Tahoe 26.3 (Apple Silicon)
Summary
When a repository is opened via the CLI (
github-desktop-plus-cli <path>, which boils down toopen -n … --args --cli-open=<path>), the app always routes the open action to the currently-focused window and switches that window's repository — even when another already-open window is showing the requested repository.In my case it was triggered via an editor-integrated "Open in GitHub Desktop" command (that I have added via this extension), but it's reproducible via the CLI directly.
Compare with the reverse behavior: "Open in Editor", where typically editors will bring up the existing window rather than switch the most recent window to a different project.
Steps to reproduce
github-desktop-plus-cli /path/to/AExpected: the window already showing A is restored/focused.
Actual: the focused window (showing B) is switched to A; the original A window is left as-is.
Investigation
I asked Claude to look into it, these were the results. Happy to prototype a PR, just wanted to make sure there is alignment on the direction.
Where it happens
Both the
second-instancehandler and the CLI dispatch resolve their target throughgetTargetWindow(), which returns the focused window (or the first window) — it never considers which window already has the requested repository:github-desktop-plus/app/src/main-process/main.ts
Lines 184 to 193 in 3e01e8e
second-instancehandler routes through it:github-desktop-plus/app/src/main-process/main.ts
Lines 253 to 270 in 3e01e8e
--cli-opendispatch:github-desktop-plus/app/src/main-process/main.ts
Lines 359 to 360 in 3e01e8e
handleCLIAction→onDidLoad→getLoadedTargetWindow→getTargetWindow:github-desktop-plus/app/src/main-process/main.ts
Lines 373 to 380 in 3e01e8e
github-desktop-plus/app/src/main-process/main.ts
Lines 979 to 987 in 3e01e8e
I searched the source for any "find the window already showing repo X" logic and there's none — the CLI / second-instance path has no notion of which window holds which repository.
Suggested fix
Before routing
open-repositorytogetTargetWindow(), search the open windows for one whose currently-selected repository matches the requested path; if found, restore/focus that window instead of changing the focused one. Falls back to current behavior when no window has it.The main process doesn't currently track a window→repository mapping (windows report titles but not their selected repo path), so this likely needs each window to report its selected repository path to main so the lookup can be done there. A path-normalization step (resolve symlinks / trailing slashes / case) would make the match robust.
Environment