Support bare worktrees where worktree does not have its own .git file

This was on oversight on my part: I assumed that the --work-tree arg was
always intended for use with linked worktrees which have a .git file
pointing back to the repo.

I'm honestly confused now: seems like there are three kinds of worktrees:
* the main worktree of a non-bare repo
* a linked worktree (with its own gitdir in the repo's worktrees/ dir)
* a random folder which you specify as a worktree with the --work-tree arg

I'm pretty sure the --work-tree arg is only intended to be used with this
third kind or workree
This commit is contained in:
Jesse Duffield 2023-08-07 22:08:12 +10:00
parent 0551f29de9
commit 595e28d335
6 changed files with 42 additions and 23 deletions

View file

@ -63,8 +63,17 @@ func Start(buildInfo *BuildInfo, integrationTest integrationTypes.IntegrationTes
log.Fatal(absRepoPath + " is not a valid git repository.") log.Fatal(absRepoPath + " is not a valid git repository.")
} }
cliArgs.WorkTree = absRepoPath
cliArgs.GitDir = filepath.Join(absRepoPath, ".git") cliArgs.GitDir = filepath.Join(absRepoPath, ".git")
err = os.Chdir(absRepoPath)
if err != nil {
log.Fatalf("Failed to change directory to %s: %v", absRepoPath, err)
}
} else if cliArgs.WorkTree != "" {
env.SetWorkTreeEnv(cliArgs.WorkTree)
if err := os.Chdir(cliArgs.WorkTree); err != nil {
log.Fatalf("Failed to change directory to %s: %v", cliArgs.WorkTree, err)
}
} }
if cliArgs.CustomConfigFile != "" { if cliArgs.CustomConfigFile != "" {
@ -75,13 +84,6 @@ func Start(buildInfo *BuildInfo, integrationTest integrationTypes.IntegrationTes
os.Setenv("CONFIG_DIR", cliArgs.UseConfigDir) os.Setenv("CONFIG_DIR", cliArgs.UseConfigDir)
} }
if cliArgs.WorkTree != "" {
err := os.Chdir(cliArgs.WorkTree)
if err != nil {
log.Fatalf("Failed to change directory to %s: %v", cliArgs.WorkTree, err)
}
}
if cliArgs.GitDir != "" { if cliArgs.GitDir != "" {
env.SetGitDirEnv(cliArgs.GitDir) env.SetGitDirEnv(cliArgs.GitDir)
} }
@ -118,12 +120,6 @@ func Start(buildInfo *BuildInfo, integrationTest integrationTypes.IntegrationTes
os.Exit(0) os.Exit(0)
} }
if cliArgs.WorkTree != "" {
if err := os.Chdir(cliArgs.WorkTree); err != nil {
log.Fatal(err.Error())
}
}
tempDir, err := os.MkdirTemp("", "lazygit-*") tempDir, err := os.MkdirTemp("", "lazygit-*")
if err != nil { if err != nil {
log.Fatal(err.Error()) log.Fatal(err.Error())

View file

@ -91,10 +91,24 @@ func getRepoPathsAux(
if err != nil { if err != nil {
return nil, errors.Errorf("failed to get repo git dir path: %v", err) return nil, errors.Errorf("failed to get repo git dir path: %v", err)
} }
worktreeGitDirPath, err := worktreeGitDirPath(fs, currentPath)
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)
if err != nil { if err != nil {
return nil, errors.Errorf("failed to get worktree git dir path: %v", err) return nil, errors.Errorf("failed to get worktree git dir path: %v", err)
} }
}
repoName := path.Base(repoPath) repoName := path.Base(repoPath)
return &RepoPaths{ return &RepoPaths{
@ -110,7 +124,7 @@ func getRepoPathsAux(
// Returns the path of the git-dir for the worktree. For linked worktrees, the worktree has // 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 // a .git file that points to the git-dir (which itself lives in the git-dir
// of the repo) // of the repo)
func worktreeGitDirPath(fs afero.Fs, worktreePath string) (string, error) { func getWorktreeGitDirPath(fs afero.Fs, worktreePath string) (string, error) {
// if .git is a file, we're in a linked worktree, otherwise we're in // if .git is a file, we're in a linked worktree, otherwise we're in
// the main worktree // the main worktree
dotGitPath := path.Join(worktreePath, ".git") dotGitPath := path.Join(worktreePath, ".git")

View file

@ -58,7 +58,7 @@ func (self *WorktreeLoader) GetWorktrees() ([]*models.Worktree, error) {
isPathMissing := self.pathExists(path) isPathMissing := self.pathExists(path)
var gitDir string var gitDir string
gitDir, err := worktreeGitDirPath(self.Fs, path) gitDir, err := getWorktreeGitDirPath(self.Fs, path)
if err != nil { if err != nil {
self.Log.Warnf("Could not find git dir for worktree %s: %v", path, err) self.Log.Warnf("Could not find git dir for worktree %s: %v", path, err)
} }

13
pkg/env/env.go vendored
View file

@ -14,6 +14,15 @@ func SetGitDirEnv(value string) {
os.Setenv("GIT_DIR", value) os.Setenv("GIT_DIR", value)
} }
func UnsetGitDirEnv() { func GetWorkTreeEnv() string {
_ = os.Unsetenv("GIT_DIR") return os.Getenv("GIT_WORK_TREE")
}
func SetWorkTreeEnv(value string) {
os.Setenv("GIT_WORK_TREE", value)
}
func UnsetGitLocationEnvVars() {
_ = os.Unsetenv("GIT_DIR")
_ = os.Unsetenv("GIT_WORK_TREE")
} }

View file

@ -145,7 +145,7 @@ func (self *ReposHelper) DispatchSwitchToRepo(path string, contextKey types.Cont
func (self *ReposHelper) DispatchSwitchTo(path string, errMsg string, contextKey types.ContextKey) error { func (self *ReposHelper) DispatchSwitchTo(path string, errMsg string, contextKey types.ContextKey) error {
return self.c.WithWaitingStatus(self.c.Tr.Switching, func(gocui.Task) error { return self.c.WithWaitingStatus(self.c.Tr.Switching, func(gocui.Task) error {
env.UnsetGitDirEnv() env.UnsetGitLocationEnvVars()
originalPath, err := os.Getwd() originalPath, err := os.Getwd()
if err != nil { if err != nil {
return nil return nil

View file

@ -11,7 +11,7 @@ import (
var DotfileBareRepo = NewIntegrationTest(NewIntegrationTestArgs{ var DotfileBareRepo = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Open lazygit in the worktree of a dotfile bare repo and add a file and commit", Description: "Open lazygit in the worktree of a dotfile bare repo and add a file and commit",
ExtraCmdArgs: []string{"--git-dir={{.actualPath}}/.bare", "--work-tree={{.actualPath}}/repo"}, ExtraCmdArgs: []string{"--git-dir={{.actualPath}}/.bare", "--work-tree={{.actualPath}}/repo"},
Skip: true, Skip: false,
// passing this because we're explicitly passing --git-dir and --work-tree args // passing this because we're explicitly passing --git-dir and --work-tree args
UseCustomPath: true, UseCustomPath: true,
SetupConfig: func(config *config.AppConfig) {}, SetupConfig: func(config *config.AppConfig) {},