Skip to content

core: gitbash() fails when git resolves to mingw64/bin (e.g. inside Git Bash), shell falls back to pwsh #57310

Open

Description

@theshasha

Description

ShellSelect.gitbash() finds Git Bash by taking the first git on PATH and going two levels up to bin/bash.exe. That only works for Git\cmd\git.exe. Inside a Git Bash session /mingw64/bin comes first on PATH, so git is Git\mingw64\bin\git.exe and the guess becomes Git\mingw64\bin\bash.exe, which doesn't exist.

When that happens:

  • SHELL=/usr/bin/bash (set by Git Bash) can't be mapped to a Windows path, so OpenCode started from Git Bash runs the shell tool in pwsh
  • "shell": "bash" falls back to bash on PATH, which can be the WSL launcher in System32
  • Git Bash is missing from the shell list

#22054 reported the same guess failing for MSYS2's ucrt64/bin/git.exe.

Suggestion: use git --exec-path (once, cached). It returns <git root>/mingw64/libexec/git-core (or the ucrt64/clang64 equivalent) regardless of which git on PATH was found.

Plugins

none

OpenCode version

current dev

Steps to reproduce

In Git Bash, from packages/core:

which git   # /mingw64/bin/git
bun -e 'import { ShellSelect } from "@opencode/core/shell/select"; console.log(ShellSelect.gitbash(), ShellSelect.resolve({ priority: "config" }))'
# undefined C:\Program Files\PowerShell\7\pwsh.EXE

Operating System

Windows 11 (22621), Git for Windows 2.52.0

Terminal

Git Bash

Activity

  1. opencode-agent commented on Oct 20, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed report. I confirmed this on the latest dev (9d90d892), and select.ts is the same in v2.0.32.

    There was no Windows machine available, so I recreated the Git for Windows folder layout on Linux (Git/cmd/git, Git/mingw64/bin/git, Git/bin/bash.exe) and made ShellSelect take its Windows branch. The script below does this.

    • With Git/cmd first on PATH, ShellSelect.gitbash() returns Git/bin/bash.exe.
    • With Git/mingw64/bin first on PATH, as inside Git Bash, it returns undefined.

    The cause is path.join(git, "..", "..", "bin", "bash.exe"), which only works when git is the one in Git\cmd. I didn't run the full resolve() path. From the code, though, once gitbash() fails, SHELL=/usr/bin/bash and "shell": "bash" fall back as you describe.

    Related: #22054 reported the same guess failing for MSYS2's ucrt64/bin/git.exe (on v1).

    Reproduction script (gitbash-sim.ts)
    // Copy into <checkout>/packages/core/ and run there with bun (module resolution needs the workspace).
    // Simulates the Git for Windows directory layout on Linux and makes ShellSelect take its
    // win32 branch (process.platform is overridden after imports), to exercise gitbash()'s
    // path derivation. Run from a checkout's packages/core:  bun /workspace/repro/gitbash-sim.ts
    import { mkdirSync, writeFileSync, chmodSync, mkdtempSync } from "fs"
    import path from "path"
    import os from "os"
    const { ShellSelect } = await import("@opencode/core/shell/select")
    
    const root = path.join(mkdtempSync(path.join(os.tmpdir(), "gfw-")), "Git")
    for (const f of ["cmd/git", "mingw64/bin/git", "bin/bash.exe"]) {
      const p = path.join(root, f)
      mkdirSync(path.dirname(p), { recursive: true })
      writeFileSync(p, "#!/bin/sh\n")
      chmodSync(p, 0o755)
    }
    Object.defineProperty(process, "platform", { value: "win32" })
    
    process.env.PATH = `${root}/cmd:/usr/bin:/bin` // like cmd.exe / PowerShell: Git\cmd on PATH
    console.log("git on PATH = Git/cmd/git         -> gitbash():", ShellSelect.gitbash())
    process.env.PATH = `${root}/mingw64/bin:${root}/cmd:/usr/bin:/bin` // inside Git Bash: /mingw64/bin first
    console.log("git on PATH = Git/mingw64/bin/git -> gitbash():", ShellSelect.gitbash())
    console.log("expected in both cases:", path.join(root, "bin", "bash.exe"))

    Run it: bun gitbash-sim.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions