diff --git a/pkg/commands/git_commands/repo_paths.go b/pkg/commands/git_commands/repo_paths.go index 0473f8f8e07..78c2dc8cf8c 100644 --- a/pkg/commands/git_commands/repo_paths.go +++ b/pkg/commands/git_commands/repo_paths.go @@ -2,7 +2,9 @@ package git_commands import ( "os" + "os/exec" "path/filepath" + "runtime" "strings" "github.com/go-errors/errors" @@ -298,5 +300,45 @@ func runGitRevParse(gitCmd *oscommands.CmdObj) (string, error) { if err != nil { return "", errors.Errorf("'%s' failed: %v", gitCmd.ToString(), err) } - return strings.TrimSpace(res), nil + + res = strings.TrimSpace(res) + + // On Windows, we may encounter Cygwin Git repos, which returns Unix + // paths which are illegible to Windows. Try running it through cygpath. + if runtime.GOOS == "windows" { + // Some callers pass in a command that produces newline delimited + // multiline output, e.g., multiple rev-parse args. + lines := strings.Split(res, "\n") + converted := false + for i, line := range lines { + // Relative paths should never trip in the first place, so guard + // this fallback with a prefix check. Guard is placed here and not + // earlier before splitting to avoid bailing too early in case + // callers produce both absolute and relative paths. + if strings.HasPrefix(line, "/") { + norm, err := exec.Command("cygpath", "-w", line).Output() + if err != nil { + // If cygpath doesn't exist, that's fine, just pray the + // original works, + if errors.Is(err, exec.ErrNotFound) { + return res, nil + } + + // but don't swallow other possibly interesting errors. + return "", errors.Errorf("'cygpath -w %s' failed: %v", line, err) + } + + lines[i] = strings.TrimSpace(string(norm)) + converted = true + } + } + + // Do not bother spending even more effort rejoining if we did not + // work on anything + if converted { + return strings.Join(lines, "\n"), nil + } + } + + return res, nil } diff --git a/pkg/commands/git_commands/worktree_loader_test.go b/pkg/commands/git_commands/worktree_loader_test.go index c537c6be4d7..7abfaf8399b 100644 --- a/pkg/commands/git_commands/worktree_loader_test.go +++ b/pkg/commands/git_commands/worktree_loader_test.go @@ -1,6 +1,7 @@ package git_commands import ( + "runtime" "testing" "github.com/go-errors/errors" @@ -11,6 +12,13 @@ import ( ) func TestGetWorktrees(t *testing.T) { + if runtime.GOOS == "windows" { + // Path conversion via cygpath is not pure and cannot be meaningfully + // tested, it is affected by and thus dependant on at least Cygwin + // install location and Cygwin /etc/fstab custom mounts, possibly more. + t.Skip("Skipping test on Windows") + } + type scenario struct { testName string repoPaths *RepoPaths