From ed3f4db4f91c4db7f7f6873406ae92240c02ec5f Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Wed, 1 Jul 2026 09:30:17 +0200 Subject: [PATCH] Pick both hunks, not the common ancestor, in diff3 conflicts `b` on a merge conflict is meant to keep both sides. With the diff3 conflict style git additionally renders the common ancestor between the two sides, and the old ALL selection kept everything between the outermost markers, dragging that ancestor into the resolved file. Rename the selection from ALL to BOTH and restrict it to the top and bottom hunks so the common base is dropped. Without the diff3 style there is no ancestor section, so the behaviour there is unchanged. The user-facing keybinding config was already named pickBothHunks; only the internal enum, handler, translation and log string still said "all". Co-Authored-By: Claude Opus 4.8 (1M context) --- docs-master/keybindings/Keybindings_en.md | 2 +- docs-master/keybindings/Keybindings_ja.md | 2 +- docs-master/keybindings/Keybindings_ko.md | 2 +- docs-master/keybindings/Keybindings_nl.md | 2 +- docs-master/keybindings/Keybindings_pl.md | 2 +- docs-master/keybindings/Keybindings_pt.md | 2 +- docs-master/keybindings/Keybindings_ru.md | 2 +- docs-master/keybindings/Keybindings_zh-CN.md | 2 +- docs-master/keybindings/Keybindings_zh-TW.md | 2 +- pkg/gui/controllers/merge_conflicts_controller.go | 12 ++++++------ pkg/gui/mergeconflicts/merge_conflict.go | 15 ++++++++++++--- pkg/i18n/english.go | 4 ++-- .../tests/conflicts/pick_both_hunks_diff3.go | 5 +---- 13 files changed, 30 insertions(+), 24 deletions(-) diff --git a/docs-master/keybindings/Keybindings_en.md b/docs-master/keybindings/Keybindings_en.md index ba9b45c4a..b105b8108 100644 --- a/docs-master/keybindings/Keybindings_en.md +++ b/docs-master/keybindings/Keybindings_en.md @@ -205,7 +205,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| | `` `` | Pick hunk | | -| `` b `` | Pick all hunks | | +| `` b `` | Pick both hunks | | | `` , k `` | Previous hunk | | | `` , j `` | Next hunk | | | `` , h `` | Previous conflict | | diff --git a/docs-master/keybindings/Keybindings_ja.md b/docs-master/keybindings/Keybindings_ja.md index 77283ffd8..a31d93d1a 100644 --- a/docs-master/keybindings/Keybindings_ja.md +++ b/docs-master/keybindings/Keybindings_ja.md @@ -287,7 +287,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| | `` `` | ハンクを選択 | | -| `` b `` | すべてのハンクを選択 | | +| `` b `` | Pick both hunks | | | `` , k `` | 前のハンク | | | `` , j `` | 次のハンク | | | `` , h `` | 前のコンフリクト | | diff --git a/docs-master/keybindings/Keybindings_ko.md b/docs-master/keybindings/Keybindings_ko.md index 4463c612a..ebf943868 100644 --- a/docs-master/keybindings/Keybindings_ko.md +++ b/docs-master/keybindings/Keybindings_ko.md @@ -144,7 +144,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| | `` `` | Pick hunk | | -| `` b `` | Pick all hunks | | +| `` b `` | Pick both hunks | | | `` , k `` | 이전 hunk를 선택 | | | `` , j `` | 다음 hunk를 선택 | | | `` , h `` | 이전 충돌을 선택 | | diff --git a/docs-master/keybindings/Keybindings_nl.md b/docs-master/keybindings/Keybindings_nl.md index 16a4856a4..a7d7b09ac 100644 --- a/docs-master/keybindings/Keybindings_nl.md +++ b/docs-master/keybindings/Keybindings_nl.md @@ -213,7 +213,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| | `` `` | Kies stuk | | -| `` b `` | Kies beide stukken | | +| `` b `` | Pick both hunks | | | `` , k `` | Selecteer bovenste hunk | | | `` , j `` | Selecteer onderste hunk | | | `` , h `` | Selecteer voorgaand conflict | | diff --git a/docs-master/keybindings/Keybindings_pl.md b/docs-master/keybindings/Keybindings_pl.md index 06f7af859..1f6710416 100644 --- a/docs-master/keybindings/Keybindings_pl.md +++ b/docs-master/keybindings/Keybindings_pl.md @@ -209,7 +209,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| | `` `` | Wybierz fragment | | -| `` b `` | Wybierz wszystkie fragmenty | | +| `` b `` | Pick both hunks | | | `` , k `` | Poprzedni fragment | | | `` , j `` | Następny fragment | | | `` , h `` | Poprzedni konflikt | | diff --git a/docs-master/keybindings/Keybindings_pt.md b/docs-master/keybindings/Keybindings_pt.md index 2a9e6497c..a2d163735 100644 --- a/docs-master/keybindings/Keybindings_pt.md +++ b/docs-master/keybindings/Keybindings_pt.md @@ -273,7 +273,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| | `` `` | Escolha o local | | -| `` b `` | Pegar todos os pedaços | | +| `` b `` | Pick both hunks | | | `` , k `` | Trecho anterior | | | `` , j `` | Próximo trecho | | | `` , h `` | Conflito anterior | | diff --git a/docs-master/keybindings/Keybindings_ru.md b/docs-master/keybindings/Keybindings_ru.md index bbd355c23..68be4a601 100644 --- a/docs-master/keybindings/Keybindings_ru.md +++ b/docs-master/keybindings/Keybindings_ru.md @@ -114,7 +114,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| | `` `` | Выбрать эту часть | | -| `` b `` | Выбрать все части | | +| `` b `` | Pick both hunks | | | `` , k `` | Выбрать предыдущую часть | | | `` , j `` | Выбрать следующую часть | | | `` , h `` | Выбрать предыдущий конфликт | | diff --git a/docs-master/keybindings/Keybindings_zh-CN.md b/docs-master/keybindings/Keybindings_zh-CN.md index 57d445d5b..6828c35e3 100644 --- a/docs-master/keybindings/Keybindings_zh-CN.md +++ b/docs-master/keybindings/Keybindings_zh-CN.md @@ -294,7 +294,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| | `` `` | 选中区块 | | -| `` b `` | 选中所有区块 | | +| `` b `` | Pick both hunks | | | `` , k `` | 选择顶部块 | | | `` , j `` | 选择底部块 | | | `` , h `` | 选择上一个冲突 | | diff --git a/docs-master/keybindings/Keybindings_zh-TW.md b/docs-master/keybindings/Keybindings_zh-TW.md index a693281f1..56d383ff9 100644 --- a/docs-master/keybindings/Keybindings_zh-TW.md +++ b/docs-master/keybindings/Keybindings_zh-TW.md @@ -90,7 +90,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | Key | Action | Info | |-----|--------|-------------| | `` `` | 挑選程式碼片段 | | -| `` b `` | 挑選所有程式碼片段 | | +| `` b `` | Pick both hunks | | | `` , k `` | 選擇上一段 | | | `` , j `` | 選擇下一段 | | | `` , h `` | 選擇上一個衝突 | | diff --git a/pkg/gui/controllers/merge_conflicts_controller.go b/pkg/gui/controllers/merge_conflicts_controller.go index e1e3f8e2c..898eb356b 100644 --- a/pkg/gui/controllers/merge_conflicts_controller.go +++ b/pkg/gui/controllers/merge_conflicts_controller.go @@ -35,8 +35,8 @@ func (self *MergeConflictsController) GetKeybindings(opts types.KeybindingsOpts) }, { Keys: opts.GetKeys(opts.Config.Main.PickBothHunks), - Handler: self.withRenderAndFocus(self.HandlePickAllHunks), - Description: self.c.Tr.PickAllHunks, + Handler: self.withRenderAndFocus(self.HandlePickBothHunks), + Description: self.c.Tr.PickBothHunks, DisplayOnScreen: true, }, { @@ -247,8 +247,8 @@ func (self *MergeConflictsController) HandlePickHunk() error { return self.pickSelection(self.context().GetState().Selection()) } -func (self *MergeConflictsController) HandlePickAllHunks() error { - return self.pickSelection(mergeconflicts.ALL) +func (self *MergeConflictsController) HandlePickBothHunks() error { + return self.pickSelection(mergeconflicts.BOTH) } func (self *MergeConflictsController) pickSelection(selection mergeconflicts.Selection) error { @@ -290,8 +290,8 @@ func (self *MergeConflictsController) resolveConflict(selection mergeconflicts.S logStr = "Picking middle hunk" case mergeconflicts.BOTTOM: logStr = "Picking bottom hunk" - case mergeconflicts.ALL: - logStr = "Picking all hunks" + case mergeconflicts.BOTH: + logStr = "Picking both hunks" } self.c.LogAction("Resolve merge conflict") self.c.LogCommand(logStr, false) diff --git a/pkg/gui/mergeconflicts/merge_conflict.go b/pkg/gui/mergeconflicts/merge_conflict.go index 9b9b72f55..4252aa384 100644 --- a/pkg/gui/mergeconflicts/merge_conflict.go +++ b/pkg/gui/mergeconflicts/merge_conflict.go @@ -28,7 +28,7 @@ const ( TOP Selection = iota MIDDLE BOTTOM - ALL + BOTH ) func (s Selection) isIndexToKeep(conflict *mergeConflict, i int) bool { @@ -56,14 +56,23 @@ func (s Selection) bounds(c *mergeConflict) (int, int) { return c.ancestor, c.target case BOTTOM: return c.target, c.end - case ALL: - return c.start, c.end + case BOTH: + // BOTH spans two disjoint hunks, so it has no single range; callers + // go through selected() instead of asking for its bounds. + panic("BOTH has no single range") } panic("unexpected selection for merge conflict") } func (s Selection) selected(c *mergeConflict, idx int) bool { + // BOTH keeps the top and bottom hunks but drops the common ancestor in + // between (which is only present with the diff3 conflict style), so it + // isn't a single contiguous range like the other selections. + if s == BOTH { + return TOP.selected(c, idx) || BOTTOM.selected(c, idx) + } + start, end := s.bounds(c) return start < idx && idx < end } diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 6ddf356cd..db8cdbd5e 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -320,7 +320,7 @@ type TranslationSet struct { ViewConflictsMenuItem string AbortMenuItem string PickHunk string - PickAllHunks string + PickBothHunks string ViewMergeRebaseOptions string ViewMergeRebaseOptionsTooltip string ViewMergeOptions string @@ -1338,7 +1338,7 @@ func EnglishTranslationSet() *TranslationSet { RewordCommitEditor: "Reword with editor", Error: "Error", PickHunk: "Pick hunk", - PickAllHunks: "Pick all hunks", + PickBothHunks: "Pick both hunks", Undo: "Undo", UndoReflog: "Undo", RedoReflog: "Redo", diff --git a/pkg/integration/tests/conflicts/pick_both_hunks_diff3.go b/pkg/integration/tests/conflicts/pick_both_hunks_diff3.go index 2df3ab3a3..59a634c3b 100644 --- a/pkg/integration/tests/conflicts/pick_both_hunks_diff3.go +++ b/pkg/integration/tests/conflicts/pick_both_hunks_diff3.go @@ -36,9 +36,6 @@ var PickBothHunksDiff3 = NewIntegrationTest(NewIntegrationTestArgs{ t.Views().Files().IsEmpty() t.FileSystem().FileContent("file", - /* EXPECTED: - Equals("\nThis\nIs\nThe\nFirst Change\nSecond Change\nFile\n") - ACTUAL: */ - Equals("\nThis\nIs\nThe\nFirst Change\nOriginal\nSecond Change\nFile\n")) + Equals("\nThis\nIs\nThe\nFirst Change\nSecond Change\nFile\n")) }, })