mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 23:56:24 -04:00
Lazygit changes the process working directory when switching repos, but work that is still in flight for the previous repo can keep spawning git commands after the switch — most notably a background refresh. Its model writes are already dropped by the repo generation guard, but its git commands would now run against the new repo. That is wasted work at best; at worst it surfaces spurious error popups (the behind-base- branch computation failing with "no such ref" when the old repo's main branch doesn't exist in the new one) and pollutes caches belonging to the old repo's reusable state (e.g. MainBranches' existing-branches cache), which the user sees when switching back. Give the git command builder the directory of the repo it was created for, and pin every command it produces to that directory. The pinned directory and the process cwd are identical until a switch happens (NewGitCommand chdirs to the worktree path right before creating the builder), so nothing changes in the steady state; the pin only takes effect for commands built through a previous repo's GitCommand instance after a switch, which now keep addressing the repo they were built for. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
180 lines
6.9 KiB
Go
180 lines
6.9 KiB
Go
package commands
|
|
|
|
import (
|
|
"os"
|
|
|
|
"github.com/go-errors/errors"
|
|
|
|
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
|
"github.com/jesseduffield/lazygit/pkg/commands/git_config"
|
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
|
"github.com/jesseduffield/lazygit/pkg/commands/patch"
|
|
"github.com/jesseduffield/lazygit/pkg/common"
|
|
"github.com/jesseduffield/lazygit/pkg/config"
|
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
|
)
|
|
|
|
// GitCommand is our main git interface
|
|
type GitCommand struct {
|
|
Blame *git_commands.BlameCommands
|
|
Branch *git_commands.BranchCommands
|
|
Commit *git_commands.CommitCommands
|
|
Config *git_commands.ConfigCommands
|
|
Custom *git_commands.CustomCommands
|
|
Diff *git_commands.DiffCommands
|
|
File *git_commands.FileCommands
|
|
Flow *git_commands.FlowCommands
|
|
Patch *git_commands.PatchCommands
|
|
Rebase *git_commands.RebaseCommands
|
|
Remote *git_commands.RemoteCommands
|
|
Stash *git_commands.StashCommands
|
|
Status *git_commands.StatusCommands
|
|
Submodule *git_commands.SubmoduleCommands
|
|
Sync *git_commands.SyncCommands
|
|
Tag *git_commands.TagCommands
|
|
WorkingTree *git_commands.WorkingTreeCommands
|
|
Bisect *git_commands.BisectCommands
|
|
Worktree *git_commands.WorktreeCommands
|
|
Version *git_commands.GitVersion
|
|
RepoPaths *git_commands.RepoPaths
|
|
GitHub *git_commands.GitHubCommands
|
|
HostingService *git_commands.HostingService
|
|
|
|
Loaders Loaders
|
|
}
|
|
|
|
type Loaders struct {
|
|
BranchLoader *git_commands.BranchLoader
|
|
CommitFileLoader *git_commands.CommitFileLoader
|
|
CommitLoader *git_commands.CommitLoader
|
|
FileLoader *git_commands.FileLoader
|
|
ReflogCommitLoader *git_commands.ReflogCommitLoader
|
|
RemoteLoader *git_commands.RemoteLoader
|
|
StashLoader *git_commands.StashLoader
|
|
TagLoader *git_commands.TagLoader
|
|
Worktrees *git_commands.WorktreeLoader
|
|
}
|
|
|
|
func NewGitCommand(
|
|
cmn *common.Common,
|
|
version *git_commands.GitVersion,
|
|
osCommand *oscommands.OSCommand,
|
|
gitConfig git_config.IGitConfig,
|
|
pagerConfig *config.PagerConfig,
|
|
) (*GitCommand, error) {
|
|
repoPaths, err := git_commands.GetRepoPaths(osCommand.Cmd, version)
|
|
if err != nil {
|
|
return nil, errors.Errorf("Error getting repo paths: %v", err)
|
|
}
|
|
|
|
err = os.Chdir(repoPaths.WorktreePath())
|
|
if err != nil {
|
|
return nil, utils.WrapError(err)
|
|
}
|
|
|
|
return NewGitCommandAux(
|
|
cmn,
|
|
version,
|
|
osCommand,
|
|
gitConfig,
|
|
repoPaths,
|
|
pagerConfig,
|
|
), nil
|
|
}
|
|
|
|
func NewGitCommandAux(
|
|
cmn *common.Common,
|
|
version *git_commands.GitVersion,
|
|
osCommand *oscommands.OSCommand,
|
|
gitConfig git_config.IGitConfig,
|
|
repoPaths *git_commands.RepoPaths,
|
|
pagerConfig *config.PagerConfig,
|
|
) *GitCommand {
|
|
cmd := NewGitCmdObjBuilder(cmn.Log, osCommand.Cmd, repoPaths.WorktreePath())
|
|
|
|
// here we're doing a bunch of dependency injection for each of our commands structs.
|
|
// This is admittedly messy, but allows us to test each command struct in isolation,
|
|
// and allows for better namespacing when compared to having every method living
|
|
// on the one struct.
|
|
// common ones are: cmn, osCommand, dotGitDir, configCommands
|
|
configCommands := git_commands.NewConfigCommands(cmn, gitConfig)
|
|
|
|
gitCommon := git_commands.NewGitCommon(cmn, version, cmd, osCommand, repoPaths, configCommands, pagerConfig)
|
|
|
|
fileLoader := git_commands.NewFileLoader(gitCommon, cmd, configCommands)
|
|
statusCommands := git_commands.NewStatusCommands(gitCommon)
|
|
flowCommands := git_commands.NewFlowCommands(gitCommon)
|
|
remoteCommands := git_commands.NewRemoteCommands(gitCommon)
|
|
branchCommands := git_commands.NewBranchCommands(gitCommon)
|
|
syncCommands := git_commands.NewSyncCommands(gitCommon)
|
|
tagCommands := git_commands.NewTagCommands(gitCommon)
|
|
commitCommands := git_commands.NewCommitCommands(gitCommon)
|
|
customCommands := git_commands.NewCustomCommands(gitCommon)
|
|
diffCommands := git_commands.NewDiffCommands(gitCommon)
|
|
fileCommands := git_commands.NewFileCommands(gitCommon)
|
|
submoduleCommands := git_commands.NewSubmoduleCommands(gitCommon)
|
|
workingTreeCommands := git_commands.NewWorkingTreeCommands(gitCommon, submoduleCommands, fileLoader)
|
|
rebaseCommands := git_commands.NewRebaseCommands(gitCommon, commitCommands, workingTreeCommands)
|
|
stashCommands := git_commands.NewStashCommands(gitCommon, fileLoader, workingTreeCommands)
|
|
patchBuilder := patch.NewPatchBuilder(cmn.Log,
|
|
func(from string, to string, reverse bool, filename string, previousPath string, plain bool) (string, error) {
|
|
return workingTreeCommands.ShowFileDiff(from, to, reverse, filename, previousPath, plain)
|
|
})
|
|
patchCommands := git_commands.NewPatchCommands(gitCommon, rebaseCommands, commitCommands, statusCommands, stashCommands, patchBuilder)
|
|
bisectCommands := git_commands.NewBisectCommands(gitCommon)
|
|
worktreeCommands := git_commands.NewWorktreeCommands(gitCommon)
|
|
blameCommands := git_commands.NewBlameCommands(gitCommon)
|
|
gitHubCommands := git_commands.NewGitHubCommands(gitCommon)
|
|
hostingServiceCommands := git_commands.NewHostingServiceCommand(gitCommon)
|
|
|
|
branchLoader := git_commands.NewBranchLoader(cmn, gitCommon, cmd, branchCommands.CurrentBranchInfo, configCommands)
|
|
commitFileLoader := git_commands.NewCommitFileLoader(cmn, cmd)
|
|
commitLoader := git_commands.NewCommitLoader(cmn, cmd, statusCommands.WorkingTreeState, gitCommon)
|
|
reflogCommitLoader := git_commands.NewReflogCommitLoader(cmn, cmd)
|
|
remoteLoader := git_commands.NewRemoteLoader(cmn, cmd)
|
|
worktreeLoader := git_commands.NewWorktreeLoader(gitCommon)
|
|
stashLoader := git_commands.NewStashLoader(cmn, cmd)
|
|
tagLoader := git_commands.NewTagLoader(cmn, cmd)
|
|
|
|
return &GitCommand{
|
|
Blame: blameCommands,
|
|
Branch: branchCommands,
|
|
Commit: commitCommands,
|
|
Config: configCommands,
|
|
Custom: customCommands,
|
|
Diff: diffCommands,
|
|
File: fileCommands,
|
|
Flow: flowCommands,
|
|
Patch: patchCommands,
|
|
Rebase: rebaseCommands,
|
|
Remote: remoteCommands,
|
|
Stash: stashCommands,
|
|
Status: statusCommands,
|
|
Submodule: submoduleCommands,
|
|
Sync: syncCommands,
|
|
Tag: tagCommands,
|
|
Bisect: bisectCommands,
|
|
WorkingTree: workingTreeCommands,
|
|
Worktree: worktreeCommands,
|
|
Version: version,
|
|
GitHub: gitHubCommands,
|
|
HostingService: hostingServiceCommands,
|
|
Loaders: Loaders{
|
|
BranchLoader: branchLoader,
|
|
CommitFileLoader: commitFileLoader,
|
|
CommitLoader: commitLoader,
|
|
FileLoader: fileLoader,
|
|
ReflogCommitLoader: reflogCommitLoader,
|
|
RemoteLoader: remoteLoader,
|
|
Worktrees: worktreeLoader,
|
|
StashLoader: stashLoader,
|
|
TagLoader: tagLoader,
|
|
},
|
|
RepoPaths: repoPaths,
|
|
}
|
|
}
|
|
|
|
func VerifyInGitRepo(osCommand *oscommands.OSCommand) error {
|
|
return osCommand.Cmd.New(git_commands.NewGitCmd("rev-parse").Arg("--git-dir").ToArgv()).DontLog().Run()
|
|
}
|