fix(git): prefer PATH git before fallback#2665
Conversation
Greptile SummaryThis PR upgrades the git binary resolution strategy so the first executable
Confidence Score: 5/5Safe to merge — the git binary is resolved at startup as before and the new dynamic override only takes effect after an explicit probe, so there is no regression window. The probe-then-override ordering is correct: buildAndStoreHostDependency is now awaited for core deps, ensuring setGitExecutableOverride is called before any GitRuntime is constructed. All existing callers that used the static GIT_EXECUTABLE now call getGitExecutable(), which falls back to the same startup-resolved value until the probe fires. The Windows PATHEXT path, per-connection remote overrides, and the invalid-GIT_PATH fallthrough are all covered by new tests. No files require special attention; the one style note on DynamicGitExec.file in runtime-manager.ts is non-blocking.
|
| Filename | Overview |
|---|---|
| apps/emdash-desktop/src/main/core/utils/exec.ts | Core of the change: adds PATH-based git discovery with Windows PATHEXT support, dynamic per-connection overrides, and a GIT_EXECUTABLE startup fallback. |
| apps/emdash-desktop/src/main/core/runtime/runtime-manager.ts | Introduces DynamicGitExec (BoundExec wrapping dynamic git resolution) and probeGitDependency called before runtime creation; DynamicGitExec.file is hardcoded as 'git' while the actual binary is resolved dynamically. |
| apps/emdash-desktop/src/main/core/dependencies/dependency-managers.ts | Adds syncGitExecutable subscriber on onStatusUpdated to propagate the probed git path into getGitExecutable; clears remote overrides on clearDependencyManager. |
| packages/core/src/host-dependencies/runtime/host-dependency-manager.ts | Extends probe() to await buildAndStoreHostDependency for core-category deps (synchronous event emission) and adds probePinnedSource for pinned installs not on PATH. |
| apps/emdash-desktop/src/main/core/execution-context/ssh-execution-context.ts | Threads connectionId through SshExecutionContext and uses getGitExecutable(connectionId) to select the correct remote git binary per connection. |
| packages/core/src/host-dependencies/core-dependencies.ts | New file: defines GIT_DEPENDENCY_DESCRIPTOR and CORE_DEPENDENCIES array for git as a core (non-agent) dependency. |
| apps/emdash-desktop/src/main/core/utils/exec.test.ts | New test file covering GIT_PATH priority, PATH preference, invalid GIT_PATH fallthrough, Windows PATHEXT, local override, and per-connection remote overrides. |
| apps/emdash-desktop/src/main/core/runtime/legacy/ssh-git.ts | Threads connectionId into LegacySshGitRuntime so all internally created SshExecutionContexts carry the correct connection identity for git resolution. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant App as App startup
participant RM as RuntimeManager.acquire()
participant PGD as probeGitDependency()
participant DM as HostDependencyManager
participant SE as syncGitExecutable()
participant GE as getGitExecutable()
App->>RM: acquire(machine)
RM->>PGD: await probeGitDependency(machine)
PGD->>DM: getDependencyManager(connectionId)
DM-->>PGD: manager
PGD->>DM: await manager.probe('git')
DM->>DM: findExecutableOnPath('git') + version probe
DM->>DM: buildAndStoreHostDependency (awaited for core deps)
DM->>SE: onStatusUpdated.emit(event)
SE->>SE: resolveActiveInstallation()
SE->>GE: setGitExecutableOverride(path, connectionId)
DM-->>PGD: DependencyState
PGD-->>RM: (done)
RM->>RM: new LocalMachineRuntime() / SshMachineRuntime()
Note over RM,GE: GitRuntime now calls getGitExecutable() which returns the probed PATH git
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant App as App startup
participant RM as RuntimeManager.acquire()
participant PGD as probeGitDependency()
participant DM as HostDependencyManager
participant SE as syncGitExecutable()
participant GE as getGitExecutable()
App->>RM: acquire(machine)
RM->>PGD: await probeGitDependency(machine)
PGD->>DM: getDependencyManager(connectionId)
DM-->>PGD: manager
PGD->>DM: await manager.probe('git')
DM->>DM: findExecutableOnPath('git') + version probe
DM->>DM: buildAndStoreHostDependency (awaited for core deps)
DM->>SE: onStatusUpdated.emit(event)
SE->>SE: resolveActiveInstallation()
SE->>GE: setGitExecutableOverride(path, connectionId)
DM-->>PGD: DependencyState
PGD-->>RM: (done)
RM->>RM: new LocalMachineRuntime() / SshMachineRuntime()
Note over RM,GE: GitRuntime now calls getGitExecutable() which returns the probed PATH git
Reviews (4): Last reviewed commit: "fix(deps): clear ssh git override" | Re-trigger Greptile
|
@Davidknp would love for your feedback :) |
Description
gitfound onPATHbefore falling back on hardcoded git locationsGIT_PATHas highest-priority overrideScreenshot/Recording (if applicable)
(context: i updated my git path before this haha)
https://streamable.com/m4ee7h
Checklist
messages and, when possible, the PR title