git: Fix staging file hunks on Windows (#26661)

CharlesChen0823 and 张小白 created

Closes #26458 

I had checked, and also reference the implementation in vscode.

Release Notes:

- N/A

---------

Co-authored-by: 张小白 <364772080@qq.com>

Change summary

crates/git/src/repository.rs | 23 +++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)

Detailed changes

crates/git/src/repository.rs 🔗

@@ -10,7 +10,8 @@ use parking_lot::Mutex;
 use rope::Rope;
 use schemars::JsonSchema;
 use serde::Deserialize;
-use std::borrow::Borrow;
+use std::borrow::{Borrow, Cow};
+use std::ffi::OsStr;
 use std::future;
 use std::path::Component;
 use std::process::{ExitStatus, Stdio};
@@ -550,7 +551,7 @@ impl GitRepository for RealGitRepository {
                     .current_dir(&working_directory)
                     .envs(env)
                     .args(["update-index", "--add", "--cacheinfo", "100644", &sha])
-                    .arg(path.as_ref())
+                    .arg(path.to_unix_style())
                     .output()
                     .await?;
 
@@ -565,7 +566,7 @@ impl GitRepository for RealGitRepository {
                     .current_dir(&working_directory)
                     .envs(env)
                     .args(["update-index", "--force-remove"])
-                    .arg(path.as_ref())
+                    .arg(path.to_unix_style())
                     .output()
                     .await?;
 
@@ -779,7 +780,7 @@ impl GitRepository for RealGitRepository {
                     .current_dir(&working_directory?)
                     .envs(env)
                     .args(["update-index", "--add", "--remove", "--"])
-                    .args(paths.iter().map(|p| p.as_ref()))
+                    .args(paths.iter().map(|p| p.to_unix_style()))
                     .output()
                     .await?;
 
@@ -1336,6 +1337,20 @@ impl RepoPath {
 
         RepoPath(path.into())
     }
+
+    pub fn to_unix_style(&self) -> Cow<'_, OsStr> {
+        #[cfg(target_os = "windows")]
+        {
+            use std::ffi::OsString;
+
+            let path = self.0.as_os_str().to_string_lossy().replace("\\", "/");
+            Cow::Owned(OsString::from(path))
+        }
+        #[cfg(not(target_os = "windows"))]
+        {
+            Cow::Borrowed(self.0.as_os_str())
+        }
+    }
 }
 
 impl std::fmt::Display for RepoPath {