mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 15:46:26 -04:00
`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) <noreply@anthropic.com>
86 lines
2 KiB
Go
86 lines
2 KiB
Go
package mergeconflicts
|
|
|
|
// mergeConflict : A git conflict with a start, ancestor (if exists), target, and end corresponding to line
|
|
// numbers in the file where the conflict markers appear.
|
|
// If no ancestor is present (i.e. we're not using the diff3 algorithm), then
|
|
// the `ancestor` field's value will be -1
|
|
type mergeConflict struct {
|
|
start int
|
|
ancestor int
|
|
target int
|
|
end int
|
|
}
|
|
|
|
func (c *mergeConflict) hasAncestor() bool {
|
|
return c.ancestor >= 0
|
|
}
|
|
|
|
func (c *mergeConflict) isMarkerLine(i int) bool {
|
|
return i == c.start ||
|
|
i == c.ancestor ||
|
|
i == c.target ||
|
|
i == c.end
|
|
}
|
|
|
|
type Selection int
|
|
|
|
const (
|
|
TOP Selection = iota
|
|
MIDDLE
|
|
BOTTOM
|
|
BOTH
|
|
)
|
|
|
|
func (s Selection) isIndexToKeep(conflict *mergeConflict, i int) bool {
|
|
// we're only handling one conflict at a time so any lines outside this
|
|
// conflict we'll keep
|
|
if i < conflict.start || conflict.end < i {
|
|
return true
|
|
}
|
|
|
|
if conflict.isMarkerLine(i) {
|
|
return false
|
|
}
|
|
|
|
return s.selected(conflict, i)
|
|
}
|
|
|
|
func (s Selection) bounds(c *mergeConflict) (int, int) {
|
|
switch s {
|
|
case TOP:
|
|
if c.hasAncestor() {
|
|
return c.start, c.ancestor
|
|
}
|
|
return c.start, c.target
|
|
case MIDDLE:
|
|
return c.ancestor, c.target
|
|
case BOTTOM:
|
|
return c.target, 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
|
|
}
|
|
|
|
func availableSelections(c *mergeConflict) []Selection {
|
|
if c.hasAncestor() {
|
|
return []Selection{TOP, MIDDLE, BOTTOM}
|
|
}
|
|
return []Selection{TOP, BOTTOM}
|
|
}
|