From 7130cb2947a58b8d0d2134f2efe12eba71c0ff75 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Mon, 18 Aug 2025 18:31:09 +0200 Subject: [PATCH 1/2] Add test for auto-forwarding branches that are checked out by another worktree The test shows that we are currently auto-forwarding branches even if they are checked out by another worktree; this is quite bad, because when you switch to that other worktree you'll see that the files that are touched by the fetched commits are all modified (which we don't test here). --- ..._branches_checked_out_in_other_worktree.go | 60 +++++++++++++++++++ pkg/integration/tests/test_list.go | 1 + 2 files changed, 61 insertions(+) create mode 100644 pkg/integration/tests/sync/fetch_and_auto_forward_branches_all_branches_checked_out_in_other_worktree.go diff --git a/pkg/integration/tests/sync/fetch_and_auto_forward_branches_all_branches_checked_out_in_other_worktree.go b/pkg/integration/tests/sync/fetch_and_auto_forward_branches_all_branches_checked_out_in_other_worktree.go new file mode 100644 index 000000000..e0913fb0e --- /dev/null +++ b/pkg/integration/tests/sync/fetch_and_auto_forward_branches_all_branches_checked_out_in_other_worktree.go @@ -0,0 +1,60 @@ +package sync + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var FetchAndAutoForwardBranchesAllBranchesCheckedOutInOtherWorktree = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Fetch from remote and auto-forward branches with config set to 'allBranches'; check that this skips branches checked out by another worktree", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) { + config.GetUserConfig().Git.AutoForwardBranches = "allBranches" + config.GetUserConfig().Git.LocalBranchSortOrder = "alphabetical" + }, + SetupRepo: func(shell *Shell) { + shell.CreateNCommits(3) + shell.NewBranch("feature") + shell.NewBranch("diverged") + shell.CloneIntoRemote("origin") + shell.SetBranchUpstream("master", "origin/master") + shell.SetBranchUpstream("feature", "origin/feature") + shell.SetBranchUpstream("diverged", "origin/diverged") + shell.Checkout("master") + shell.HardReset("HEAD^") + shell.Checkout("feature") + shell.HardReset("HEAD~2") + shell.Checkout("diverged") + shell.HardReset("HEAD~2") + shell.EmptyCommit("local") + shell.NewBranch("checked-out") + + shell.AddWorktreeCheckout("master", "../linked-worktree") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Branches(). + Lines( + Contains("checked-out").IsSelected(), + Contains("diverged ↓2↑1"), + Contains("feature ↓2").DoesNotContain("↑"), + Contains("master (worktree) ↓1").DoesNotContain("↑"), + ) + + t.Views().Files(). + IsFocused(). + Press(keys.Files.Fetch) + + // AutoForwardBranches is "allBranches": both master and feature get forwarded + t.Views().Branches(). + Lines( + Contains("checked-out").IsSelected(), + Contains("diverged ↓2↑1"), + Contains("feature ✓"), + /* EXPECTED: + Contains("master (worktree) ↓1"), + ACTUAL: */ + Contains("master (worktree) ✓"), + ) + }, +}) diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index 3fc314d10..bd352d38e 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -383,6 +383,7 @@ var tests = []*components.IntegrationTest{ submodule.Reset, submodule.ResetFolder, sync.FetchAndAutoForwardBranchesAllBranches, + sync.FetchAndAutoForwardBranchesAllBranchesCheckedOutInOtherWorktree, sync.FetchAndAutoForwardBranchesNone, sync.FetchAndAutoForwardBranchesOnlyMainBranches, sync.FetchPrune, From 235ab15d7b59fb5d8652b20279542e4e3ddeeb7b Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Mon, 18 Aug 2025 18:21:45 +0200 Subject: [PATCH 2/2] Don't auto-forward branches that are checked out by another worktree --- pkg/gui/controllers/helpers/branches_helper.go | 4 +++- ...ard_branches_all_branches_checked_out_in_other_worktree.go | 3 --- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pkg/gui/controllers/helpers/branches_helper.go b/pkg/gui/controllers/helpers/branches_helper.go index 8760c4366..5566dc40c 100644 --- a/pkg/gui/controllers/helpers/branches_helper.go +++ b/pkg/gui/controllers/helpers/branches_helper.go @@ -283,7 +283,9 @@ func (self *BranchesHelper) AutoForwardBranches() error { updateCommands := "" // The first branch is the currently checked out branch; skip it for _, branch := range branches[1:] { - if branch.RemoteBranchStoredLocally() && (allBranches || lo.Contains(self.c.UserConfig().Git.MainBranches, branch.Name)) { + if branch.RemoteBranchStoredLocally() && + !self.checkedOutByOtherWorktree(branch) && + (allBranches || lo.Contains(self.c.UserConfig().Git.MainBranches, branch.Name)) { isStrictlyBehind := branch.IsBehindForPull() && !branch.IsAheadForPull() if isStrictlyBehind { updateCommands += fmt.Sprintf("update %s %s %s\n", branch.FullRefName(), branch.FullUpstreamRefName(), branch.CommitHash) diff --git a/pkg/integration/tests/sync/fetch_and_auto_forward_branches_all_branches_checked_out_in_other_worktree.go b/pkg/integration/tests/sync/fetch_and_auto_forward_branches_all_branches_checked_out_in_other_worktree.go index e0913fb0e..bc1ecd294 100644 --- a/pkg/integration/tests/sync/fetch_and_auto_forward_branches_all_branches_checked_out_in_other_worktree.go +++ b/pkg/integration/tests/sync/fetch_and_auto_forward_branches_all_branches_checked_out_in_other_worktree.go @@ -51,10 +51,7 @@ var FetchAndAutoForwardBranchesAllBranchesCheckedOutInOtherWorktree = NewIntegra Contains("checked-out").IsSelected(), Contains("diverged ↓2↑1"), Contains("feature ✓"), - /* EXPECTED: Contains("master (worktree) ↓1"), - ACTUAL: */ - Contains("master (worktree) ✓"), ) }, })