Skip to content

fix(git): route git operations through wsl.exe for WSL UNC paths#314

Open
withabdul wants to merge 2 commits into
gnoviawan:devfrom
withabdul:fix/wsl-git-routing
Open

fix(git): route git operations through wsl.exe for WSL UNC paths#314
withabdul wants to merge 2 commits into
gnoviawan:devfrom
withabdul:fix/wsl-git-routing

Conversation

@withabdul

@withabdul withabdul commented Jun 6, 2026

Copy link
Copy Markdown

Summary

Routes git operations through wsl.exe when a project's CWD is a WSL UNC path (e.g. \\wsl.localhost\Ubuntu-24\home\user\project). Fixes the Git Changes sidebar panel showing zero entries on WSL projects, while leaving the branch indicator working.

Related Issue

None — discovered while using Termul on a Windows host with a project inside WSL.

Type of Change

  • fix: bug fix
  • test: adds or updates tests

What Changed

Problem: git rev-parse --abbrev-ref HEAD succeeds against a 9P UNC path (cheap metadata read), so the status bar shows the correct branch. git status --porcelain traverses the working tree and either times out at the 2s GIT_COMMAND_TIMEOUT_MS or returns empty, so git_get_status_detail returns an IPC error. The renderer's refreshStatus in git-status-store.ts has no try/catch toast, so the failure is silent and the sidebar shows "No changes detected".

Fix: Detect WSL UNC paths in git_tracker.rs and spawn git inside the WSL distro via wsl.exe -d <distro> --exec git -C <linux-path> <args>. Path translation uses wsl.exe -d <distro> --exec wslpath -u <windows-path>, cached per session in a OnceLock<Mutex<HashMap>> to amortise the WSL service cold-start cost. Effective timeout bumped to 8s on WSL paths. Non-WSL paths are unchanged — fast path-string check, falls through to existing Windows git.

