diff --git a/GitCommands/Git/GitModule.cs b/GitCommands/Git/GitModule.cs
index fdbb64cc372..f0eea67d689 100644
--- a/GitCommands/Git/GitModule.cs
+++ b/GitCommands/Git/GitModule.cs
@@ -67,7 +67,7 @@ public sealed class GitModule : IGitModule
public GitModule(string? workingDir)
{
- WorkingDir = (workingDir ?? "").NormalizePath().EnsureTrailingPathSeparator();
+ WorkingDir = (workingDir ?? "").NormalizePath().NormalizeWslPath().EnsureTrailingPathSeparator();
WorkingDirGitDir = GitDirectoryResolverInstance.Resolve(WorkingDir);
_indexLockManager = new IndexLockManager(this);
_commitDataManager = new CommitDataManager(() => this);
diff --git a/GitCommands/PathUtil.cs b/GitCommands/PathUtil.cs
index 4836136e61a..123f8376a31 100644
--- a/GitCommands/PathUtil.cs
+++ b/GitCommands/PathUtil.cs
@@ -11,6 +11,7 @@ public static class PathUtil
// Windows build 21354 supports wsl.localhost too, not supported for WSL Git
private const string WslPrefix = @"\\wsl$\";
+ private const string WslLocalhostPrefix = @"\\wsl.localhost\";
public static readonly char PosixDirectorySeparatorChar = '/';
public static readonly char NativeDirectorySeparatorChar = Path.DirectorySeparatorChar;
@@ -146,6 +147,23 @@ public static string NormalizePath(this string path)
}
}
+ ///
+ /// Replaces \\wsl.localhost\ with \\wsl$\, if found. Else returns the untouched.
+ ///
+ /// The path to normalize.
+ /// The WSL normalized path.
+ public static string NormalizeWslPath(this string path)
+ {
+ // NOTE: path is expected to be already normalized!
+
+ if (!IsWslLocalhostPrefixPath(path))
+ {
+ return path;
+ }
+
+ return path.Replace(WslLocalhostPrefix, WslPrefix, StringComparison.OrdinalIgnoreCase);
+ }
+
public static string Resolve(string path, string relativePath = "")
{
if (string.IsNullOrWhiteSpace(path))
@@ -198,23 +216,26 @@ private static string ResolveRelativePath(string path, string relativePath)
/// Check if the path is any known path for WSL that may require special handling
///
/// Path to check
- /// true if a path is a known WSL path
- public static bool IsWslPath(string path)
+ /// if a path is a known WSL path; otherwise, .
+ public static bool IsWslPath(string? path)
{
return !string.IsNullOrWhiteSpace(path)
- && (IsWslPrefixPath(path)
- || path.ToLower().StartsWith(@"\\wsl.localhost\"));
+ && (IsWslPrefixPath(path) || IsWslLocalhostPrefixPath(path));
}
+ ///
+ /// Check if the path starts with '\\wsl.localhost\'.
+ ///
+ /// Path to check
+ /// if the path starts with '\\wsl.localhost\'; otherwise, .
+ private static bool IsWslLocalhostPrefixPath(string path) => path.StartsWith(WslLocalhostPrefix, StringComparison.OrdinalIgnoreCase);
+
///
/// Check if the path is has handled specially for WSL
///
/// Path to check
- /// true if the path is a WSL path with internal handling
- private static bool IsWslPrefixPath(string path)
- {
- return path.ToLower().StartsWith(WslPrefix);
- }
+ /// if the path is a WSL path with internal handling; otherwise, .
+ private static bool IsWslPrefixPath(string path) => path.StartsWith(WslPrefix, StringComparison.OrdinalIgnoreCase);
///
/// Get the name of the distribution (like "Ubuntu-20.04") for WSL2 paths.
@@ -536,6 +557,7 @@ public static bool TryDeleteDirectory(this string? path, [NotNullWhen(returnValu
internal readonly struct TestAccessor
{
+ public static bool IsWslLocalhostPrefixPath(string path) => PathUtil.IsWslLocalhostPrefixPath(path);
public static bool IsWslPrefixPath(string path) => PathUtil.IsWslPrefixPath(path);
}
}
diff --git a/GitExtensions/Program.cs b/GitExtensions/Program.cs
index f57291df406..4388d3a6f75 100644
--- a/GitExtensions/Program.cs
+++ b/GitExtensions/Program.cs
@@ -34,12 +34,18 @@ private static void Main()
Application.SetCompatibleTextRenderingDefault(false);
Application.SetHighDpiMode(HighDpiMode.SystemAware);
+ bool checkForIllegalCrossThreadCalls = false;
+#if DEBUG
+ checkForIllegalCrossThreadCalls = true;
+#endif
if (ThisAssembly.Git.IsDirty)
{
- // In non official builds force to fail for cross-thread operations so we can fix those.
- Control.CheckForIllegalCrossThreadCalls = true;
+ checkForIllegalCrossThreadCalls = true;
}
+ // In non official builds force to fail for cross-thread operations so we can fix those.
+ Control.CheckForIllegalCrossThreadCalls = checkForIllegalCrossThreadCalls;
+
// If an error happens before we had a chance to init the environment information
// the call to GetInformation() from BugReporter.ShowNBug() will fail.
// There's no perf hit calling Initialise() multiple times.
diff --git a/UnitTests/GitCommands.Tests/Helpers/PathUtilTest.cs b/UnitTests/GitCommands.Tests/Helpers/PathUtilTest.cs
index 9dbd4525070..b159a4e48ac 100644
--- a/UnitTests/GitCommands.Tests/Helpers/PathUtilTest.cs
+++ b/UnitTests/GitCommands.Tests/Helpers/PathUtilTest.cs
@@ -177,16 +177,10 @@ public void GetRepositoryNameTest()
}
[Platform(Include = "Win")]
- [TestCase(null)]
- [TestCase("")]
- [TestCase(" ")]
- [TestCase("c:")]
- public void NormalizePath(string path)
- {
- PathUtil.NormalizePath(path).Should().BeEmpty();
- }
-
- [Platform(Include = "Win")]
+ [TestCase(null, "")]
+ [TestCase("", "")]
+ [TestCase(" ", "")]
+ [TestCase("c:", "")]
[TestCase("C:\\", "C:\\")]
[TestCase("a:\\folder\\filename.txt", "a:\\folder\\filename.txt")]
[TestCase("a:\\folder\\..\\filename.txt", "a:\\filename.txt")]
@@ -206,6 +200,19 @@ public void NormalizePath(string path, string expected)
PathUtil.NormalizePath(path).Should().Be(expected);
}
+ [Platform(Include = "Win")]
+ [TestCase("", "")]
+ [TestCase(" ", " ")]
+ [TestCase("c:", "c:")]
+ [TestCase("C:\\", "C:\\")]
+ [TestCase(@"\\wsl$\Ubuntu\home\jack\work\", @"\\wsl$\Ubuntu\home\jack\work\")]
+ [TestCase(@"\\Wsl.LoCALhosT\Ubuntu\home\jack\work\", @"\\wsl$\Ubuntu\home\jack\work\")]
+ [TestCase(@"\\wsl.localhost\Ubuntu\home\jack\work\", @"\\wsl$\Ubuntu\home\jack\work\")]
+ public void NormalizeWslPath(string path, string expected)
+ {
+ PathUtil.NormalizeWslPath(path).Should().Be(expected);
+ }
+
[TestCase(@"C:\WORK\GitExtensions\", @"C:\WORK\GitExtensions\")]
[TestCase(@"\\my-pc\Work\GitExtensions\", @"\\my-pc\Work\GitExtensions\")]
[TestCase(@"\\wsl$\Ubuntu\home\jack\work\", @"\\wsl$\Ubuntu\home\jack\work\")]
@@ -255,6 +262,15 @@ public void ResolveWsl(string input, Type expectedException)
Assert.Throws(expectedException, () => PathUtil.ResolveWsl(input));
}
+ [TestCase(@"C:\work\..\GitExtensions\", false)]
+ [TestCase(@"\\Wsl$\Ubuntu\work\..\GitExtensions\", false)]
+ [TestCase(@"\\wsl.localhost\Ubuntu\work\..\GitExtensions\", true)]
+ [TestCase(@"\\wsl.localhost/Ubuntu\work\..\GitExtensions\", false)]
+ public void IsWslLocalhostPath(string path, bool expected)
+ {
+ PathUtil.TestAccessor.IsWslLocalhostPrefixPath(path).Should().Be(expected);
+ }
+
[TestCase(@"\\Wsl$\Ubuntu\work\..\GitExtensions\", true, true)]
[TestCase(@"\\wsl$\Ubuntu\work\..\GitExtensions\", true, true)]
[TestCase(@"C:\work\..\GitExtensions\", false, false)]