mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-05-12 21:05:48 +02:00
Refactor repo_paths.go to use git rev-parse
This changes GetRepoPaths() to pull information from `git rev-parse` instead of effectively reimplementing git's logic for pathfinding. This change fixes issues with bare repos, esp. versioned homedir use cases, by aligning lazygit's path handling to what git itself does. This change also enables lazygit to run from arbitrary subdirectories of a repository, including correct handling of symlinks, including "deep" symlinks into a repo, worktree, a repo's submodules, etc. Integration tests are now resilient against unintended side effects from the host's environment variables. Of necessity, $PATH and $TERM are the only env vars allowed through now.
This commit is contained in:
parent
74d937881e
commit
3d9f1e02e5
25 changed files with 590 additions and 442 deletions
|
@ -250,6 +250,7 @@ func (self *CommitCommands) ShowCmdObj(sha string, filterPath string) oscommands
|
|||
Arg(sha).
|
||||
ArgIf(self.AppState.IgnoreWhitespaceInDiffView, "--ignore-all-space").
|
||||
ArgIf(filterPath != "", "--", filterPath).
|
||||
Dir(self.repoPaths.worktreePath).
|
||||
ToArgv()
|
||||
|
||||
return self.cmd.New(cmdArgs).DontLog()
|
||||
|
|
|
@ -197,7 +197,7 @@ func TestCommitShowCmdObj(t *testing.T) {
|
|||
contextSize: 3,
|
||||
ignoreWhitespace: false,
|
||||
extDiffCmd: "",
|
||||
expected: []string{"show", "--no-ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890"},
|
||||
expected: []string{"-C", "/path/to/worktree", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890"},
|
||||
},
|
||||
{
|
||||
testName: "Default case with filter path",
|
||||
|
@ -205,7 +205,7 @@ func TestCommitShowCmdObj(t *testing.T) {
|
|||
contextSize: 3,
|
||||
ignoreWhitespace: false,
|
||||
extDiffCmd: "",
|
||||
expected: []string{"show", "--no-ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--", "file.txt"},
|
||||
expected: []string{"-C", "/path/to/worktree", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--", "file.txt"},
|
||||
},
|
||||
{
|
||||
testName: "Show diff with custom context size",
|
||||
|
@ -213,7 +213,7 @@ func TestCommitShowCmdObj(t *testing.T) {
|
|||
contextSize: 77,
|
||||
ignoreWhitespace: false,
|
||||
extDiffCmd: "",
|
||||
expected: []string{"show", "--no-ext-diff", "--submodule", "--color=always", "--unified=77", "--stat", "--decorate", "-p", "1234567890"},
|
||||
expected: []string{"-C", "/path/to/worktree", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=77", "--stat", "--decorate", "-p", "1234567890"},
|
||||
},
|
||||
{
|
||||
testName: "Show diff, ignoring whitespace",
|
||||
|
@ -221,7 +221,7 @@ func TestCommitShowCmdObj(t *testing.T) {
|
|||
contextSize: 77,
|
||||
ignoreWhitespace: true,
|
||||
extDiffCmd: "",
|
||||
expected: []string{"show", "--no-ext-diff", "--submodule", "--color=always", "--unified=77", "--stat", "--decorate", "-p", "1234567890", "--ignore-all-space"},
|
||||
expected: []string{"-C", "/path/to/worktree", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=77", "--stat", "--decorate", "-p", "1234567890", "--ignore-all-space"},
|
||||
},
|
||||
{
|
||||
testName: "Show diff with external diff command",
|
||||
|
@ -229,7 +229,7 @@ func TestCommitShowCmdObj(t *testing.T) {
|
|||
contextSize: 3,
|
||||
ignoreWhitespace: false,
|
||||
extDiffCmd: "difft --color=always",
|
||||
expected: []string{"-c", "diff.external=difft --color=always", "show", "--ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890"},
|
||||
expected: []string{"-C", "/path/to/worktree", "-c", "diff.external=difft --color=always", "show", "--ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890"},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -243,7 +243,10 @@ func TestCommitShowCmdObj(t *testing.T) {
|
|||
appState.DiffContextSize = s.contextSize
|
||||
|
||||
runner := oscommands.NewFakeRunner(t).ExpectGitArgs(s.expected, "", nil)
|
||||
instance := buildCommitCommands(commonDeps{userConfig: userConfig, appState: appState, runner: runner})
|
||||
repoPaths := RepoPaths{
|
||||
worktreePath: "/path/to/worktree",
|
||||
}
|
||||
instance := buildCommitCommands(commonDeps{userConfig: userConfig, appState: appState, runner: runner, repoPaths: &repoPaths})
|
||||
|
||||
assert.NoError(t, instance.ShowCmdObj("1234567890", s.filterPath).Run())
|
||||
runner.CheckForMissingCalls()
|
||||
|
|
|
@ -14,14 +14,19 @@ func NewDiffCommands(gitCommon *GitCommon) *DiffCommands {
|
|||
|
||||
func (self *DiffCommands) DiffCmdObj(diffArgs []string) oscommands.ICmdObj {
|
||||
return self.cmd.New(
|
||||
NewGitCmd("diff").Arg("--submodule", "--no-ext-diff", "--color").Arg(diffArgs...).ToArgv(),
|
||||
NewGitCmd("diff").
|
||||
Arg("--submodule", "--no-ext-diff", "--color").
|
||||
Arg(diffArgs...).
|
||||
Dir(self.repoPaths.worktreePath).
|
||||
ToArgv(),
|
||||
)
|
||||
}
|
||||
|
||||
func (self *DiffCommands) internalDiffCmdObj(diffArgs ...string) *GitCommandBuilder {
|
||||
return NewGitCmd("diff").
|
||||
Arg("--no-ext-diff", "--no-color").
|
||||
Arg(diffArgs...)
|
||||
Arg(diffArgs...).
|
||||
Dir(self.repoPaths.worktreePath)
|
||||
}
|
||||
|
||||
func (self *DiffCommands) GetPathDiff(path string, staged bool) (string, error) {
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
package git_commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
ioFs "io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/jesseduffield/lazygit/pkg/env"
|
||||
"github.com/samber/lo"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
type RepoPaths struct {
|
||||
currentPath string
|
||||
worktreePath string
|
||||
worktreeGitDirPath string
|
||||
repoPath string
|
||||
|
@ -23,12 +20,7 @@ type RepoPaths struct {
|
|||
repoName string
|
||||
}
|
||||
|
||||
// Current working directory of the program. Currently, this will always
|
||||
// be the same as WorktreePath(), but in future we may support running
|
||||
// lazygit from inside a subdirectory of the worktree.
|
||||
func (self *RepoPaths) CurrentPath() string {
|
||||
return self.currentPath
|
||||
}
|
||||
var gitPathFormatVersion GitVersion = GitVersion{2, 31, 0, ""}
|
||||
|
||||
// Path to the current worktree. If we're in the main worktree, this will
|
||||
// be the same as RepoPath()
|
||||
|
@ -65,7 +57,6 @@ func (self *RepoPaths) RepoName() string {
|
|||
// Returns the repo paths for a typical repo
|
||||
func MockRepoPaths(currentPath string) *RepoPaths {
|
||||
return &RepoPaths{
|
||||
currentPath: currentPath,
|
||||
worktreePath: currentPath,
|
||||
worktreeGitDirPath: path.Join(currentPath, ".git"),
|
||||
repoPath: currentPath,
|
||||
|
@ -75,44 +66,41 @@ func MockRepoPaths(currentPath string) *RepoPaths {
|
|||
}
|
||||
|
||||
func GetRepoPaths(
|
||||
fs afero.Fs,
|
||||
currentPath string,
|
||||
cmd oscommands.ICmdObjBuilder,
|
||||
version *GitVersion,
|
||||
) (*RepoPaths, error) {
|
||||
return getRepoPathsAux(afero.NewOsFs(), resolveSymlink, currentPath)
|
||||
}
|
||||
|
||||
func getRepoPathsAux(
|
||||
fs afero.Fs,
|
||||
resolveSymlinkFn func(string) (string, error),
|
||||
currentPath string,
|
||||
) (*RepoPaths, error) {
|
||||
worktreePath := currentPath
|
||||
repoGitDirPath, repoPath, err := getCurrentRepoGitDirPath(fs, resolveSymlinkFn, currentPath)
|
||||
gitDirOutput, err := callGitRevParse(cmd, version, "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--show-superproject-working-tree")
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("failed to get repo git dir path: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var worktreeGitDirPath string
|
||||
if env.GetWorkTreeEnv() != "" {
|
||||
// This env is set when you pass --work-tree to lazygit. In that case,
|
||||
// we're not dealing with a linked work-tree, we're dealing with a 'specified'
|
||||
// worktree (for lack of a better term). In this case, the worktree has no
|
||||
// .git file and it just contains a bunch of files: it has no idea it's
|
||||
// pointed to by a bare repo. As such it does not have its own git dir within
|
||||
// the bare repo's git dir. Instead, we just use the bare repo's git dir.
|
||||
worktreeGitDirPath = repoGitDirPath
|
||||
} else {
|
||||
var err error
|
||||
worktreeGitDirPath, err = getWorktreeGitDirPath(fs, currentPath)
|
||||
gitDirResults := strings.Split(utils.NormalizeLinefeeds(gitDirOutput), "\n")
|
||||
worktreePath := gitDirResults[0]
|
||||
worktreeGitDirPath := gitDirResults[1]
|
||||
repoGitDirPath := gitDirResults[2]
|
||||
if version.IsOlderThanVersion(&gitPathFormatVersion) {
|
||||
repoGitDirPath, err = filepath.Abs(repoGitDirPath)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("failed to get worktree git dir path: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// If we're in a submodule, --show-superproject-working-tree will return
|
||||
// a value, meaning gitDirResults will be length 4. In that case
|
||||
// return the worktree path as the repoPath. Otherwise we're in a
|
||||
// normal repo or a worktree so return the parent of the git common
|
||||
// dir (repoGitDirPath)
|
||||
isSubmodule := len(gitDirResults) == 4
|
||||
|
||||
var repoPath string
|
||||
if isSubmodule {
|
||||
repoPath = worktreePath
|
||||
} else {
|
||||
repoPath = path.Dir(repoGitDirPath)
|
||||
}
|
||||
repoName := path.Base(repoPath)
|
||||
|
||||
return &RepoPaths{
|
||||
currentPath: currentPath,
|
||||
worktreePath: worktreePath,
|
||||
worktreeGitDirPath: worktreeGitDirPath,
|
||||
repoPath: repoPath,
|
||||
|
@ -121,124 +109,31 @@ func getRepoPathsAux(
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Returns the path of the git-dir for the worktree. For linked worktrees, the worktree has
|
||||
// a .git file that points to the git-dir (which itself lives in the git-dir
|
||||
// of the repo)
|
||||
func getWorktreeGitDirPath(fs afero.Fs, worktreePath string) (string, error) {
|
||||
// if .git is a file, we're in a linked worktree, otherwise we're in
|
||||
// the main worktree
|
||||
dotGitPath := path.Join(worktreePath, ".git")
|
||||
gitFileInfo, err := fs.Stat(dotGitPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if gitFileInfo.IsDir() {
|
||||
return dotGitPath, nil
|
||||
}
|
||||
|
||||
return linkedWorktreeGitDirPath(fs, worktreePath)
|
||||
func callGitRevParse(
|
||||
cmd oscommands.ICmdObjBuilder,
|
||||
version *GitVersion,
|
||||
gitRevArgs ...string,
|
||||
) (string, error) {
|
||||
return callGitRevParseWithDir(cmd, version, "", gitRevArgs...)
|
||||
}
|
||||
|
||||
func linkedWorktreeGitDirPath(fs afero.Fs, worktreePath string) (string, error) {
|
||||
dotGitPath := path.Join(worktreePath, ".git")
|
||||
gitFileContents, err := afero.ReadFile(fs, dotGitPath)
|
||||
func callGitRevParseWithDir(
|
||||
cmd oscommands.ICmdObjBuilder,
|
||||
version *GitVersion,
|
||||
dir string,
|
||||
gitRevArgs ...string,
|
||||
) (string, error) {
|
||||
gitRevParse := NewGitCmd("rev-parse").ArgIf(version.IsAtLeastVersion(&gitPathFormatVersion), "--path-format=absolute").Arg(gitRevArgs...)
|
||||
if dir != "" {
|
||||
gitRevParse.Dir(dir)
|
||||
}
|
||||
|
||||
gitCmd := cmd.New(gitRevParse.ToArgv()).DontLog()
|
||||
res, err := gitCmd.RunWithOutput()
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", errors.Errorf("'%s' failed: %v", gitCmd.ToString(), err)
|
||||
}
|
||||
|
||||
// The file will have `gitdir: /path/to/.git/worktrees/<worktree-name>`
|
||||
gitDirLine := lo.Filter(strings.Split(string(gitFileContents), "\n"), func(line string, _ int) bool {
|
||||
return strings.HasPrefix(line, "gitdir: ")
|
||||
})
|
||||
|
||||
if len(gitDirLine) == 0 {
|
||||
return "", errors.New(fmt.Sprintf("%s is a file which suggests we are in a submodule or a worktree but the file's contents do not contain a gitdir pointing to the actual .git directory", dotGitPath))
|
||||
}
|
||||
|
||||
gitDir := strings.TrimPrefix(gitDirLine[0], "gitdir: ")
|
||||
|
||||
gitDir = filepath.Clean(gitDir)
|
||||
// For windows support
|
||||
gitDir = filepath.ToSlash(gitDir)
|
||||
|
||||
return gitDir, nil
|
||||
}
|
||||
|
||||
func getCurrentRepoGitDirPath(
|
||||
fs afero.Fs,
|
||||
resolveSymlinkFn func(string) (string, error),
|
||||
currentPath string,
|
||||
) (string, string, error) {
|
||||
var unresolvedGitPath string
|
||||
if env.GetGitDirEnv() != "" {
|
||||
unresolvedGitPath = env.GetGitDirEnv()
|
||||
} else {
|
||||
unresolvedGitPath = path.Join(currentPath, ".git")
|
||||
}
|
||||
|
||||
gitPath, err := resolveSymlinkFn(unresolvedGitPath)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
// check if .git is a file or a directory
|
||||
gitFileInfo, err := fs.Stat(gitPath)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
if gitFileInfo.IsDir() {
|
||||
// must be in the main worktree
|
||||
return gitPath, path.Dir(gitPath), nil
|
||||
}
|
||||
|
||||
// either in a submodule, or worktree
|
||||
worktreeGitPath, err := linkedWorktreeGitDirPath(fs, currentPath)
|
||||
if err != nil {
|
||||
return "", "", errors.Errorf("could not find git dir for %s: %v", currentPath, err)
|
||||
}
|
||||
|
||||
_, err = fs.Stat(worktreeGitPath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
// hardcoding error to get around windows-specific error message
|
||||
return "", "", errors.Errorf("could not find git dir for %s. %s does not exist", currentPath, worktreeGitPath)
|
||||
}
|
||||
return "", "", errors.Errorf("could not find git dir for %s: %v", currentPath, err)
|
||||
}
|
||||
|
||||
// confirm whether the next directory up is the worktrees directory
|
||||
parent := path.Dir(worktreeGitPath)
|
||||
if path.Base(parent) == "worktrees" {
|
||||
gitDirPath := path.Dir(parent)
|
||||
return gitDirPath, path.Dir(gitDirPath), nil
|
||||
}
|
||||
|
||||
// Unlike worktrees, submodules can be nested arbitrarily deep, so we check
|
||||
// if the `modules` directory is anywhere up the chain.
|
||||
if strings.Contains(worktreeGitPath, "/modules/") {
|
||||
// For submodules, we just return the path directly
|
||||
return worktreeGitPath, currentPath, nil
|
||||
}
|
||||
|
||||
// If this error causes issues, we could relax the constraint and just always
|
||||
// return the path
|
||||
return "", "", errors.Errorf("could not find git dir for %s: the path '%s' is not under `worktrees` or `modules` directories", currentPath, worktreeGitPath)
|
||||
}
|
||||
|
||||
// takes a path containing a symlink and returns the true path
|
||||
func resolveSymlink(path string) (string, error) {
|
||||
l, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if l.Mode()&os.ModeSymlink == 0 {
|
||||
return path, nil
|
||||
}
|
||||
|
||||
return filepath.EvalSymlinks(path)
|
||||
return strings.TrimSpace(res), nil
|
||||
}
|
||||
|
||||
// Returns the paths of linked worktrees
|
||||
|
|
|
@ -1,34 +1,50 @@
|
|||
package git_commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func mockResolveSymlinkFn(p string) (string, error) { return p, nil }
|
||||
type (
|
||||
argFn func() []string
|
||||
errFn func(getRevParseArgs argFn) error
|
||||
)
|
||||
|
||||
type Scenario struct {
|
||||
Name string
|
||||
BeforeFunc func(fs afero.Fs)
|
||||
BeforeFunc func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn)
|
||||
Path string
|
||||
Expected *RepoPaths
|
||||
Err error
|
||||
Err errFn
|
||||
}
|
||||
|
||||
func TestGetRepoPathsAux(t *testing.T) {
|
||||
func TestGetRepoPaths(t *testing.T) {
|
||||
scenarios := []Scenario{
|
||||
{
|
||||
Name: "typical case",
|
||||
BeforeFunc: func(fs afero.Fs) {
|
||||
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
|
||||
// setup for main worktree
|
||||
_ = fs.MkdirAll("/path/to/repo/.git", 0o755)
|
||||
expectedOutput := []string{
|
||||
// --show-toplevel
|
||||
"/path/to/repo",
|
||||
// --git-dir
|
||||
"/path/to/repo/.git",
|
||||
// --git-common-dir
|
||||
"/path/to/repo/.git",
|
||||
// --show-superproject-working-tree
|
||||
}
|
||||
runner.ExpectGitArgs(
|
||||
append(getRevParseArgs(), "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--show-superproject-working-tree"),
|
||||
strings.Join(expectedOutput, "\n"),
|
||||
nil)
|
||||
},
|
||||
Path: "/path/to/repo",
|
||||
Expected: &RepoPaths{
|
||||
currentPath: "/path/to/repo",
|
||||
worktreePath: "/path/to/repo",
|
||||
worktreeGitDirPath: "/path/to/repo/.git",
|
||||
repoPath: "/path/to/repo",
|
||||
|
@ -37,71 +53,26 @@ func TestGetRepoPathsAux(t *testing.T) {
|
|||
},
|
||||
Err: nil,
|
||||
},
|
||||
{
|
||||
Name: "linked worktree",
|
||||
BeforeFunc: func(fs afero.Fs) {
|
||||
// setup for linked worktree
|
||||
_ = fs.MkdirAll("/path/to/repo/.git/worktrees/worktree1", 0o755)
|
||||
_ = afero.WriteFile(fs, "/path/to/repo/worktree1/.git", []byte("gitdir: /path/to/repo/.git/worktrees/worktree1"), 0o644)
|
||||
},
|
||||
Path: "/path/to/repo/worktree1",
|
||||
Expected: &RepoPaths{
|
||||
currentPath: "/path/to/repo/worktree1",
|
||||
worktreePath: "/path/to/repo/worktree1",
|
||||
worktreeGitDirPath: "/path/to/repo/.git/worktrees/worktree1",
|
||||
repoPath: "/path/to/repo",
|
||||
repoGitDirPath: "/path/to/repo/.git",
|
||||
repoName: "repo",
|
||||
},
|
||||
Err: nil,
|
||||
},
|
||||
{
|
||||
Name: "worktree with trailing separator in path",
|
||||
BeforeFunc: func(fs afero.Fs) {
|
||||
// setup for linked worktree
|
||||
_ = fs.MkdirAll("/path/to/repo/.git/worktrees/worktree1", 0o755)
|
||||
_ = afero.WriteFile(fs, "/path/to/repo/worktree1/.git", []byte("gitdir: /path/to/repo/.git/worktrees/worktree1/"), 0o644)
|
||||
},
|
||||
Path: "/path/to/repo/worktree1",
|
||||
Expected: &RepoPaths{
|
||||
currentPath: "/path/to/repo/worktree1",
|
||||
worktreePath: "/path/to/repo/worktree1",
|
||||
worktreeGitDirPath: "/path/to/repo/.git/worktrees/worktree1",
|
||||
repoPath: "/path/to/repo",
|
||||
repoGitDirPath: "/path/to/repo/.git",
|
||||
repoName: "repo",
|
||||
},
|
||||
Err: nil,
|
||||
},
|
||||
{
|
||||
Name: "worktree .git file missing gitdir directive",
|
||||
BeforeFunc: func(fs afero.Fs) {
|
||||
_ = fs.MkdirAll("/path/to/repo/.git/worktrees/worktree2", 0o755)
|
||||
_ = afero.WriteFile(fs, "/path/to/repo/worktree2/.git", []byte("blah"), 0o644)
|
||||
},
|
||||
Path: "/path/to/repo/worktree2",
|
||||
Expected: nil,
|
||||
Err: errors.New("failed to get repo git dir path: could not find git dir for /path/to/repo/worktree2: /path/to/repo/worktree2/.git is a file which suggests we are in a submodule or a worktree but the file's contents do not contain a gitdir pointing to the actual .git directory"),
|
||||
},
|
||||
{
|
||||
Name: "worktree .git file gitdir directive points to a non-existing directory",
|
||||
BeforeFunc: func(fs afero.Fs) {
|
||||
_ = fs.MkdirAll("/path/to/repo/.git/worktrees/worktree2", 0o755)
|
||||
_ = afero.WriteFile(fs, "/path/to/repo/worktree2/.git", []byte("gitdir: /nonexistant"), 0o644)
|
||||
},
|
||||
Path: "/path/to/repo/worktree2",
|
||||
Expected: nil,
|
||||
Err: errors.New("failed to get repo git dir path: could not find git dir for /path/to/repo/worktree2. /nonexistant does not exist"),
|
||||
},
|
||||
{
|
||||
Name: "submodule",
|
||||
BeforeFunc: func(fs afero.Fs) {
|
||||
_ = fs.MkdirAll("/path/to/repo/.git/modules/submodule1", 0o755)
|
||||
_ = afero.WriteFile(fs, "/path/to/repo/submodule1/.git", []byte("gitdir: /path/to/repo/.git/modules/submodule1"), 0o644)
|
||||
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
|
||||
expectedOutput := []string{
|
||||
// --show-toplevel
|
||||
"/path/to/repo/submodule1",
|
||||
// --git-dir
|
||||
"/path/to/repo/.git/modules/submodule1",
|
||||
// --git-common-dir
|
||||
"/path/to/repo/.git/modules/submodule1",
|
||||
// --show-superproject-working-tree
|
||||
"/path/to/repo",
|
||||
}
|
||||
runner.ExpectGitArgs(
|
||||
append(getRevParseArgs(), "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--show-superproject-working-tree"),
|
||||
strings.Join(expectedOutput, "\n"),
|
||||
nil)
|
||||
},
|
||||
Path: "/path/to/repo/submodule1",
|
||||
Expected: &RepoPaths{
|
||||
currentPath: "/path/to/repo/submodule1",
|
||||
worktreePath: "/path/to/repo/submodule1",
|
||||
worktreeGitDirPath: "/path/to/repo/.git/modules/submodule1",
|
||||
repoPath: "/path/to/repo/submodule1",
|
||||
|
@ -111,49 +82,52 @@ func TestGetRepoPathsAux(t *testing.T) {
|
|||
Err: nil,
|
||||
},
|
||||
{
|
||||
Name: "submodule in nested directory",
|
||||
BeforeFunc: func(fs afero.Fs) {
|
||||
_ = fs.MkdirAll("/path/to/repo/.git/modules/my/submodule1", 0o755)
|
||||
_ = afero.WriteFile(fs, "/path/to/repo/my/submodule1/.git", []byte("gitdir: /path/to/repo/.git/modules/my/submodule1"), 0o644)
|
||||
Name: "git rev-parse returns an error",
|
||||
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
|
||||
runner.ExpectGitArgs(
|
||||
append(getRevParseArgs(), "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--show-superproject-working-tree"),
|
||||
"",
|
||||
errors.New("fatal: invalid gitfile format: /path/to/repo/worktree2/.git"))
|
||||
},
|
||||
Path: "/path/to/repo/my/submodule1",
|
||||
Expected: &RepoPaths{
|
||||
currentPath: "/path/to/repo/my/submodule1",
|
||||
worktreePath: "/path/to/repo/my/submodule1",
|
||||
worktreeGitDirPath: "/path/to/repo/.git/modules/my/submodule1",
|
||||
repoPath: "/path/to/repo/my/submodule1",
|
||||
repoGitDirPath: "/path/to/repo/.git/modules/my/submodule1",
|
||||
repoName: "submodule1",
|
||||
},
|
||||
Err: nil,
|
||||
},
|
||||
{
|
||||
Name: "submodule git dir not under .git/modules",
|
||||
BeforeFunc: func(fs afero.Fs) {
|
||||
_ = fs.MkdirAll("/random/submodule1", 0o755)
|
||||
_ = afero.WriteFile(fs, "/path/to/repo/my/submodule1/.git", []byte("gitdir: /random/submodule1"), 0o644)
|
||||
},
|
||||
Path: "/path/to/repo/my/submodule1",
|
||||
Path: "/path/to/repo/worktree2",
|
||||
Expected: nil,
|
||||
Err: errors.New("failed to get repo git dir path: could not find git dir for /path/to/repo/my/submodule1: the path '/random/submodule1' is not under `worktrees` or `modules` directories"),
|
||||
Err: func(getRevParseArgs argFn) error {
|
||||
args := strings.Join(getRevParseArgs(), " ")
|
||||
return errors.New(
|
||||
fmt.Sprintf("'git %v --show-toplevel --absolute-git-dir --git-common-dir --show-superproject-working-tree' failed: fatal: invalid gitfile format: /path/to/repo/worktree2/.git", args),
|
||||
)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, s := range scenarios {
|
||||
s := s
|
||||
t.Run(s.Name, func(t *testing.T) {
|
||||
fs := afero.NewMemMapFs()
|
||||
runner := oscommands.NewFakeRunner(t)
|
||||
cmd := oscommands.NewDummyCmdObjBuilder(runner)
|
||||
|
||||
version, err := GetGitVersion(oscommands.NewDummyOSCommand())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
getRevParseArgs := func() []string {
|
||||
args := []string{"rev-parse"}
|
||||
if version.IsAtLeast(2, 31, 0) {
|
||||
args = append(args, "--path-format=absolute")
|
||||
}
|
||||
return args
|
||||
}
|
||||
// prepare the filesystem for the scenario
|
||||
s.BeforeFunc(fs)
|
||||
s.BeforeFunc(runner, getRevParseArgs)
|
||||
|
||||
// run the function with the scenario path
|
||||
repoPaths, err := getRepoPathsAux(fs, mockResolveSymlinkFn, s.Path)
|
||||
repoPaths, err := GetRepoPaths(cmd, version)
|
||||
|
||||
// check the error and the paths
|
||||
if s.Err != nil {
|
||||
scenarioErr := s.Err(getRevParseArgs)
|
||||
assert.Error(t, err)
|
||||
assert.EqualError(t, err, s.Err.Error())
|
||||
assert.EqualError(t, err, scenarioErr.Error())
|
||||
} else {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, s.Expected, repoPaths)
|
||||
|
|
|
@ -88,6 +88,7 @@ func (self *StashCommands) ShowStashEntryCmdObj(index int) oscommands.ICmdObj {
|
|||
Arg(fmt.Sprintf("--unified=%d", self.AppState.DiffContextSize)).
|
||||
ArgIf(self.AppState.IgnoreWhitespaceInDiffView, "--ignore-all-space").
|
||||
Arg(fmt.Sprintf("stash@{%d}", index)).
|
||||
Dir(self.repoPaths.worktreePath).
|
||||
ToArgv()
|
||||
|
||||
return self.cmd.New(cmdArgs).DontLog()
|
||||
|
|
|
@ -112,21 +112,21 @@ func TestStashStashEntryCmdObj(t *testing.T) {
|
|||
index: 5,
|
||||
contextSize: 3,
|
||||
ignoreWhitespace: false,
|
||||
expected: []string{"git", "stash", "show", "-p", "--stat", "--color=always", "--unified=3", "stash@{5}"},
|
||||
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "--color=always", "--unified=3", "stash@{5}"},
|
||||
},
|
||||
{
|
||||
testName: "Show diff with custom context size",
|
||||
index: 5,
|
||||
contextSize: 77,
|
||||
ignoreWhitespace: false,
|
||||
expected: []string{"git", "stash", "show", "-p", "--stat", "--color=always", "--unified=77", "stash@{5}"},
|
||||
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "--color=always", "--unified=77", "stash@{5}"},
|
||||
},
|
||||
{
|
||||
testName: "Default case",
|
||||
index: 5,
|
||||
contextSize: 3,
|
||||
ignoreWhitespace: true,
|
||||
expected: []string{"git", "stash", "show", "-p", "--stat", "--color=always", "--unified=3", "--ignore-all-space", "stash@{5}"},
|
||||
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "--color=always", "--unified=3", "--ignore-all-space", "stash@{5}"},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -137,7 +137,10 @@ func TestStashStashEntryCmdObj(t *testing.T) {
|
|||
appState := &config.AppState{}
|
||||
appState.IgnoreWhitespaceInDiffView = s.ignoreWhitespace
|
||||
appState.DiffContextSize = s.contextSize
|
||||
instance := buildStashCommands(commonDeps{userConfig: userConfig, appState: appState})
|
||||
repoPaths := RepoPaths{
|
||||
worktreePath: "/path/to/worktree",
|
||||
}
|
||||
instance := buildStashCommands(commonDeps{userConfig: userConfig, appState: appState, repoPaths: &repoPaths})
|
||||
|
||||
cmdStr := instance.ShowStashEntryCmdObj(s.index).Args()
|
||||
assert.Equal(t, s.expected, cmdStr)
|
||||
|
|
|
@ -255,6 +255,7 @@ func (self *WorkingTreeCommands) WorktreeFileDiffCmdObj(node models.IFile, plain
|
|||
ArgIf(noIndex, "/dev/null").
|
||||
Arg(node.GetPath()).
|
||||
ArgIf(prevPath != "", prevPath).
|
||||
Dir(self.repoPaths.worktreePath).
|
||||
ToArgv()
|
||||
|
||||
return self.cmd.New(cmdArgs).DontLog()
|
||||
|
@ -290,6 +291,7 @@ func (self *WorkingTreeCommands) ShowFileDiffCmdObj(from string, to string, reve
|
|||
ArgIf(!plain && self.AppState.IgnoreWhitespaceInDiffView, "--ignore-all-space").
|
||||
Arg("--").
|
||||
Arg(fileName).
|
||||
Dir(self.repoPaths.worktreePath).
|
||||
ToArgv()
|
||||
|
||||
return self.cmd.New(cmdArgs).DontLog()
|
||||
|
|
|
@ -231,7 +231,7 @@ func TestWorkingTreeDiff(t *testing.T) {
|
|||
ignoreWhitespace: false,
|
||||
contextSize: 3,
|
||||
runner: oscommands.NewFakeRunner(t).
|
||||
ExpectGitArgs([]string{"diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=always", "--", "test.txt"}, expectedResult, nil),
|
||||
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=always", "--", "test.txt"}, expectedResult, nil),
|
||||
},
|
||||
{
|
||||
testName: "cached",
|
||||
|
@ -245,7 +245,7 @@ func TestWorkingTreeDiff(t *testing.T) {
|
|||
ignoreWhitespace: false,
|
||||
contextSize: 3,
|
||||
runner: oscommands.NewFakeRunner(t).
|
||||
ExpectGitArgs([]string{"diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=always", "--cached", "--", "test.txt"}, expectedResult, nil),
|
||||
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=always", "--cached", "--", "test.txt"}, expectedResult, nil),
|
||||
},
|
||||
{
|
||||
testName: "plain",
|
||||
|
@ -259,7 +259,7 @@ func TestWorkingTreeDiff(t *testing.T) {
|
|||
ignoreWhitespace: false,
|
||||
contextSize: 3,
|
||||
runner: oscommands.NewFakeRunner(t).
|
||||
ExpectGitArgs([]string{"diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=never", "--", "test.txt"}, expectedResult, nil),
|
||||
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=never", "--", "test.txt"}, expectedResult, nil),
|
||||
},
|
||||
{
|
||||
testName: "File not tracked and file has no staged changes",
|
||||
|
@ -273,7 +273,7 @@ func TestWorkingTreeDiff(t *testing.T) {
|
|||
ignoreWhitespace: false,
|
||||
contextSize: 3,
|
||||
runner: oscommands.NewFakeRunner(t).
|
||||
ExpectGitArgs([]string{"diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=always", "--no-index", "--", "/dev/null", "test.txt"}, expectedResult, nil),
|
||||
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=always", "--no-index", "--", "/dev/null", "test.txt"}, expectedResult, nil),
|
||||
},
|
||||
{
|
||||
testName: "Default case (ignore whitespace)",
|
||||
|
@ -287,7 +287,7 @@ func TestWorkingTreeDiff(t *testing.T) {
|
|||
ignoreWhitespace: true,
|
||||
contextSize: 3,
|
||||
runner: oscommands.NewFakeRunner(t).
|
||||
ExpectGitArgs([]string{"diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=always", "--ignore-all-space", "--", "test.txt"}, expectedResult, nil),
|
||||
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=always", "--ignore-all-space", "--", "test.txt"}, expectedResult, nil),
|
||||
},
|
||||
{
|
||||
testName: "Show diff with custom context size",
|
||||
|
@ -301,7 +301,7 @@ func TestWorkingTreeDiff(t *testing.T) {
|
|||
ignoreWhitespace: false,
|
||||
contextSize: 17,
|
||||
runner: oscommands.NewFakeRunner(t).
|
||||
ExpectGitArgs([]string{"diff", "--no-ext-diff", "--submodule", "--unified=17", "--color=always", "--", "test.txt"}, expectedResult, nil),
|
||||
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=17", "--color=always", "--", "test.txt"}, expectedResult, nil),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -312,8 +312,11 @@ func TestWorkingTreeDiff(t *testing.T) {
|
|||
appState := &config.AppState{}
|
||||
appState.IgnoreWhitespaceInDiffView = s.ignoreWhitespace
|
||||
appState.DiffContextSize = s.contextSize
|
||||
repoPaths := RepoPaths{
|
||||
worktreePath: "/path/to/worktree",
|
||||
}
|
||||
|
||||
instance := buildWorkingTreeCommands(commonDeps{runner: s.runner, userConfig: userConfig, appState: appState})
|
||||
instance := buildWorkingTreeCommands(commonDeps{runner: s.runner, userConfig: userConfig, appState: appState, repoPaths: &repoPaths})
|
||||
result := instance.WorktreeFileDiff(s.file, s.plain, s.cached)
|
||||
assert.Equal(t, expectedResult, result)
|
||||
s.runner.CheckForMissingCalls()
|
||||
|
@ -345,7 +348,7 @@ func TestWorkingTreeShowFileDiff(t *testing.T) {
|
|||
ignoreWhitespace: false,
|
||||
contextSize: 3,
|
||||
runner: oscommands.NewFakeRunner(t).
|
||||
ExpectGitArgs([]string{"diff", "--no-ext-diff", "--submodule", "--unified=3", "--no-renames", "--color=always", "1234567890", "0987654321", "--", "test.txt"}, expectedResult, nil),
|
||||
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--no-renames", "--color=always", "1234567890", "0987654321", "--", "test.txt"}, expectedResult, nil),
|
||||
},
|
||||
{
|
||||
testName: "Show diff with custom context size",
|
||||
|
@ -356,7 +359,7 @@ func TestWorkingTreeShowFileDiff(t *testing.T) {
|
|||
ignoreWhitespace: false,
|
||||
contextSize: 123,
|
||||
runner: oscommands.NewFakeRunner(t).
|
||||
ExpectGitArgs([]string{"diff", "--no-ext-diff", "--submodule", "--unified=123", "--no-renames", "--color=always", "1234567890", "0987654321", "--", "test.txt"}, expectedResult, nil),
|
||||
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=123", "--no-renames", "--color=always", "1234567890", "0987654321", "--", "test.txt"}, expectedResult, nil),
|
||||
},
|
||||
{
|
||||
testName: "Default case (ignore whitespace)",
|
||||
|
@ -367,7 +370,7 @@ func TestWorkingTreeShowFileDiff(t *testing.T) {
|
|||
ignoreWhitespace: true,
|
||||
contextSize: 3,
|
||||
runner: oscommands.NewFakeRunner(t).
|
||||
ExpectGitArgs([]string{"diff", "--no-ext-diff", "--submodule", "--unified=3", "--no-renames", "--color=always", "1234567890", "0987654321", "--ignore-all-space", "--", "test.txt"}, expectedResult, nil),
|
||||
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--no-renames", "--color=always", "1234567890", "0987654321", "--ignore-all-space", "--", "test.txt"}, expectedResult, nil),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -378,8 +381,11 @@ func TestWorkingTreeShowFileDiff(t *testing.T) {
|
|||
appState := &config.AppState{}
|
||||
appState.IgnoreWhitespaceInDiffView = s.ignoreWhitespace
|
||||
appState.DiffContextSize = s.contextSize
|
||||
repoPaths := RepoPaths{
|
||||
worktreePath: "/path/to/worktree",
|
||||
}
|
||||
|
||||
instance := buildWorkingTreeCommands(commonDeps{runner: s.runner, userConfig: userConfig, appState: appState})
|
||||
instance := buildWorkingTreeCommands(commonDeps{runner: s.runner, userConfig: userConfig, appState: appState, repoPaths: &repoPaths})
|
||||
|
||||
result, err := instance.ShowFileDiff(s.from, s.to, s.reverse, "test.txt", s.plain)
|
||||
assert.NoError(t, err)
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
iofs "io/fs"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
|
@ -57,18 +58,14 @@ func (self *WorktreeLoader) GetWorktrees() ([]*models.Worktree, error) {
|
|||
isCurrent := path == worktreePath
|
||||
isPathMissing := self.pathExists(path)
|
||||
|
||||
var gitDir string
|
||||
gitDir, err := getWorktreeGitDirPath(self.Fs, path)
|
||||
if err != nil {
|
||||
self.Log.Warnf("Could not find git dir for worktree %s: %v", path, err)
|
||||
}
|
||||
|
||||
current = &models.Worktree{
|
||||
IsMain: isMain,
|
||||
IsCurrent: isCurrent,
|
||||
IsPathMissing: isPathMissing,
|
||||
Path: path,
|
||||
GitDir: gitDir,
|
||||
// we defer populating GitDir until a loop below so that
|
||||
// we can parallelize the calls to git rev-parse
|
||||
GitDir: "",
|
||||
}
|
||||
} else if strings.HasPrefix(splitLine, "branch ") {
|
||||
branch := strings.SplitN(splitLine, " ", 2)[1]
|
||||
|
@ -76,6 +73,28 @@ func (self *WorktreeLoader) GetWorktrees() ([]*models.Worktree, error) {
|
|||
}
|
||||
}
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(len(worktrees))
|
||||
for _, worktree := range worktrees {
|
||||
worktree := worktree
|
||||
|
||||
go utils.Safe(func() {
|
||||
defer wg.Done()
|
||||
|
||||
if worktree.IsPathMissing {
|
||||
return
|
||||
}
|
||||
gitDir, err := callGitRevParseWithDir(self.cmd, self.version, worktree.Path, "--absolute-git-dir")
|
||||
if err != nil {
|
||||
self.Log.Warnf("Could not find git dir for worktree %s: %v", worktree.Path, err)
|
||||
return
|
||||
}
|
||||
|
||||
worktree.GitDir = gitDir
|
||||
})
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
names := getUniqueNamesFromPaths(lo.Map(worktrees, func(worktree *models.Worktree, _ int) string {
|
||||
return worktree.Path
|
||||
}))
|
||||
|
|
|
@ -14,7 +14,7 @@ func TestGetWorktrees(t *testing.T) {
|
|||
type scenario struct {
|
||||
testName string
|
||||
repoPaths *RepoPaths
|
||||
before func(runner *oscommands.FakeCmdObjRunner, fs afero.Fs)
|
||||
before func(runner *oscommands.FakeCmdObjRunner, fs afero.Fs, getRevParseArgs argFn)
|
||||
expectedWorktrees []*models.Worktree
|
||||
expectedErr string
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ func TestGetWorktrees(t *testing.T) {
|
|||
repoPath: "/path/to/repo",
|
||||
worktreePath: "/path/to/repo",
|
||||
},
|
||||
before: func(runner *oscommands.FakeCmdObjRunner, fs afero.Fs) {
|
||||
before: func(runner *oscommands.FakeCmdObjRunner, fs afero.Fs, getRevParseArgs argFn) {
|
||||
runner.ExpectGitArgs([]string{"worktree", "list", "--porcelain"},
|
||||
`worktree /path/to/repo
|
||||
HEAD d85cc9d281fa6ae1665c68365fc70e75e82a042d
|
||||
|
@ -34,6 +34,8 @@ branch refs/heads/mybranch
|
|||
`,
|
||||
nil)
|
||||
|
||||
gitArgsMainWorktree := append(append([]string{"-C", "/path/to/repo"}, getRevParseArgs()...), "--absolute-git-dir")
|
||||
runner.ExpectGitArgs(gitArgsMainWorktree, "/path/to/repo/.git", nil)
|
||||
_ = fs.MkdirAll("/path/to/repo/.git", 0o755)
|
||||
},
|
||||
expectedWorktrees: []*models.Worktree{
|
||||
|
@ -55,7 +57,7 @@ branch refs/heads/mybranch
|
|||
repoPath: "/path/to/repo",
|
||||
worktreePath: "/path/to/repo",
|
||||
},
|
||||
before: func(runner *oscommands.FakeCmdObjRunner, fs afero.Fs) {
|
||||
before: func(runner *oscommands.FakeCmdObjRunner, fs afero.Fs, getRevParseArgs argFn) {
|
||||
runner.ExpectGitArgs([]string{"worktree", "list", "--porcelain"},
|
||||
`worktree /path/to/repo
|
||||
HEAD d85cc9d281fa6ae1665c68365fc70e75e82a042d
|
||||
|
@ -66,6 +68,10 @@ HEAD 775955775e79b8f5b4c4b56f82fbf657e2d5e4de
|
|||
branch refs/heads/mybranch-worktree
|
||||
`,
|
||||
nil)
|
||||
gitArgsMainWorktree := append(append([]string{"-C", "/path/to/repo"}, getRevParseArgs()...), "--absolute-git-dir")
|
||||
runner.ExpectGitArgs(gitArgsMainWorktree, "/path/to/repo/.git", nil)
|
||||
gitArgsLinkedWorktree := append(append([]string{"-C", "/path/to/repo-worktree"}, getRevParseArgs()...), "--absolute-git-dir")
|
||||
runner.ExpectGitArgs(gitArgsLinkedWorktree, "/path/to/repo/.git/worktrees/repo-worktree", nil)
|
||||
|
||||
_ = fs.MkdirAll("/path/to/repo/.git", 0o755)
|
||||
_ = fs.MkdirAll("/path/to/repo-worktree", 0o755)
|
||||
|
@ -100,7 +106,7 @@ branch refs/heads/mybranch-worktree
|
|||
repoPath: "/path/to/repo",
|
||||
worktreePath: "/path/to/repo",
|
||||
},
|
||||
before: func(runner *oscommands.FakeCmdObjRunner, fs afero.Fs) {
|
||||
before: func(runner *oscommands.FakeCmdObjRunner, fs afero.Fs, getRevParseArgs argFn) {
|
||||
runner.ExpectGitArgs([]string{"worktree", "list", "--porcelain"},
|
||||
`worktree /path/to/worktree
|
||||
HEAD 775955775e79b8f5b4c4b56f82fbf657e2d5e4de
|
||||
|
@ -129,7 +135,7 @@ branch refs/heads/missingbranch
|
|||
repoPath: "/path/to/repo",
|
||||
worktreePath: "/path/to/repo-worktree",
|
||||
},
|
||||
before: func(runner *oscommands.FakeCmdObjRunner, fs afero.Fs) {
|
||||
before: func(runner *oscommands.FakeCmdObjRunner, fs afero.Fs, getRevParseArgs argFn) {
|
||||
runner.ExpectGitArgs([]string{"worktree", "list", "--porcelain"},
|
||||
`worktree /path/to/repo
|
||||
HEAD d85cc9d281fa6ae1665c68365fc70e75e82a042d
|
||||
|
@ -140,6 +146,10 @@ HEAD 775955775e79b8f5b4c4b56f82fbf657e2d5e4de
|
|||
branch refs/heads/mybranch-worktree
|
||||
`,
|
||||
nil)
|
||||
gitArgsMainWorktree := append(append([]string{"-C", "/path/to/repo"}, getRevParseArgs()...), "--absolute-git-dir")
|
||||
runner.ExpectGitArgs(gitArgsMainWorktree, "/path/to/repo/.git", nil)
|
||||
gitArgsLinkedWorktree := append(append([]string{"-C", "/path/to/repo-worktree"}, getRevParseArgs()...), "--absolute-git-dir")
|
||||
runner.ExpectGitArgs(gitArgsLinkedWorktree, "/path/to/repo/.git/worktrees/repo-worktree", nil)
|
||||
|
||||
_ = fs.MkdirAll("/path/to/repo/.git", 0o755)
|
||||
_ = fs.MkdirAll("/path/to/repo-worktree", 0o755)
|
||||
|
@ -175,10 +185,23 @@ branch refs/heads/mybranch-worktree
|
|||
t.Run(s.testName, func(t *testing.T) {
|
||||
runner := oscommands.NewFakeRunner(t)
|
||||
fs := afero.NewMemMapFs()
|
||||
s.before(runner, fs)
|
||||
version, err := GetGitVersion(oscommands.NewDummyOSCommand())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
getRevParseArgs := func() []string {
|
||||
args := []string{"rev-parse"}
|
||||
if version.IsAtLeast(2, 31, 0) {
|
||||
args = append(args, "--path-format=absolute")
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
s.before(runner, fs, getRevParseArgs)
|
||||
|
||||
loader := &WorktreeLoader{
|
||||
GitCommon: buildGitCommon(commonDeps{runner: runner, fs: fs, repoPaths: s.repoPaths}),
|
||||
GitCommon: buildGitCommon(commonDeps{runner: runner, fs: fs, repoPaths: s.repoPaths, gitVersion: version}),
|
||||
}
|
||||
|
||||
worktrees, err := loader.GetWorktrees()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue