Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/Config.md
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,7 @@ keybinding:
viewResetOptions: D
fetch: f
toggleTreeView: '`'
openMergeTool: M
openMergeOptions: M
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a breaking change (users might have changed the keybinding in their config file). We have the technology to migrate users's config files to account for this, and we should do that by adding an entry to this array.

openStatusFilter: <c-b>
copyFileInfoToClipboard: "y"
collapseAll: '-'
Expand Down
2 changes: 1 addition & 1 deletion docs/keybindings/Keybindings_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
| `` ` `` | Toggle file tree view | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory.<br><br>The default can be changed in the config file with the key 'gui.showFileTree'. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` M `` | Open external merge tool | Run `git mergetool`. |
| `` M `` | View merge conflict options | View options for resolving merge conflicts. |
| `` f `` | Fetch | Fetch changes from remote. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
Expand Down
2 changes: 1 addition & 1 deletion docs/keybindings/Keybindings_ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ _凡例:`<c-b>` はctrl+b、`<a-b>` はalt+b、`B` はshift+bを意味
| `` D `` | リセット | 作業ツリーのリセットオプション(例:作業ツリーの完全破棄)を表示します。 |
| `` ` `` | ファイルツリービューを切り替え | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory.<br><br>The default can be changed in the config file with the key 'gui.showFileTree'. |
| `` <c-t> `` | 外部差分ツールを開く(git difftool) | |
| `` M `` | 外部マージツールを開く | `git mergetool`を実行します。 |
| `` M `` | View merge conflict options | View options for resolving merge conflicts. |
| `` f `` | フェッチ | リモートから変更をフェッチします。 |
| `` - `` | すべてのファイルを折りたたむ | ファイルツリー内のすべてのディレクトリを折りたたみます |
| `` = `` | すべてのファイルを展開 | ファイルツリー内のすべてのディレクトリを展開します |
Expand Down
2 changes: 1 addition & 1 deletion docs/keybindings/Keybindings_ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` D `` | 초기화 | View reset options for working tree (e.g. nuking the working tree). |
| `` ` `` | 파일 트리뷰로 전환 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory.<br><br>The default can be changed in the config file with the key 'gui.showFileTree'. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` M `` | Git mergetool를 열기 | Run `git mergetool`. |
| `` M `` | View merge conflict options | View options for resolving merge conflicts. |
| `` f `` | Fetch | Fetch changes from remote. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
Expand Down
2 changes: 1 addition & 1 deletion docs/keybindings/Keybindings_nl.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
| `` ` `` | Toggle bestandsboom weergave | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory.<br><br>The default can be changed in the config file with the key 'gui.showFileTree'. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` M `` | Open external merge tool | Run `git mergetool`. |
| `` M `` | View merge conflict options | View options for resolving merge conflicts. |
| `` f `` | Fetch | Fetch changes from remote. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
Expand Down
2 changes: 1 addition & 1 deletion docs/keybindings/Keybindings_pl.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ _Legenda: `<c-b>` oznacza ctrl+b, `<a-b>` oznacza alt+b, `B` oznacza shift+b_
| `` D `` | Reset | Wyświetl opcje resetu dla drzewa roboczego (np. zniszczenie drzewa roboczego). |
| `` ` `` | Przełącz widok drzewa plików | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory.<br><br>The default can be changed in the config file with the key 'gui.showFileTree'. |
| `` <c-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
| `` M `` | Otwórz zewnętrzne narzędzie scalania | Uruchom `git mergetool`. |
| `` M `` | View merge conflict options | View options for resolving merge conflicts. |
| `` f `` | Pobierz | Pobierz zmiany ze zdalnego serwera. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
Expand Down
2 changes: 1 addition & 1 deletion docs/keybindings/Keybindings_pt.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` D `` | Restaurar | Opções de redefinição de exibição para árvore de trabalho (por exemplo, nukando a árvore de trabalho). |
| `` ` `` | Alternar exibição de árvore de arquivo | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory.<br><br>The default can be changed in the config file with the key 'gui.showFileTree'. |
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
| `` M `` | Abrir ferramenta de merge externa | Execute `git mergetool`. |
| `` M `` | View merge conflict options | View options for resolving merge conflicts. |
| `` f `` | Buscar | Buscar alterações do controle remoto. |
| `` - `` | Recolher todos os arquivos | Recolher todos os diretórios na árvore de arquivos |
| `` = `` | Expandir todos os arquivos | Expandir todos os diretórios na árvore do arquivo |
Expand Down
2 changes: 1 addition & 1 deletion docs/keybindings/Keybindings_ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ _Связки клавиш_
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
| `` ` `` | Переключить вид дерева файлов | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory.<br><br>The default can be changed in the config file with the key 'gui.showFileTree'. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` M `` | Открыть внешний инструмент слияния (git mergetool) | Run `git mergetool`. |
| `` M `` | View merge conflict options | View options for resolving merge conflicts. |
| `` f `` | Получить изменения | Fetch changes from remote. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
Expand Down
2 changes: 1 addition & 1 deletion docs/keybindings/Keybindings_zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ _图例:`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
| `` D `` | 重置 | 查看工作树的重置选项(例如:清除工作树)。 |
| `` ` `` | 切换文件树视图 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory.<br><br>The default can be changed in the config file with the key 'gui.showFileTree'. |
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
| `` M `` | 打开外部合并工具(git mergetool) | 执行 `git mergetool`. |
| `` M `` | View merge conflict options | View options for resolving merge conflicts. |
| `` f `` | 抓取 | 从远程获取变更 |
| `` - `` | 折叠全部文件 | 折叠文件树中的全部目录 |
| `` = `` | 展开全部文件 | 展开文件树中的全部目录 |
Expand Down
2 changes: 1 addition & 1 deletion docs/keybindings/Keybindings_zh-TW.md
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B
| `` D `` | 重設 | View reset options for working tree (e.g. nuking the working tree). |
| `` ` `` | 顯示檔案樹狀視圖 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory.<br><br>The default can be changed in the config file with the key 'gui.showFileTree'. |
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
| `` M `` | 開啟外部合併工具 | 執行 `git mergetool`。 |
| `` M `` | View merge conflict options | View options for resolving merge conflicts. |
| `` f `` | 擷取 | 同步遠端異動 |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
Expand Down
24 changes: 24 additions & 0 deletions pkg/commands/git_commands/working_tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os"
"path/filepath"
"regexp"
"strings"

