From 699a65e042cfc4287eee12e360188374405a999b Mon Sep 17 00:00:00 2001 From: JoeJoeflyn Date: Thu, 30 Jul 2026 17:19:08 +0700 Subject: [PATCH] fix(desktop): strip Windows extended-path prefix before git clone (#3707) Signed-off-by: JoeJoeflyn --- desktop/src-tauri/Cargo.lock | 1 + desktop/src-tauri/Cargo.toml | 1 + .../src/commands/project_git_workflow.rs | 4 ++-- .../src/commands/project_repo_paths.rs | 24 ++++++++++++++++++- 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock index 5835f8b39b..fd8f92cba2 100644 --- a/desktop/src-tauri/Cargo.lock +++ b/desktop/src-tauri/Cargo.lock @@ -1026,6 +1026,7 @@ dependencies = [ "chrono", "ctrlc", "dirs", + "dunce", "earshot", "ed25519-dalek", "flate2", diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml index 9db907db3f..f7fb1cec8b 100644 --- a/desktop/src-tauri/Cargo.toml +++ b/desktop/src-tauri/Cargo.toml @@ -58,6 +58,7 @@ user-idle = { version = "0.6", default-features = false } atomic-write-file = "0.3" anyhow = "1" dirs = "6" +dunce = "1" tauri = { version = "2", features = ["macos-private-api"] } tauri-plugin-deep-link = "2" tauri-plugin-opener = "2" diff --git a/desktop/src-tauri/src/commands/project_git_workflow.rs b/desktop/src-tauri/src/commands/project_git_workflow.rs index 39832feb10..3317e0fa5e 100644 --- a/desktop/src-tauri/src/commands/project_git_workflow.rs +++ b/desktop/src-tauri/src/commands/project_git_workflow.rs @@ -8,7 +8,7 @@ use super::project_git_exec::{ }; use super::project_repo_paths::{ canonical_repos_roots, canonicalize_repos_root, default_repos_root_candidates, - find_local_repo_dir, local_repo_candidates, + find_local_repo_dir, local_repo_candidates, strip_extended_path_prefix, }; use crate::app_state::AppState; use crate::managed_agents::{load_managed_agents, spawn_key_refusal}; @@ -425,7 +425,7 @@ pub(crate) fn clone_project_repository_blocking( .into_iter() .next() .ok_or_else(|| "Could not derive a directory name for the repository.".to_string())?; - let repo_dir = repos_root.join(repo_name); + let repo_dir = strip_extended_path_prefix(&repos_root.join(repo_name)); if repo_dir.exists() { return Err(format!( "{} already exists but is not a git checkout.", diff --git a/desktop/src-tauri/src/commands/project_repo_paths.rs b/desktop/src-tauri/src/commands/project_repo_paths.rs index 4193327c01..6797c205ce 100644 --- a/desktop/src-tauri/src/commands/project_repo_paths.rs +++ b/desktop/src-tauri/src/commands/project_repo_paths.rs @@ -137,7 +137,7 @@ pub(crate) fn find_local_repo_dir( .map(|url| checkout_origin_matches(&candidate_path, &repos_root, url)) .unwrap_or(true) { - return Ok(Some(candidate_path)); + return Ok(Some(strip_extended_path_prefix(&candidate_path))); } } } @@ -170,6 +170,16 @@ pub(crate) fn canonicalize_repos_root( Ok(repos_root) } +/// Strip the Windows extended-length path prefix (`\\?\`) that +/// `PathBuf::canonicalize()` adds on Windows. Git for Windows rejects +/// `\\?\`-prefixed destinations, so canonical paths must be cleaned before +/// being passed to the git CLI. +pub(crate) fn strip_extended_path_prefix( + path: &std::path::Path, +) -> std::path::PathBuf { + dunce::simplified(path).to_path_buf() +} + pub(crate) fn canonical_repos_roots( repos_dir: Option<&str>, ) -> Result, String> { @@ -190,3 +200,15 @@ pub(crate) fn canonical_repos_roots( } Ok(roots) } + +#[cfg(test)] +mod tests { + use super::strip_extended_path_prefix; + use std::path::PathBuf; + + #[test] + fn strip_extended_path_prefix_leaves_normal_path_untouched() { + let path = PathBuf::from("/home/james/.buzz/REPOS/owner--repo"); + assert_eq!(strip_extended_path_prefix(&path), path); + } +}