summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pkg/commands/git.go75
-rw-r--r--pkg/commands/git_commands/bisect.go2
-rw-r--r--pkg/commands/git_commands/commit_loader.go12
-rw-r--r--pkg/commands/git_commands/common.go6
-rw-r--r--pkg/commands/git_commands/file_loader.go9
-rw-r--r--pkg/commands/git_commands/patch.go2
-rw-r--r--pkg/commands/git_commands/paths.go235
-rw-r--r--pkg/commands/git_commands/rebase.go6
-rw-r--r--pkg/commands/git_commands/status.go6
-rw-r--r--pkg/commands/git_commands/submodule.go4
-rw-r--r--pkg/commands/git_commands/worktree.go90
-rw-r--r--pkg/commands/git_commands/worktree_loader.go67
-rw-r--r--pkg/env/env.go11
-rw-r--r--pkg/gui/controllers/helpers/refresh_helper.go2
-rw-r--r--pkg/gui/controllers/helpers/repos_helper.go2
-rw-r--r--pkg/gui/controllers/helpers/working_tree_helper.go3
-rw-r--r--pkg/gui/controllers/status_controller.go4
-rw-r--r--pkg/gui/gui.go10
-rw-r--r--pkg/integration/tests/test_list.go4
-rw-r--r--pkg/integration/tests/worktree/associate_branch_bisect.go (renamed from pkg/integration/tests/worktree/bisect.go)2
-rw-r--r--pkg/integration/tests/worktree/associate_branch_rebase.go (renamed from pkg/integration/tests/worktree/rebase.go)2
-rw-r--r--pkg/integration/tests/worktree/bare_repo.go43
22 files changed, 347 insertions, 250 deletions
diff --git a/pkg/commands/git.go b/pkg/commands/git.go
index 3f7e823e7..510b26c11 100644
--- a/pkg/commands/git.go
+++ b/pkg/commands/git.go
@@ -1,7 +1,6 @@
package commands
import (
- "fmt"
"os"
"path/filepath"
"strings"
@@ -40,6 +39,7 @@ type GitCommand struct {
Bisect *git_commands.BisectCommands
Worktree *git_commands.WorktreeCommands
Version *git_commands.GitVersion
+ RepoPaths git_commands.RepoPaths
Loaders Loaders
}
@@ -67,12 +67,15 @@ func NewGitCommand(
return nil, err
}
- dotGitDir, err := findDotGitDir(os.Stat, os.ReadFile)
+ repoPaths, err := git_commands.GetRepoPaths()
if err != nil {
- return nil, err
+ return nil, errors.Errorf("Error getting repo paths: %v", err)
}
- repository, err := gogit.PlainOpenWithOptions(dotGitDir, &gogit.PlainOpenOptions{DetectDotGit: false, EnableDotGitCommonDir: true})
+ repository, err := gogit.PlainOpenWithOptions(
+ repoPaths.WorktreeGitDirPath(),
+ &gogit.PlainOpenOptions{DetectDotGit: false, EnableDotGitCommonDir: true},
+ )
if err != nil {
if strings.Contains(err.Error(), `unquoted '\' must be followed by new line`) {
return nil, errors.New(cmn.Tr.GitconfigParseErr)
@@ -85,7 +88,7 @@ func NewGitCommand(
version,
osCommand,
gitConfig,
- dotGitDir,
+ repoPaths,
repository,
syncMutex,
), nil
@@ -96,7 +99,7 @@ func NewGitCommandAux(
version *git_commands.GitVersion,
osCommand *oscommands.OSCommand,
gitConfig git_config.IGitConfig,
- dotGitDir string,
+ repoPaths git_commands.RepoPaths,
repo *gogit.Repository,
syncMutex *deadlock.Mutex,
) *GitCommand {
@@ -109,9 +112,9 @@ func NewGitCommandAux(
// common ones are: cmn, osCommand, dotGitDir, configCommands
configCommands := git_commands.NewConfigCommands(cmn, gitConfig, repo)
- fileLoader := git_commands.NewFileLoader(cmn, cmd, configCommands)
+ gitCommon := git_commands.NewGitCommon(cmn, version, cmd, osCommand, repoPaths, repo, configCommands, syncMutex)
- gitCommon := git_commands.NewGitCommon(cmn, version, cmd, osCommand, dotGitDir, repo, configCommands, syncMutex)
+ fileLoader := git_commands.NewFileLoader(gitCommon, cmd, configCommands)
statusCommands := git_commands.NewStatusCommands(gitCommon)
flowCommands := git_commands.NewFlowCommands(gitCommon)
remoteCommands := git_commands.NewRemoteCommands(gitCommon)
@@ -138,10 +141,10 @@ func NewGitCommandAux(
branchLoader := git_commands.NewBranchLoader(cmn, cmd, branchCommands.CurrentBranchInfo, configCommands)
commitFileLoader := git_commands.NewCommitFileLoader(cmn, cmd)
- commitLoader := git_commands.NewCommitLoader(cmn, cmd, dotGitDir, statusCommands.RebaseMode, gitCommon)
+ commitLoader := git_commands.NewCommitLoader(cmn, cmd, statusCommands.RebaseMode, gitCommon)
reflogCommitLoader := git_commands.NewReflogCommitLoader(cmn, cmd)
remoteLoader := git_commands.NewRemoteLoader(cmn, cmd, repo.Remotes)
- worktreeLoader := git_commands.NewWorktreeLoader(cmn, cmd)
+ worktreeLoader := git_commands.NewWorktreeLoader(gitCommon, cmd)
stashLoader := git_commands.NewStashLoader(cmn, cmd)
tagLoader := git_commands.NewTagLoader(cmn, cmd)
@@ -176,6 +179,7 @@ func NewGitCommandAux(
StashLoader: stashLoader,
TagLoader: tagLoader,
},
+ RepoPaths: repoPaths,
}
}
@@ -222,20 +226,6 @@ func navigateToRepoRootDirectory(stat func(string) (os.FileInfo, error), chdir f
}
}
-// 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)
-}
-
func setupRepository(
openGitRepository func(string, *gogit.PlainOpenOptions) (*gogit.Repository, error),
options gogit.PlainOpenOptions,
@@ -253,43 +243,6 @@ func setupRepository(
return repository, err
}
-func findDotGitDir(stat func(string) (os.FileInfo, error), readFile func(filename string) ([]byte, error)) (string, error) {
- unresolvedPath := env.GetGitDirEnv()
- if unresolvedPath == "" {
- var err error
- unresolvedPath, err = os.Getwd()
- if err != nil {
- return "", err
- }
- unresolvedPath = filepath.Join(unresolvedPath, ".git")
- }
-
- path, err := resolveSymlink(unresolvedPath)
- if err != nil {
- return "", err
- }
-
- f, err := stat(path)
- if err != nil {
- return "", err
- }
-
- if f.IsDir() {
- return path, nil
- }
-
- fileBytes, err := readFile(path)
- if err != nil {
- return "", err
- }
-
- fileContent := string(fileBytes)
- if !strings.HasPrefix(fileContent, "gitdir: ") {
- 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", path))
- }
- return strings.TrimSpace(strings.TrimPrefix(fileContent, "gitdir: ")), nil
-}
-
func VerifyInGitRepo(osCommand *oscommands.OSCommand) error {
return osCommand.Cmd.New(git_commands.NewGitCmd("rev-parse").Arg("--git-dir").ToArgv()).DontLog().Run()
}
diff --git a/pkg/commands/git_commands/bisect.go b/pkg/commands/git_commands/bisect.go
index bd4b3ead2..41e99bd3c 100644
--- a/pkg/commands/git_commands/bisect.go
+++ b/pkg/commands/git_commands/bisect.go
@@ -19,7 +19,7 @@ func NewBisectCommands(gitCommon *GitCommon) *BisectCommands {
// This command is pretty cheap to run so we're not storing the result anywhere.
// But if it becomes problematic we can chang that.
func (self *BisectCommands) GetInfo() *BisectInfo {
- return self.GetInfoForGitDir(self.dotGitDir)
+ return self.GetInfoForGitDir(self.repoPaths.WorktreeGitDirPath())
}
func (self *BisectCommands) GetInfoForGitDir(gitDir string) *BisectInfo {
diff --git a/pkg/commands/git_commands/commit_loader.go b/pkg/commands/git_commands/commit_loader.go
index 7e304ea44..ac0f19363 100644
--- a/pkg/commands/git_commands/commit_loader.go
+++ b/pkg/commands/git_commands/commit_loader.go
@@ -47,7 +47,6 @@ type CommitLoader struct {
func NewCommitLoader(
cmn *common.Common,
cmd oscommands.ICmdObjBuilder,
- dotGitDir string,
getRebaseMode func() (enums.RebaseMode, error),
gitCommon *GitCommon,
) *CommitLoader {
@@ -57,7 +56,6 @@ func NewCommitLoader(
getRebaseMode: getRebaseMode,
readFile: os.ReadFile,
walkFiles: filepath.Walk,
- dotGitDir: dotGitDir,
mainBranches: nil,
GitCommon: gitCommon,
}
@@ -299,7 +297,7 @@ func (self *CommitLoader) getRebasingCommits(rebaseMode enums.RebaseMode) ([]*mo
func (self *CommitLoader) getNormalRebasingCommits() ([]*models.Commit, error) {
rewrittenCount := 0
- bytesContent, err := self.readFile(filepath.Join(self.dotGitDir, "rebase-apply/rewritten"))
+ bytesContent, err := self.readFile(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-apply/rewritten"))
if err == nil {
content := string(bytesContent)
rewrittenCount = len(strings.Split(content, "\n"))
@@ -307,7 +305,7 @@ func (self *CommitLoader) getNormalRebasingCommits() ([]*models.Commit, error) {
// we know we're rebasing, so lets get all the files whose names have numbers
commits := []*models.Commit{}
- err = self.walkFiles(filepath.Join(self.dotGitDir, "rebase-apply"), func(path string, f os.FileInfo, err error) error {
+ err = self.walkFiles(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-apply"), func(path string, f os.FileInfo, err error) error {
if rewrittenCount > 0 {
rewrittenCount--
return nil
@@ -348,7 +346,7 @@ func (self *CommitLoader) getNormalRebasingCommits() ([]*models.Commit, error) {
// and extracts out the sha and names of commits that we still have to go
// in the rebase:
func (self *CommitLoader) getInteractiveRebasingCommits() ([]*models.Commit, error) {
- bytesContent, err := self.readFile(filepath.Join(self.dotGitDir, "rebase-merge/git-rebase-todo"))
+ bytesContent, err := self.readFile(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo"))
if err != nil {
self.Log.Error(fmt.Sprintf("error occurred reading git-rebase-todo: %s", err.Error()))
// we assume an error means the file doesn't exist so we just return
@@ -393,7 +391,7 @@ func (self *CommitLoader) getInteractiveRebasingCommits() ([]*models.Commit, err
}
func (self *CommitLoader) getConflictedCommit(todos []todo.Todo) string {
- bytesContent, err := self.readFile(filepath.Join(self.dotGitDir, "rebase-merge/done"))
+ bytesContent, err := self.readFile(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/done"))
if err != nil {
self.Log.Error(fmt.Sprintf("error occurred reading rebase-merge/done: %s", err.Error()))
return ""
@@ -406,7 +404,7 @@ func (self *CommitLoader) getConflictedCommit(todos []todo.Todo) string {
}
amendFileExists := false
- if _, err := os.Stat(filepath.Join(self.dotGitDir, "rebase-merge/amend")); err == nil {
+ if _, err := os.Stat(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/amend")); err == nil {
amendFileExists = true
}
diff --git a/pkg/commands/git_commands/common.go b/pkg/commands/git_commands/common.go
index f2f187bef..b4c8bea32 100644
--- a/pkg/commands/git_commands/common.go
+++ b/pkg/commands/git_commands/common.go
@@ -12,7 +12,7 @@ type GitCommon struct {
version *GitVersion
cmd oscommands.ICmdObjBuilder
os *oscommands.OSCommand
- dotGitDir string
+ repoPaths RepoPaths
repo *gogit.Repository
config *ConfigCommands
// mutex for doing things like push/pull/fetch
@@ -24,7 +24,7 @@ func NewGitCommon(
version *GitVersion,
cmd oscommands.ICmdObjBuilder,
osCommand *oscommands.OSCommand,
- dotGitDir string,
+ repoPaths RepoPaths,
repo *gogit.Repository,
config *ConfigCommands,
syncMutex *deadlock.Mutex,
@@ -34,7 +34,7 @@ func NewGitCommon(
version: version,
cmd: cmd,
os: osCommand,
- dotGitDir: dotGitDir,
+ repoPaths: repoPaths,
repo: repo,
config: config,
syncMutex: syncMutex,
diff --git a/pkg/commands/git_commands/file_loader.go b/pkg/commands/git_commands/file_loader.go
index 1585fced6..574a8a6f0 100644
--- a/pkg/commands/git_commands/file_loader.go
+++ b/pkg/commands/git_commands/file_loader.go
@@ -7,7 +7,6 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
- "github.com/jesseduffield/lazygit/pkg/common"
)
type FileLoaderConfig interface {
@@ -15,15 +14,15 @@ type FileLoaderConfig interface {
}
type FileLoader struct {
- *common.Common
+ *GitCommon
cmd oscommands.ICmdObjBuilder
config FileLoaderConfig
getFileType func(string) string
}
-func NewFileLoader(cmn *common.Common, cmd oscommands.ICmdObjBuilder, config FileLoaderConfig) *FileLoader {
+func NewFileLoader(gitCommon *GitCommon, cmd oscommands.ICmdObjBuilder, config FileLoaderConfig) *FileLoader {
return &FileLoader{
- Common: cmn,
+ GitCommon: gitCommon,
cmd: cmd,
getFileType: oscommands.FileType,
config: config,
@@ -67,7 +66,7 @@ func (self *FileLoader) GetStatusFiles(opts GetStatusFileOptions) []*models.File
// Go through the files to see if any of these files are actually worktrees
// so that we can render them correctly
- worktreePaths := linkedWortkreePaths()
+ worktreePaths := linkedWortkreePaths(self.repoPaths.RepoGitDirPath())
for _, file := range files {
for _, worktreePath := range worktreePaths {
absFilePath, err := filepath.Abs(file.Name)
diff --git a/pkg/commands/git_commands/patch.go b/pkg/commands/git_commands/patch.go
index 871dadc05..749e5dc22 100644
--- a/pkg/commands/git_commands/patch.go
+++ b/pkg/commands/git_commands/patch.go
@@ -79,7 +79,7 @@ func (self *PatchCommands) applyPatchFile(filepath string, opts ApplyPatchOpts)
}
func (self *PatchCommands) SaveTemporaryPatch(patch string) (string, error) {
- filepath := filepath.Join(self.os.GetTempDir(), GetCurrentRepoName(), time.Now().Format("Jan _2 15.04.05.000000000")+".patch")
+ filepath := filepath.Join(self.os.GetTempDir(), self.repoPaths.RepoName(), time.Now().Format("Jan _2 15.04.05.000000000")+".patch")
self.Log.Infof("saving temporary patch to %s", filepath)
if err := self.os.CreateFileWithContent(filepath, patch); err != nil {
return "", err
diff --git a/pkg/commands/git_commands/paths.go b/pkg/commands/git_commands/paths.go
new file mode 100644
index 000000000..de83346ce
--- /dev/null
+++ b/pkg/commands/git_commands/paths.go
@@ -0,0 +1,235 @@
+package git_commands
+
+import (
+ "fmt"
+ "io/fs"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/go-errors/errors"
+ "github.com/jesseduffield/lazygit/pkg/env"
+ "github.com/samber/lo"
+)
+
+type RepoPaths interface {
+ // 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.
+ CurrentPath() string
+ // Path to the current worktree. If we're in the main worktree, this will
+ // be the same as RepoPath()
+ WorktreePath() string
+ // Path of the worktree's git dir.
+ // If we're in the main worktree, this will be the .git dir under the RepoPath().
+ // If we're in a linked worktree, it will be the directory pointed at by the worktree's .git file
+ WorktreeGitDirPath() string
+ // Path of the repo. If we're in a the main worktree, this will be the same as WorktreePath()
+ // If we're in a bare repo, it will be the parent folder of the bare repo
+ RepoPath() string
+ // path of the git-dir for the repo.
+ // If this is a bare repo, it will be the location of the bare repo
+ // If this is a non-bare repo, it will be the location of the .git dir in
+ // the main worktree.
+ RepoGitDirPath() string
+ // Name of the repo. Basename of the folder containing the repo.
+ RepoName() string
+}
+
+type RepoDirsImpl struct {
+ currentPath string
+ worktreePath string
+ worktreeGitDirPath string
+ repoPath string
+ repoGitDirPath string
+ repoName string
+}
+
+var _ RepoPaths = &RepoDirsImpl{}
+
+func (self *RepoDirsImpl) CurrentPath() string {
+ return self.currentPath
+}
+
+func (self *RepoDirsImpl) WorktreePath() string {
+ return self.worktreePath
+}
+
+func (self *RepoDirsImpl) WorktreeGitDirPath() string {
+ return self.worktreeGitDirPath
+}
+
+func (self *RepoDirsImpl) RepoPath() string {
+ return self.repoPath
+}
+
+func (self *RepoDirsImpl) RepoGitDirPath() string {
+ return self.repoGitDirPath
+}
+
+func (self *RepoDirsImpl) RepoName() string {
+ return self.repoName
+}
+
+func GetRepoPaths() (RepoPaths, error) {
+ currentPath, err := os.Getwd()
+ if err != nil {
+ return &RepoDirsImpl{}, errors.Errorf("failed to get current path: %v", err)
+ }
+
+ worktreePath := currentPath
+ repoGitDirPath, repoPath, err := GetCurrentRepoGitDirPath(currentPath)
+ if err != nil {
+ return &RepoDirsImpl{}, errors.Errorf("failed to get repo git dir path: %v", err)
+ }
+ worktreeGitDirPath, err := worktreeGitDirPath(currentPath)
+ if err != nil {
+ return &RepoDirsImpl{}, errors.Errorf("failed to get worktree git dir path: %v", err)
+ }
+ repoName := filepath.Base(repoPath)
+
+ return &RepoDirsImpl{
+ currentPath: currentPath,
+ worktreePath: worktreePath,
+ worktreeGitDirPath: worktreeGitDirPath,
+ repoPath: repoPath,
+ repoGitDirPath: repoGitDirPath,
+ repoName: repoName,
+ }, nil
+}
+
+// Returns the paths of linked worktrees
+func linkedWortkreePaths(repoGitDirPath string) []string {
+ result := []string{}
+ // For each directory in this path we're going to cat the `gitdir` file and append its contents to our result
+ // That file points us to the `.git` file in the worktree.
+ worktreeGitDirsPath := filepath.Join(repoGitDirPath, "worktrees")
+
+ // ensure the directory exists
+ _, err := os.Stat(worktreeGitDirsPath)
+ if err != nil {
+ return result
+ }
+
+ _ = filepath.Walk(worktreeGitDirsPath, func(path string, info fs.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+
+ if !info.IsDir() {
+ return nil
+ }
+
+ gitDirPath := filepath.Join(path, "gitdir")
+ gitDirBytes, err := os.ReadFile(gitDirPath)
+ if err != nil {
+ // ignoring error
+ return nil
+ }
+ trimmedGitDir := strings.TrimSpace(string(gitDirBytes))
+ // removing the .git part
+ worktreeDir := filepath.Dir(trimmedGitDir)
+ result = append(result, worktreeDir)
+ return nil
+ })
+
+ return result
+}
+
+// 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 worktreeGitDirPath(worktreePath string) (string, error) {
+ // if .git is a file, we're in a linked worktree, otherwise we're in
+ // the main worktree
+ dotGitPath := filepath.Join(worktreePath, ".git")
+ gitFileInfo, err := os.Stat(dotGitPath)
+ if err != nil {
+ return "", err
+ }
+
+ if gitFileInfo.IsDir() {
+ return dotGitPath, nil
+ }
+
+ return linkedWorktreeGitDirPath(worktreePath)
+}
+
+func linkedWorktreeGitDirPath(worktreePath string) (string, error) {
+ dotGitPath := filepath.Join(worktreePath, ".git")
+ gitFileContents, err := os.ReadFile(dotGitPath)
+ if err != nil {
+ return "", 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: ")
+ return gitDir, nil
+}
+
+func GetCurrentRepoGitDirPath(currentPath string) (string, string, error) {
+ var unresolvedGitPath string
+ if env.GetGitDirEnv() != "" {
+ unresolvedGitPath = env.GetGitDirEnv()
+ } else {
+ unresolvedGitPath = filepath.Join(currentPath, ".git")
+ }
+
+ gitPath, err := resolveSymlink(unresolvedGitPath)
+ if err != nil {
+ return "", "", err
+ }
+
+ // check if .git is a file or a directory
+ gitFileInfo, err := os.Stat(gitPath)
+ if err != nil {
+ return "", "", err
+ }
+
+ if gitFileInfo.IsDir() {
+ // must be in the main worktree
+ return gitPath, filepath.Dir(gitPath), nil
+ }
+
+ // either in a submodule, or worktree
+ worktreeGitPath, err := linkedWorktreeGitDirPath(currentPath)
+ if err != nil {
+ return "", "", errors.Errorf("could not find git dir for %s: %v", currentPath, err)
+ }
+
+ // confirm whether the next directory up is the worktrees/submodules directory
+ parent := filepath.Dir(worktreeGitPath)
+ if filepath.Base(parent) != "worktrees" && filepath.Base(parent) != "modules" {
+ return "", "", errors.Errorf("could not find git dir for %s", currentPath)
+ }
+
+ // if it's a submodule, we treat it as its own repo
+ if filepath.Base(parent) == "modules" {
+ return worktreeGitPath, currentPath, nil
+ }
+
+ gitDirPath := filepath.Dir(parent)
+ return gitDirPath, filepath.Dir(gitDirPath), nil
+}
+
+// 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)
+}
diff --git a/pkg/commands/git_commands/rebase.go b/pkg/commands/git_commands/rebase.go
index 74bb3d464..66bfbf82d 100644
--- a/pkg/commands/git_commands/rebase.go
+++ b/pkg/commands/git_commands/rebase.go
@@ -243,18 +243,18 @@ func (self *RebaseCommands) AmendTo(commits []*models.Commit, commitIndex int) e
// EditRebaseTodo sets the action for a given rebase commit in the git-rebase-todo file
func (self *RebaseCommands) EditRebaseTodo(commit *models.Commit, action todo.TodoCommand) error {
return utils.EditRebaseTodo(
- filepath.Join(self.dotGitDir, "rebase-merge/git-rebase-todo"), commit.Sha, commit.Action, action, self.config.GetCoreCommentChar())
+ filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo"), commit.Sha, commit.Action, action, self.config.GetCoreCommentChar())
}
// MoveTodoDown moves a rebase todo item down by one position
func (self *RebaseCommands) MoveTodoDown(commit *models.Commit) error {
- fileName := filepath.Join(self.dotGitDir, "rebase-merge/git-rebase-todo")
+ fileName := filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo")
return utils.MoveTodoDown(fileName, commit.Sha, commit.Action, self.config.GetCoreCommentChar())
}
// MoveTodoDown moves a rebase todo item down by one position
func (self *RebaseCommands) MoveTodoUp(commit *models.Commit) error {
- fileName := filepath.Join(self.dotGitDir, "rebase-merge/git-rebase-todo")
+ fileName := filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo")
return utils.MoveTodoUp(fileName, commit.Sha, commit.Action, self.config.GetCoreCommentChar())
}
diff --git a/pkg/commands/git_commands/status.go b/pkg/commands/git_commands/status.go
index 7f03c698e..13ff02cc0 100644
--- a/pkg/commands/git_commands/status.go
+++ b/pkg/commands/git_commands/status.go
@@ -24,14 +24,14 @@ func NewStatusCommands(
// RebaseMode returns "" for non-rebase mode, "normal" for normal rebase
// and "interactive" for interactive rebase
func (self *StatusCommands) RebaseMode() (enums.RebaseMode, error) {
- exists, err := self.os.FileExists(filepath.Join(self.dotGitDir, "rebase-apply"))
+ exists, err := self.os.FileExists(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-apply"))
if err != nil {
return enums.REBASE_MODE_NONE, err
}
if exists {
return enums.REBASE_MODE_NORMAL, nil
}
- exists, err = self.os.FileExists(filepath.Join(self.dotGitDir, "rebase-merge"))
+ exists, err = self.os.FileExists(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge"))
if exists {
return enums.REBASE_MODE_INTERACTIVE, err
} else {
@@ -69,5 +69,5 @@ func IsBareRepo(osCommand *oscommands.OSCommand) (bool, error) {
// IsInMergeState states whether we are still mid-merge
func (self *StatusCommands) IsInMergeState() (bool, error) {
- return self.os.FileExists(filepath.Join(self.dotGitDir, "MERGE_HEAD"))
+ return self.os.FileExists(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "MERGE_HEAD"))
}
diff --git a/pkg/commands/git_commands/submodule.go b/pkg/commands/git_commands/submodule.go
index 3d8602b9a..d9d1ccd20 100644
--- a/pkg/commands/git_commands/submodule.go
+++ b/pkg/commands/git_commands/submodule.go
@@ -139,7 +139,9 @@ func (self *SubmoduleCommands) Delete(submodule *models.SubmoduleConfig) error {
self.Log.Error(err)
}
- return os.RemoveAll(filepath.Join(self.dotGitDir, "modules", submodule.Path))
+ // We may in fact want to use the repo's git dir path but git docs say not to
+ // mix submodules and worktrees anyway.
+ return os.RemoveAll(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "modules", submodule.Path))
}
func (self *SubmoduleCommands) Add(name string, path string, url string) error {
diff --git a/pkg/commands/git_commands/worktree.go b/pkg/commands/git_commands/worktree.go
index 1b57ab122..986bb6d42 100644
--- a/pkg/commands/git_commands/worktree.go
+++ b/pkg/commands/git_commands/worktree.go
@@ -1,11 +1,7 @@
package git_commands
import (
- "io/fs"
- "log"
- "os"
"path/filepath"
- "strings"
"github.com/jesseduffield/lazygit/pkg/commands/models"
)
@@ -76,89 +72,3 @@ func CheckedOutByOtherWorktree(branch *models.Branch, worktrees []*models.Worktr
return !worktree.IsCurrent
}
-
-// If in a non-bare repo, this returns the path of the main worktree
-// TODO: see if this works with a bare repo.
-func GetCurrentRepoPath() string {
- pwd, err := os.Getwd()
- if err != nil {
- log.Fatalln(err.Error())
- }
-
- // check if .git is a file or a directory
- gitPath := filepath.Join(pwd, ".git")
- gitFileInfo, err := os.Stat(gitPath)
- if err != nil {
- // fallback
- return currentPath()
- }
-
- if gitFileInfo.IsDir() {
- // must be in the main worktree
- return currentPath()
- }
-
- // either in a submodule, a worktree, or a bare repo
- worktreeGitPath, ok := LinkedWorktreeGitPath(pwd)
- if !ok {
- // fallback
- return currentPath()
- }
-
- // confirm whether the next directory up is the 'worktrees' directory
- parent := filepath.Dir(worktreeGitPath)
- if filepath.Base(parent) != "worktrees" {
- // fallback
- return currentPath()
- }
-
- // now we just jump up two more directories to get the repo name
- return filepath.Dir(filepath.Dir(parent))
-}
-
-func GetCurrentRepoName() string {
- return filepath.Base(GetCurrentRepoPath())
-}
-
-func currentPath() string {
- pwd, err := os.Getwd()
- if err != nil {
- log.Fatalln(err.Error())
- }
- return pwd
-}
-
-func linkedWortkreePaths() []string {
- // first we need to get the repo dir
- repoPath := GetCurrentRepoPath()
- result := []string{}
- worktreePath := filepath.Join(repoPath, ".git", "worktrees")
- // for each directory in this path we're going to cat the `gitdir` file and append its contents to our result
-
- // ensure the directory exists
- _, err := os.Stat(worktreePath)
- if err != nil {
- return result
- }
-
- err = filepath.Walk(worktreePath, func(path string, info fs.FileInfo, err error) error {
- if info.IsDir() {
- gitDirPath := filepath.Join(path, "gitdir")
- gitDirBytes, err := os.ReadFile(gitDirPath)
- if err != nil {
- // ignoring error
- return nil
- }
- trimmedGitDir := strings.TrimSpace(string(gitDirBytes))
- // removing the .git part
- worktreeDir := filepath.Dir(trimmedGitDir)
- result = append(result, worktreeDir)
- }
- return nil
- })
- if err != nil {
- return result
- }
-
- return result
-}
diff --git a/pkg/commands/git_commands/worktree_loader.go b/pkg/commands/git_commands/worktree_loader.go
index 42f889156..06a22d2b5 100644
--- a/pkg/commands/git_commands/worktree_loader.go
+++ b/pkg/commands/git_commands/worktree_loader.go
@@ -9,33 +9,28 @@ import (
"github.com/go-errors/errors"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
- "github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo"
)
type WorktreeLoader struct {
- *common.Common
+ *GitCommon
cmd oscommands.ICmdObjBuilder
}
func NewWorktreeLoader(
- common *common.Common,
+ gitCommon *GitCommon,
cmd oscommands.ICmdObjBuilder,
) *WorktreeLoader {
return &WorktreeLoader{
- Common: common,
- cmd: cmd,
+ GitCommon: gitCommon,
+ cmd: cmd,
}
}
func (self *WorktreeLoader) GetWorktrees() ([]*models.Worktree, error) {
- currentRepoPath := GetCurrentRepoPath()
-
- pwd, err := os.Getwd()
- if err != nil {
- return nil, err
- }
+ currentRepoPath := self.repoPaths.RepoPath()
+ worktreePath := self.repoP