New helpers (all #[cfg(target_os = "windows")]):

  • is_wsl_path / extract_wsl_distro — recognise \\wsl$\<distro>\ and \\wsl.localhost\<distro>\, case-insensitive prefix, distro case preserved.
  • wslpath_translatewslpath -u with caching.
  • pick_git_timeout_ms — 8s on WSL, requested on native.

run_git_command_with_timeout and run_git_push route through wsl.exe on WSL paths. WSL detected but wslpath fails → return None (no silent fallback to Windows git).

How It Was Tested

  • bun run lint (frontend; no changes)
  • bun run typecheck (frontend; no changes)
  • bun run test — Rust tests gated by #[cfg(target_os = "windows")]; cannot run in the development sandbox (target not installed). Should be run on a Windows host: cd src-tauri && cargo test --target x86_64-pc-windows-msvc.
  • Manual verification — needs a Windows host with WSL and a Termul project pointing at a WSL folder.

Manual verification steps:

  1. Add a project pointing at \\wsl.localhost\<distro>\home\<user>\<project>.
  2. Open a terminal in the project, confirm git status inside the WSL shell shows changes.
  3. Open the Git Changes sidebar — entries should now appear and refresh on file changes.
  4. Stage / unstage / commit / push from the sidebar should work end-to-end against the WSL-side working tree.

Screenshots or Recordings

Not applicable — UI behaviour change is the appearance of the existing (currently empty) Git Changes list. No new UI surfaces.

Checklist

  • My PR title follows the conventional commit format used by this repo (fix(git): ...)
  • I linked the related issue or explained why none exists (no upstream issue; discovered in local use)
  • I updated docs when needed (N/A — internal behaviour, no public API change)
  • I added or updated tests when needed (11 new unit tests for WSL path detection)
  • I verified the change does not introduce unrelated modifications (single file: src-tauri/src/trackers/git_tracker.rs)

Summary by CodeRabbit

  • Bug Fixes

    • Improved Git command execution for files on Windows WSL UNC paths, with better detection and path translation.
    • Enhanced timeout handling for WSL operations to accommodate cold-start latency and avoid inappropriate fallbacks.
    • Returns explicit failure when WSL translation fails instead of silently falling back to Windows-native Git.
  • Tests

    • Expanded Windows-only tests covering WSL path detection, distro extraction, and edge cases.

When a project points at a WSL folder via UNC path (e.g. \\wsl.localhost\Ubuntu-24\home\user\project), the branch indicator in the status bar worked but the Git Changes sidebar panel showed zero changes.

Root cause: 'git status --porcelain' against a 9P UNC share either times out (2s default) or returns empty output, so git_get_status_detail returns an IPC error. The renderer's refreshStatus does not toast on error, so the failure is silent.

Fix: detect WSL UNC paths and spawn git via 'wsl.exe -d <distro> --exec git -C <linux-path>' with wslpath -u translation (cached). Non-WSL paths unchanged. 8s timeout on WSL for cold-start tolerance.

Adds 11 unit tests for WSL path detection (case-insensitive, both UNC forms, distro case preservation, native/Unix rejection).
@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Complex PR? Review this PR in Change Stack to move by importance, not file order.

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 955a30f3-b003-4b43-beb9-d780c8f279a3

📥 Commits

Reviewing files that changed from the base of the PR and between 9ecdac6 and 10578df.

📒 Files selected for processing (1)
  • src-tauri/src/trackers/git_tracker.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src-tauri/src/trackers/git_tracker.rs

📝 Walkthrough

Walkthrough

Adds Windows handling for WSL UNC paths: detects/extracts distro names, caches wslpath -u translations, picks WSL-specific git timeouts, and routes git commands through wsl.exe (returning None on translation failure). Includes unit tests for UNC detection and extraction.

Changes

WSL Git Command Execution on Windows

Layer / File(s) Summary
WSL path detection and translation infrastructure
src-tauri/src/trackers/git_tracker.rs
Adds Mutex import, a WSL-specific timeout constant, a process-local cached wslpath -u translator (OnceLock<Mutex<HashMap<...>>>), and helpers is_wsl_path and extract_wsl_distro that recognize legacy (\\wsl$\<distro>\...) and modern (\\wsl.localhost\<distro>\...) UNC forms with case-insensitive prefix matching and preserved distro segment casing.
Git command routing and timeout selection
src-tauri/src/trackers/git_tracker.rs
Adds pick_git_timeout_ms to choose WSL timeouts for WSL UNC paths. Updates run_git_command_with_timeout to compute an effective timeout and, on Windows WSL paths, run wsl.exe -d <distro> --exec git -C <translated_linux_path> ...; translation failure after distro extraction yields None (no fallback to Windows git). Updates run_git_push to use the effective timeout, route WSL paths through wsl.exe (with GIT_TERMINAL_PROMPT=0), and pass effective_timeout to non-WSL spawns.
Unit tests for WSL path logic
src-tauri/src/trackers/git_tracker.rs
Adds Windows-only tests validating extract_wsl_distro and is_wsl_path across legacy/modern UNC formats, prefix case-insensitivity, distro-case preservation, malformed UNC shapes, native Windows/Unix rejections, and edge inputs.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant PathDetector
  participant PathTranslator
  participant TimeoutPicker
  participant WslExecution
  Caller->>PathDetector: request git operation with Windows path
  PathDetector->>PathDetector: is_wsl_path / extract_wsl_distro
  alt WSL path detected
    PathDetector->>PathTranslator: translate via wslpath -u (cached)
    alt Translation succeeds
      PathTranslator-->>PathDetector: Linux path
      PathDetector->>TimeoutPicker: pick_git_timeout_ms
      TimeoutPicker-->>PathDetector: effective timeout
      PathDetector->>WslExecution: wsl.exe -d <distro> --exec git -C <linux_path>
      WslExecution-->>Caller: command result
    else Translation fails
      PathTranslator-->>PathDetector: None
      PathDetector-->>Caller: None (log warning)
    end
  else Non-WSL path
    PathDetector->>TimeoutPicker: pick_git_timeout_ms
    TimeoutPicker-->>PathDetector: effective timeout
    PathDetector->>WslExecution: spawn Windows git with effective timeout
    WslExecution-->>Caller: command result
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

A rabbit hops through UNC lanes at night,
Translating paths to WSL's soft light,
It caches each wslpath to save the day,
Picks timeouts so git won't stall or stray,
And sings as wsl.exe carries code away. 🐰

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'fix(git): route git operations through wsl.exe for WSL UNC paths' directly and accurately captures the main change: routing git operations through WSL when working with WSL UNC paths.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src-tauri/src/trackers/git_tracker.rs (1)

236-242: 💤 Low value

Comment example is misleading.

The comment says it rejects \\wsl$\foo, but that path would have distro="foo" which is not empty. The code actually rejects \\wsl$\ (prefix with no distro segment). Consider updating the example:

-    // Distro name extends to the next path separator. Reject empty distro
-    // (`\\wsl$\foo`) and slices beyond the prefix.
+    // Distro name extends to the next path separator. Reject empty distro
+    // segment (e.g. `\\wsl$\` with nothing after the prefix).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-tauri/src/trackers/git_tracker.rs` around lines 236 - 242, Update the
misleading comment above the logic that extracts the distro (variables end,
after, distro): it currently claims it rejects `\\wsl$\foo` but the code would
accept that and actually rejects an empty distro like `\\wsl$\` (no segment
after the prefix); change the example in the comment to `\\wsl$\` (or similar
showing a trailing separator with no distro) and adjust wording to state it
rejects an empty distro segment rather than `\\wsl$\foo`.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src-tauri/src/trackers/git_tracker.rs`:
- Around line 827-848: The GIT_TERMINAL_PROMPT env currently set on the wsl.exe
process won't be passed into the Linux git; change the constructed command so
the env is set inside WSL by invoking env before git (e.g., use
backend_command("wsl.exe") with .args([... "--exec", "env",
"GIT_TERMINAL_PROMPT=0", "git", "-C", &linux_path]) instead of
.env("GIT_TERMINAL_PROMPT","0"); update the block that builds the command in the
WSL branch (where extract_wsl_distro, wslpath_translate, backend_command and
Self::spawn_and_wait are used) so the env assignment is part of the --exec
arguments.

---

Nitpick comments:
In `@src-tauri/src/trackers/git_tracker.rs`:
- Around line 236-242: Update the misleading comment above the logic that
extracts the distro (variables end, after, distro): it currently claims it
rejects `\\wsl$\foo` but the code would accept that and actually rejects an
empty distro like `\\wsl$\` (no segment after the prefix); change the example in
the comment to `\\wsl$\` (or similar showing a trailing separator with no
distro) and adjust wording to state it rejects an empty distro segment rather
than `\\wsl$\foo`.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4d413980-2f38-4428-98df-0b4f4fb88318

📥 Commits

Reviewing files that changed from the base of the PR and between 39ab564 and 9ecdac6.

📒 Files selected for processing (1)
  • src-tauri/src/trackers/git_tracker.rs

Comment thread src-tauri/src/trackers/git_tracker.rs
The previous patch set GIT_TERMINAL_PROMPT=0 on the wsl.exe Windows process
via .env(), but wsl.exe only forwards a small set of well-known env vars to
the Linux side; arbitrary ones (including GIT_TERMINAL_PROMPT) never reach
git running inside the WSL distro. As a result, git push on a WSL project
could still block on a credentials prompt at the 2s default timeout instead
of failing fast.

Move the env assignment into the --exec invocation so it is set on the
Linux side: 'wsl.exe --exec env GIT_TERMINAL_PROMPT=0 git ...'. The
non-WSL Windows branch is unchanged — .env() on a Windows process is the
correct way to set env for a Windows child.
@gnoviawan

gnoviawan commented Jun 14, 2026

Copy link
Copy Markdown
Owner

Hey @withabdul — triage update 🔁

Mergeable, but CI is red: Rust Checks (fails cargo check — unclosed delimiter in termul-manager) and Rust Windows Smoke Check are failing.
https://github.com/gnoviawan/termul/actions/runs/27056466160

The branch appears out of sync with dev; please rebase onto dev and re-run.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants