jesseduffield.lazygit/pkg/integration/tests/submodule/resolve_conflict.go
Stefan Haller afe4d14106 Resolve submodule conflicts through a picker
When both sides of a merge moved a submodule's gitlink, git reports it as "UU".
Pressing space used to fall into the submodule no-op guard and pop the confusing
"Nothing to stage..." error, and enter just entered the submodule, which does
nothing to resolve the superproject conflict.

Treat a conflicted submodule like the other non-textual conflicts: both space
and enter now open a picker offering the two candidate commits, "current" and
"incoming", each labelled with its summary. `git checkout --ours/--theirs` is a
no-op on gitlinks, so we resolve by checking the submodule out at the chosen
commit and staging it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 16:12:36 +02:00

74 lines
2.7 KiB
Go

package submodule
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var ResolveConflict = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Resolve a submodule conflict (both sides moved the gitlink) by picking one side's commit",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Gui.ShowFileTree = false
},
SetupRepo: func(shell *Shell) {
shell.EmptyCommit("first commit")
shell.CloneIntoSubmodule("my_submodule_name", "my_submodule_path")
shell.GitAddAll()
shell.Commit("add submodule")
sub := "my_submodule_path"
// Two diverging commits in the submodule, so the gitlink can't be
// fast-forwarded and the merge genuinely conflicts.
shell.RunCommand([]string{"git", "-C", sub, "checkout", "-b", "left"})
shell.RunCommand([]string{"git", "-C", sub, "commit", "--allow-empty", "-m", "left"})
shell.RunCommand([]string{"git", "-C", sub, "checkout", "-b", "right", "HEAD~1"})
shell.RunCommand([]string{"git", "-C", sub, "commit", "--allow-empty", "-m", "right"})
// "ours" points the submodule at left, "theirs" at right.
shell.RunCommand([]string{"git", "checkout", "-b", "ours"})
shell.RunCommand([]string{"git", "-C", sub, "checkout", "left"})
shell.RunCommand([]string{"git", "add", sub})
shell.Commit("ours")
shell.RunCommand([]string{"git", "checkout", "-b", "theirs", "HEAD~1"})
shell.RunCommand([]string{"git", "-C", sub, "checkout", "right"})
shell.RunCommand([]string{"git", "add", sub})
shell.Commit("theirs")
shell.RunCommand([]string{"git", "checkout", "ours"})
shell.RunCommand([]string{"git", "-C", sub, "checkout", "left"})
shell.RunCommandExpectError([]string{"git", "merge", "theirs"})
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Files().
Focus().
Lines(
Contains("UU my_submodule_path (submodule)").IsSelected(),
).
// Enter opens the resolution menu instead of entering the submodule.
// The two candidate commits are shown with their summaries.
Press(keys.Universal.GoInto).
Tap(func() {
t.ExpectPopup().Menu().
Title(Equals("Merge conflicts")).
Select(Contains("Take current commit").Contains("left")).
Select(Contains("Take incoming commit").Contains("right")).
Cancel()
}).
// Space opens the same menu; take the incoming commit to resolve.
PressPrimaryAction().
Tap(func() {
t.ExpectPopup().Menu().
Title(Equals("Merge conflicts")).
Select(Contains("Take incoming commit")).
Confirm()
}).
Lines(
Contains("M my_submodule_path (submodule)").IsSelected(),
)
},
})