@@ -1680,6 +1680,13 @@ async fn managed_target_path(
16801680 format ! ( "Failed to resolve the managed worktree root: {io_error}" ) ,
16811681 )
16821682 } ) ?;
1683+ // `std::fs::canonicalize` (and Tokio's wrapper) returns a verbatim
1684+ // `\\?\C:\...` path on Windows. Git for Windows does not accept that form
1685+ // as a `worktree add` target after the Git adapter normalizes separators,
1686+ // because it becomes `//?/C:/...`. Keep the resolved path used for the
1687+ // containment checks, but prefer the ordinary drive-letter representation
1688+ // whenever it can address the same path.
1689+ let canonical_root = dunce:: simplified ( & canonical_root) . to_path_buf ( ) ;
16831690 let repository_root = canonical_root. join ( repository_id) ;
16841691 match tokio:: fs:: symlink_metadata ( & repository_root) . await {
16851692 Ok ( metadata) if metadata. file_type ( ) . is_symlink ( ) || !metadata. is_dir ( ) => {
@@ -1715,6 +1722,7 @@ async fn managed_target_path(
17151722 format ! ( "Failed to resolve the repository worktree root: {io_error}" ) ,
17161723 )
17171724 } ) ?;
1725+ let canonical_repository_root = dunce:: simplified ( & canonical_repository_root) . to_path_buf ( ) ;
17181726 if !canonical_repository_root. starts_with ( & canonical_root) {
17191727 return Err ( error (
17201728 WorktreeErrorCode :: InvalidPath ,
@@ -2092,6 +2100,32 @@ mod tests {
20922100 assert_eq ! ( collision. code, WorktreeErrorCode :: InvalidPath ) ;
20932101 }
20942102
2103+ #[ cfg( windows) ]
2104+ #[ tokio:: test]
2105+ async fn managed_target_path_is_compatible_with_git_for_windows ( ) {
2106+ let root = tempfile:: tempdir ( ) . expect ( "temp root" ) ;
2107+ let settings = WorktreeSettings {
2108+ root_path : root. path ( ) . join ( "managed-worktrees" ) . display ( ) . to_string ( ) ,
2109+ ..WorktreeSettings :: default ( )
2110+ } ;
2111+
2112+ let target = managed_target_path (
2113+ & settings,
2114+ "repository-id" ,
2115+ & root. path ( ) . join ( "projects/BitFun" ) ,
2116+ "48e8b457e87649aebf801b408698f46c" ,
2117+ )
2118+ . await
2119+ . expect ( "managed target path" ) ;
2120+ let git_argument = target. to_string_lossy ( ) . replace ( '\\' , "/" ) ;
2121+
2122+ assert ! (
2123+ !git_argument. starts_with( "//?/" ) ,
2124+ "managed worktree targets passed to Git must not use a Windows verbatim path: {}" ,
2125+ target. display( )
2126+ ) ;
2127+ }
2128+
20952129 #[ test]
20962130 fn managed_directory_name_falls_back_for_paths_without_a_project_name ( ) {
20972131 assert ! ( managed_worktree_directory_name(
0 commit comments