From 6255728e636eee77451521ded983e50ec57be9b0 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Tue, 9 Jan 2024 13:27:35 +0100 Subject: [PATCH 1/3] Add a method GitVersion.IsAtLeast --- pkg/commands/git_commands/rebase.go | 4 ++-- pkg/commands/git_commands/version.go | 8 ++++++++ pkg/commands/git_commands/version_test.go | 9 +++++++++ pkg/integration/components/test.go | 2 +- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/pkg/commands/git_commands/rebase.go b/pkg/commands/git_commands/rebase.go index 2dd1ee886..fde049cda 100644 --- a/pkg/commands/git_commands/rebase.go +++ b/pkg/commands/git_commands/rebase.go @@ -221,9 +221,9 @@ func (self *RebaseCommands) PrepareInteractiveRebaseCommand(opts PrepareInteract Arg("--interactive"). Arg("--autostash"). Arg("--keep-empty"). - ArgIf(opts.keepCommitsThatBecomeEmpty && !self.version.IsOlderThan(2, 26, 0), "--empty=keep"). + ArgIf(opts.keepCommitsThatBecomeEmpty && self.version.IsAtLeast(2, 26, 0), "--empty=keep"). Arg("--no-autosquash"). - ArgIf(!self.version.IsOlderThan(2, 22, 0), "--rebase-merges"). + ArgIf(self.version.IsAtLeast(2, 22, 0), "--rebase-merges"). ArgIf(opts.onto != "", "--onto", opts.onto). Arg(opts.baseShaOrRoot). ToArgv() diff --git a/pkg/commands/git_commands/version.go b/pkg/commands/git_commands/version.go index a089d7e06..aab912ba5 100644 --- a/pkg/commands/git_commands/version.go +++ b/pkg/commands/git_commands/version.go @@ -69,3 +69,11 @@ func (v *GitVersion) IsOlderThan(major, minor, patch int) bool { func (v *GitVersion) IsOlderThanVersion(version *GitVersion) bool { return v.IsOlderThan(version.Major, version.Minor, version.Patch) } + +func (v *GitVersion) IsAtLeast(major, minor, patch int) bool { + return !v.IsOlderThan(major, minor, patch) +} + +func (v *GitVersion) IsAtLeastVersion(version *GitVersion) bool { + return v.IsAtLeast(version.Major, version.Minor, version.Patch) +} diff --git a/pkg/commands/git_commands/version_test.go b/pkg/commands/git_commands/version_test.go index 0c57813ef..46b002f60 100644 --- a/pkg/commands/git_commands/version_test.go +++ b/pkg/commands/git_commands/version_test.go @@ -45,3 +45,12 @@ func TestGitVersionIsOlderThan(t *testing.T) { assert.True(t, (&GitVersion{2, 0, 1, ""}).IsOlderThan(2, 1, 0)) assert.True(t, (&GitVersion{2, 0, 1, ""}).IsOlderThan(3, 0, 0)) } + +func TestGitVersionIsAtLeast(t *testing.T) { + assert.True(t, (&GitVersion{2, 0, 0, ""}).IsAtLeast(1, 99, 99)) + assert.True(t, (&GitVersion{2, 0, 0, ""}).IsAtLeast(2, 0, 0)) + assert.True(t, (&GitVersion{2, 1, 0, ""}).IsAtLeast(2, 0, 9)) + + assert.False(t, (&GitVersion{2, 0, 1, ""}).IsAtLeast(2, 1, 0)) + assert.False(t, (&GitVersion{2, 0, 1, ""}).IsAtLeast(3, 0, 0)) +} diff --git a/pkg/integration/components/test.go b/pkg/integration/components/test.go index 41c16ac0d..7a088c80a 100644 --- a/pkg/integration/components/test.go +++ b/pkg/integration/components/test.go @@ -100,7 +100,7 @@ func (self GitVersionRestriction) shouldRunOnVersion(version *git_commands.GitVe if err != nil { panic("Invalid git version string: " + self.from) } - return !version.IsOlderThanVersion(from) + return version.IsAtLeastVersion(from) } if self.before != "" { before, err := git_commands.ParseGitVersion(self.before) From 5b91cd0cc86a121f4ec96f9d5f7f35eb0ae810b9 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Tue, 2 Jan 2024 21:07:44 +0100 Subject: [PATCH 2/3] Extract a function fetchCommandBuilder --- pkg/commands/git_commands/sync.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/pkg/commands/git_commands/sync.go b/pkg/commands/git_commands/sync.go index fd7584aea..d049deb07 100644 --- a/pkg/commands/git_commands/sync.go +++ b/pkg/commands/git_commands/sync.go @@ -49,10 +49,13 @@ func (self *SyncCommands) Push(task gocui.Task, opts PushOpts) error { return cmdObj.Run() } +func (self *SyncCommands) fetchCommandBuilder(fetchAll bool) *GitCommandBuilder { + return NewGitCmd("fetch"). + ArgIf(fetchAll, "--all") +} + func (self *SyncCommands) FetchCmdObj(task gocui.Task) oscommands.ICmdObj { - cmdArgs := NewGitCmd("fetch"). - ArgIf(self.UserConfig.Git.FetchAll, "--all"). - ToArgv() + cmdArgs := self.fetchCommandBuilder(self.UserConfig.Git.FetchAll).ToArgv() cmdObj := self.cmd.New(cmdArgs) cmdObj.PromptOnCredentialRequest(task) @@ -64,9 +67,7 @@ func (self *SyncCommands) Fetch(task gocui.Task) error { } func (self *SyncCommands) FetchBackgroundCmdObj() oscommands.ICmdObj { - cmdArgs := NewGitCmd("fetch"). - ArgIf(self.UserConfig.Git.FetchAll, "--all"). - ToArgv() + cmdArgs := self.fetchCommandBuilder(self.UserConfig.Git.FetchAll).ToArgv() cmdObj := self.cmd.New(cmdArgs) cmdObj.DontLog().FailOnCredentialRequest() @@ -104,7 +105,7 @@ func (self *SyncCommands) FastForward( remoteName string, remoteBranchName string, ) error { - cmdArgs := NewGitCmd("fetch"). + cmdArgs := self.fetchCommandBuilder(false). Arg(remoteName). Arg(remoteBranchName + ":" + branchName). ToArgv() @@ -113,7 +114,7 @@ func (self *SyncCommands) FastForward( } func (self *SyncCommands) FetchRemote(task gocui.Task, remoteName string) error { - cmdArgs := NewGitCmd("fetch"). + cmdArgs := self.fetchCommandBuilder(false). Arg(remoteName). ToArgv() From 76e39af76ff280a0bf184e9b7d4bf23577bfe902 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Tue, 2 Jan 2024 22:17:11 +0100 Subject: [PATCH 3/3] Allow multiple fetch commands (or fetch and pull) to run concurrently Git has a bug [1] whereby running multiple fetch commands at the same time causes all of them to append their information to the .git/FETCH_HEAD file, causing the next git pull that wants to use the information to become confused, and show an error like "Cannot rebase onto multiple branches". This error would occur when pressing "f" and "p" in quick succession in the files panel, but also when pressing "p" while a background fetch happens to be running. One likely situation for this is pressing "p" right after startup. Since lazygit never uses the information written to .git/FETCH_HEAD, it's best to avoid writing to it, which fixes the scenarios described above. However, it doesn't fix the problem of repeatedly pressing "f" quickly on the checked-out branch; since we call "git pull" in that case, the above fix doesn't help there. We'll address this separately in another PR. [1] See https://public-inbox.org/git/xmqqy1daffk8.fsf@gitster.g/ for more information. --- pkg/commands/git_commands/sync.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/commands/git_commands/sync.go b/pkg/commands/git_commands/sync.go index d049deb07..4ab1f336b 100644 --- a/pkg/commands/git_commands/sync.go +++ b/pkg/commands/git_commands/sync.go @@ -51,7 +51,10 @@ func (self *SyncCommands) Push(task gocui.Task, opts PushOpts) error { func (self *SyncCommands) fetchCommandBuilder(fetchAll bool) *GitCommandBuilder { return NewGitCmd("fetch"). - ArgIf(fetchAll, "--all") + ArgIf(fetchAll, "--all"). + // avoid writing to .git/FETCH_HEAD; this allows running a pull + // concurrently without getting errors + ArgIf(self.version.IsAtLeast(2, 29, 0), "--no-write-fetch-head") } func (self *SyncCommands) FetchCmdObj(task gocui.Task) oscommands.ICmdObj {