Better main view display for conflicing files

For the less common conflict types DD, AU, UA, DU, and UD, we would previously
only show "* Unmerged path" in the main view, which isn't helpful. Also, for
some of these we would split the main view and show this text both in the
unstaged changes and staged changes views, which is a bit embarrassing.

Improve this by offering more explanation about what's going on, and what the
most likely way to resolve the situation is for each case.
This commit is contained in:
Stefan Haller 2025-03-26 18:26:18 +01:00
parent a09ca592fa
commit 2e1be45957
3 changed files with 65 additions and 0 deletions

View file

@ -1,6 +1,7 @@
package models
import (
"github.com/jesseduffield/lazygit/pkg/i18n"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo"
)
@ -101,6 +102,22 @@ func (f *File) GetIsFile() bool {
return true
}
func (f *File) GetMergeStateDescription(tr *i18n.TranslationSet) string {
m := map[string]string{
"DD": tr.MergeConflictDescription_DD,
"AU": tr.MergeConflictDescription_AU,
"UA": tr.MergeConflictDescription_UA,
"DU": tr.MergeConflictDescription_DU,
"UD": tr.MergeConflictDescription_UD,
}
if description, ok := m[f.ShortStatus]; ok {
return description
}
panic("should only be called if there's a merge conflict")
}
type StatusFields struct {
HasStagedChanges bool
HasUnstagedChanges bool

View file

@ -268,6 +268,38 @@ func (self *FilesController) GetOnRenderToMain() func() {
self.c.Helpers().MergeConflicts.Render()
return
}
} else if node.File != nil && node.File.HasMergeConflicts {
opts := types.RefreshMainOpts{
Pair: self.c.MainViewPairs().Normal,
Main: &types.ViewUpdateOpts{
Title: self.c.Tr.DiffTitle,
SubTitle: self.c.Helpers().Diff.IgnoringWhitespaceSubTitle(),
},
}
message := node.File.GetMergeStateDescription(self.c.Tr)
message += "\n\n" + fmt.Sprintf(self.c.Tr.MergeConflictPressEnterToResolve,
self.c.UserConfig().Keybinding.Universal.GoInto)
if self.c.Views().Main.InnerWidth() > 70 {
// If the main view is very wide, wrap the message to increase readability
lines, _, _ := utils.WrapViewLinesToWidth(true, false, message, 70, 4)
message = strings.Join(lines, "\n")
}
if node.File.ShortStatus == "DU" || node.File.ShortStatus == "UD" {
cmdObj := self.c.Git().Diff.DiffCmdObj([]string{"--base", "--", node.GetPath()})
task := types.NewRunPtyTask(cmdObj.GetCmd())
task.Prefix = message + "\n\n"
if node.File.ShortStatus == "DU" {
task.Prefix += self.c.Tr.MergeConflictIncomingDiff
} else {
task.Prefix += self.c.Tr.MergeConflictCurrentDiff
}
task.Prefix += "\n\n"
opts.Main.Task = task
} else {
opts.Main.Task = types.NewRenderStringTask(message)
}
self.c.RenderToMainViews(opts)
return
}
self.c.Helpers().MergeConflicts.ResetMergeState()

View file

@ -99,6 +99,14 @@ type TranslationSet struct {
FilterLabelUntrackedFiles string
FilterLabelConflictingFiles string
MergeConflictsTitle string
MergeConflictDescription_DD string
MergeConflictDescription_AU string
MergeConflictDescription_UA string
MergeConflictDescription_DU string
MergeConflictDescription_UD string
MergeConflictIncomingDiff string
MergeConflictCurrentDiff string
MergeConflictPressEnterToResolve string
Checkout string
CheckoutTooltip string
CantCheckoutBranchWhilePulling string
@ -1112,6 +1120,14 @@ func EnglishTranslationSet() *TranslationSet {
PullTooltip: "Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch.",
Scroll: "Scroll",
MergeConflictsTitle: "Merge conflicts",
MergeConflictDescription_DD: "Conflict: this file was moved or renamed both in the current and the incoming changes, but to different destinations. I don't know which ones, but they should both show up as conflicts too (marked 'AU' and 'UA', respectively). The most likely resolution is to delete this file, and pick one of the destinations and delete the other.",
MergeConflictDescription_AU: "Conflict: this file is the destination of a move or rename in the current changes, but was moved or renamed to a different destination in the incoming changes. That other destination should also show up as a conflict (marked 'UA'), as well as the file that both were renamed from (marked 'DD').",
MergeConflictDescription_UA: "Conflict: this file is the destination of a move or rename in the incoming changes, but was moved or renamed to a different destination in the current changes. That other destination should also show up as a conflict (marked 'AU'), as well as the file that both were renamed from (marked 'DD').",
MergeConflictDescription_DU: "Conflict: this file was deleted in the current changes and modified in the incoming changes.\n\nThe most likely resolution is to delete the file after applying the incoming modifications manually to some other place in the code.",
MergeConflictDescription_UD: "Conflict: this file was modified in the current changes and deleted in incoming changes.\n\nThe most likely resolution is to delete the file after applying the current modifications manually to some other place in the code.",
MergeConflictIncomingDiff: "Incoming changes:",
MergeConflictCurrentDiff: "Current changes:",
MergeConflictPressEnterToResolve: "Press %s to resolve.",
Checkout: "Checkout",
CheckoutTooltip: "Checkout selected item.",
CantCheckoutBranchWhilePulling: "You cannot checkout another branch while pulling the current branch",