"github.com/go-errors/errors"
"github.com/jesseduffield/lazygit/pkg/commands/models"
Expand Down Expand Up @@ -407,3 +408,26 @@ func (self *WorkingTreeCommands) ResetMixed(ref string) error {

return self.cmd.New(cmdArgs).Run()
}

func (self *WorkingTreeCommands) ObjectIDAtStage(path string, stage int) (string, error) {
cmdArgs := NewGitCmd("rev-parse").
Arg(fmt.Sprintf(":%d:%s", stage, path)).
ToArgv()

output, err := self.cmd.New(cmdArgs).RunWithOutput()
if err != nil {
return "", err
}

return strings.TrimSpace(output), nil
}

func (self *WorkingTreeCommands) MergeFile(strategy string, oursID string, baseID string, theirsID string) (string, error) {
cmdArgs := NewGitCmd("merge-file").
Arg("--object-id").
Arg(strategy).
Arg("-p", oursID, baseID, theirsID).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpicks: would use --stdout instead of -p for better readability, and put it on a line by itself; otherwise it looks like it is an option that takes the object ids as arguments.

Suggested change
Arg("-p", oursID, baseID, theirsID).
Arg("--stdout").
Arg(oursID, baseID, theirsID).

ToArgv()

return self.cmd.New(cmdArgs).RunWithOutput()
}
2 changes: 1 addition & 1 deletion pkg/config/app_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -897,7 +897,7 @@ keybinding:
toggleStagedAll: a
viewResetOptions: D
fetch: f
openMergeTool: M
openMergeOptions: M
openStatusFilter: <c-b>
copyFileInfoToClipboard: "y"
collapseAll: '-'
Expand Down
4 changes: 2 additions & 2 deletions pkg/config/user_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ type KeybindingFilesConfig struct {
ViewResetOptions string `yaml:"viewResetOptions"`
Fetch string `yaml:"fetch"`
ToggleTreeView string `yaml:"toggleTreeView"`
OpenMergeTool string `yaml:"openMergeTool"`
OpenMergeOptions string `yaml:"openMergeOptions"`
OpenStatusFilter string `yaml:"openStatusFilter"`
CopyFileInfoToClipboard string `yaml:"copyFileInfoToClipboard"`
CollapseAll string `yaml:"collapseAll"`
Expand Down Expand Up @@ -950,7 +950,7 @@ func GetDefaultConfig() *UserConfig {
ViewResetOptions: "D",
Fetch: "f",
ToggleTreeView: "`",
OpenMergeTool: "M",
OpenMergeOptions: "M",
OpenStatusFilter: "<c-b>",
ConfirmDiscard: "x",
CopyFileInfoToClipboard: "y",
Expand Down
4 changes: 2 additions & 2 deletions pkg/gui/command_log_panel.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ func (gui *Gui) getRandomTip() string {
formattedKey(config.Universal.Remove),
),
fmt.Sprintf(
"If you need to pull out the big guns to resolve merge conflicts, you can press '%s' in the files panel to open 'git mergetool'",
formattedKey(config.Files.OpenMergeTool),
"If you need to pull out the big guns to resolve merge conflicts, you can press '%s' in the files panel to open merge options",
formattedKey(config.Files.OpenMergeOptions),
),
fmt.Sprintf(
"To revert a commit, press '%s' on that commit",
Expand Down
98 changes: 94 additions & 4 deletions pkg/gui/controllers/files_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package controllers
import (
"errors"
"fmt"
"os"
"path/filepath"
"strings"

Expand All @@ -12,6 +13,7 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
"github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo"
Expand Down Expand Up @@ -178,10 +180,12 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types
Description: self.c.Tr.OpenDiffTool,
},
{
Key: opts.GetKey(opts.Config.Files.OpenMergeTool),
Handler: self.c.Helpers().WorkingTree.OpenMergeTool,
Description: self.c.Tr.OpenMergeTool,
Tooltip: self.c.Tr.OpenMergeToolTooltip,
Key: opts.GetKey(opts.Config.Files.OpenMergeOptions),
Handler: self.withItems(self.createMergeConflictMenu),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of implementing the menu here, we should implement it in WorkingTreeHelper.OpenMergeTool (and rename it accordingly). That way, it will also be used when you are in the merge conflict editor.

Edit: hm, when you are in the merge conflict editor you probably expect to work only on the current file you are in. So we'd have to pass a list of file paths to that function, and pass the selected ones from here, and the current one from merge_conflicts_controller.

Description: self.c.Tr.ViewMergeConflictOptions,
Tooltip: self.c.Tr.ViewMergeConflictOptionsTooltip,
OpensMenu: true,
DisplayOnScreen: true,
},
{
Key: opts.GetKey(opts.Config.Files.Fetch),
Expand Down Expand Up @@ -1024,6 +1028,92 @@ func (self *FilesController) createStashMenu() error {
})
}

func (self *FilesController) createMergeConflictMenu(nodes []*filetree.FileNode) error {
onMergeStrategySelected := func(strategy string) error {
normalizedNodes := normalisedSelectedNodes(nodes)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This relies on the assumption that all currently shown files have conflicts. This doesn't have to be true; while we automatically filter for only conflicted files when there are any, the user can open the filter menu (ctrl-b) and choose "no filter" to show all files.

Which means we should probably filter on the status again here.

Also, for files that have non-textual conflicts (see #4431), I guess the git rev-parse commands will probably error? So we should filter those out, too.

fileNodes := lo.Filter(normalizedNodes, func(node *filetree.FileNode, _ int) bool {
return node.File != nil
})
filenames := lo.Map(fileNodes, func(node *filetree.FileNode, _ int) string {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: would call the variable filepaths.

return node.GetPath()
})

for _, filename := range filenames {
baseID, err := self.c.Git().WorkingTree.ObjectIDAtStage(filename, 1)
if err != nil {
return err
}

oursID, err := self.c.Git().WorkingTree.ObjectIDAtStage(filename, 2)
if err != nil {
return err
}

theirsID, err := self.c.Git().WorkingTree.ObjectIDAtStage(filename, 3)
if err != nil {
return err
}

output, err := self.c.Git().WorkingTree.MergeFile(strategy, oursID, baseID, theirsID)
if err != nil {
return err
}

if err = os.WriteFile(filename, []byte(output), 0o644); err != nil {
return err
}
}

err := self.c.Git().WorkingTree.StageFiles(filenames, nil)
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
}

cmdColor := style.FgBlue
return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.MergeConflictOptionsTitle,
Items: []*types.MenuItem{
{
LabelColumns: []string{
self.c.Tr.UseHead,
cmdColor.Sprint("git merge-file --ours"),
},
OnPress: func() error {
return onMergeStrategySelected("--ours")
},
Key: 'h',
},
{
LabelColumns: []string{
self.c.Tr.UseIncoming,
cmdColor.Sprint("git merge-file --theirs"),
},
OnPress: func() error {
return onMergeStrategySelected("--theirs")
},
Key: 'i',
},
{
LabelColumns: []string{
self.c.Tr.UseBoth,
cmdColor.Sprint("git merge-file --union"),
},
OnPress: func() error {
return onMergeStrategySelected("--union")
},
Key: 'b',
},
{
LabelColumns: []string{
self.c.Tr.OpenMergeTool,
cmdColor.Sprint("git mergetool"),
},
OnPress: self.c.Helpers().WorkingTree.OpenMergeTool,
Key: 'm',
},
},
})
}

func (self *FilesController) openCopyMenu() error {
node := self.context().GetSelected()

Expand Down
2 changes: 1 addition & 1 deletion pkg/gui/controllers/merge_conflicts_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func (self *MergeConflictsController) GetKeybindings(opts types.KeybindingsOpts)
Tag: "navigation",
},
{
Key: opts.GetKey(opts.Config.Files.OpenMergeTool),
Key: opts.GetKey(opts.Config.Files.OpenMergeOptions),
Handler: self.c.Helpers().WorkingTree.OpenMergeTool,
Description: self.c.Tr.OpenMergeTool,
Tooltip: self.c.Tr.OpenMergeToolTooltip,
Expand Down
13 changes: 12 additions & 1 deletion pkg/i18n/english.go
Original file line number Diff line number Diff line change
Expand Up @@ -898,8 +898,13 @@ type TranslationSet struct {
BreakingChangesTitle string
BreakingChangesMessage string
BreakingChangesByVersion map[string]string
ViewMergeConflictOptions string
ViewMergeConflictOptionsTooltip string
MergeConflictOptionsTitle string
UseHead string
UseIncoming string
UseBoth string
}

type Bisect struct {
MarkStart string
ResetTitle string
Expand Down Expand Up @@ -1970,6 +1975,12 @@ func EnglishTranslationSet() *TranslationSet {
CustomCommands: "Custom commands",
NoApplicableCommandsInThisContext: "(No applicable commands in this context)",
SelectCommitsOfCurrentBranch: "Select commits of current branch",
ViewMergeConflictOptions: "View merge conflict options",
ViewMergeConflictOptionsTooltip: "View options for resolving merge conflicts.",
MergeConflictOptionsTitle: "Resolve merge conflicts",
UseHead: "Use HEAD",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For non-textual conflicts we settled on the terms "current changes" (for head) and "incoming changes"; see #4431, so I'd suggest to use those here, too.

Also, we don't use Title Case in menu items, so it should be "Use current changes" and "Use both".

UseIncoming: "Use Incoming",
UseBoth: "Use Both",

Actions: Actions{
// TODO: combine this with the original keybinding descriptions (those are all in lowercase atm)
Expand Down
Loading