mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-10-22 06:52:19 +03:00
Add merge options menu
Replace merge-tool with merge options menu that allows resolving all conflicts for selected files as ours, theirs, or union, while still providing access to the merge tool.
This commit is contained in:
committed by
Stefan Haller
parent
1f002af06b
commit
703f053a7e
@@ -619,7 +619,7 @@ keybinding:
|
|||||||
viewResetOptions: D
|
viewResetOptions: D
|
||||||
fetch: f
|
fetch: f
|
||||||
toggleTreeView: '`'
|
toggleTreeView: '`'
|
||||||
openMergeTool: M
|
openMergeOptions: M
|
||||||
openStatusFilter: <c-b>
|
openStatusFilter: <c-b>
|
||||||
copyFileInfoToClipboard: "y"
|
copyFileInfoToClipboard: "y"
|
||||||
collapseAll: '-'
|
collapseAll: '-'
|
||||||
|
@@ -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). |
|
| `` 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'. |
|
| `` ` `` | 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) | |
|
| `` <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. |
|
| `` f `` | Fetch | Fetch changes from remote. |
|
||||||
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
| `` = `` | Expand all files | Expand all directories in the file tree |
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
@@ -210,7 +210,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| `` z `` | Undo | Undo last merge conflict resolution. |
|
| `` z `` | Undo | Undo last merge conflict resolution. |
|
||||||
| `` e `` | Edit file | Open file in external editor. |
|
| `` e `` | Edit file | Open file in external editor. |
|
||||||
| `` o `` | Open file | Open file in default application. |
|
| `` o `` | Open file | Open file in default application. |
|
||||||
| `` M `` | Open external merge tool | Run `git mergetool`. |
|
| `` M `` | View merge conflict options | View options for resolving merge conflicts. |
|
||||||
| `` <esc> `` | Return to files panel | |
|
| `` <esc> `` | Return to files panel | |
|
||||||
|
|
||||||
## Main panel (normal)
|
## Main panel (normal)
|
||||||
|
@@ -235,7 +235,7 @@ _凡例:`<c-b>` はctrl+b、`<a-b>` はalt+b、`B` はshift+bを意味
|
|||||||
| `` D `` | リセット | 作業ツリーのリセットオプション(例:作業ツリーの完全破棄)を表示します。 |
|
| `` 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'. |
|
| `` ` `` | ファイルツリービューを切り替え | 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) | |
|
| `` <c-t> `` | 外部差分ツールを開く(git difftool) | |
|
||||||
| `` M `` | 外部マージツールを開く | `git mergetool`を実行します。 |
|
| `` M `` | View merge conflict options | View options for resolving merge conflicts. |
|
||||||
| `` f `` | フェッチ | リモートから変更をフェッチします。 |
|
| `` f `` | フェッチ | リモートから変更をフェッチします。 |
|
||||||
| `` - `` | すべてのファイルを折りたたむ | ファイルツリー内のすべてのディレクトリを折りたたみます |
|
| `` - `` | すべてのファイルを折りたたむ | ファイルツリー内のすべてのディレクトリを折りたたみます |
|
||||||
| `` = `` | すべてのファイルを展開 | ファイルツリー内のすべてのディレクトリを展開します |
|
| `` = `` | すべてのファイルを展開 | ファイルツリー内のすべてのディレクトリを展開します |
|
||||||
@@ -292,7 +292,7 @@ _凡例:`<c-b>` はctrl+b、`<a-b>` はalt+b、`B` はshift+bを意味
|
|||||||
| `` z `` | 元に戻す | 最後のマージコンフリクト解決を元に戻します。 |
|
| `` z `` | 元に戻す | 最後のマージコンフリクト解決を元に戻します。 |
|
||||||
| `` e `` | ファイルを編集 | 外部エディタでファイルを開きます。 |
|
| `` e `` | ファイルを編集 | 外部エディタでファイルを開きます。 |
|
||||||
| `` o `` | ファイルを開く | デフォルトのアプリケーションでファイルを開きます。 |
|
| `` o `` | ファイルを開く | デフォルトのアプリケーションでファイルを開きます。 |
|
||||||
| `` M `` | 外部マージツールを開く | `git mergetool`を実行します。 |
|
| `` M `` | View merge conflict options | View options for resolving merge conflicts. |
|
||||||
| `` <esc> `` | ファイルパネルに戻る | |
|
| `` <esc> `` | ファイルパネルに戻る | |
|
||||||
|
|
||||||
## メインパネル(通常)
|
## メインパネル(通常)
|
||||||
|
@@ -152,7 +152,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| `` z `` | 되돌리기 | Undo last merge conflict resolution. |
|
| `` z `` | 되돌리기 | Undo last merge conflict resolution. |
|
||||||
| `` e `` | 파일 편집 | Open file in external editor. |
|
| `` e `` | 파일 편집 | Open file in external editor. |
|
||||||
| `` o `` | 파일 닫기 | Open file in default application. |
|
| `` o `` | 파일 닫기 | Open file in default application. |
|
||||||
| `` M `` | Git mergetool를 열기 | Run `git mergetool`. |
|
| `` M `` | View merge conflict options | View options for resolving merge conflicts. |
|
||||||
| `` <esc> `` | 파일 목록으로 돌아가기 | |
|
| `` <esc> `` | 파일 목록으로 돌아가기 | |
|
||||||
|
|
||||||
## 메인 패널 (Normal)
|
## 메인 패널 (Normal)
|
||||||
@@ -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). |
|
| `` 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'. |
|
| `` ` `` | 파일 트리뷰로 전환 | 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) | |
|
| `` <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. |
|
| `` f `` | Fetch | Fetch changes from remote. |
|
||||||
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
| `` = `` | Expand all files | Expand all directories in the file tree |
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
|
@@ -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). |
|
| `` 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'. |
|
| `` ` `` | 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) | |
|
| `` <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. |
|
| `` f `` | Fetch | Fetch changes from remote. |
|
||||||
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
| `` = `` | Expand all files | Expand all directories in the file tree |
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
@@ -218,7 +218,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| `` z `` | Ongedaan maken | Undo last merge conflict resolution. |
|
| `` z `` | Ongedaan maken | Undo last merge conflict resolution. |
|
||||||
| `` e `` | Verander bestand | Open file in external editor. |
|
| `` e `` | Verander bestand | Open file in external editor. |
|
||||||
| `` o `` | Open bestand | Open file in default application. |
|
| `` o `` | Open bestand | Open file in default application. |
|
||||||
| `` M `` | Open external merge tool | Run `git mergetool`. |
|
| `` M `` | View merge conflict options | View options for resolving merge conflicts. |
|
||||||
| `` <esc> `` | Ga terug naar het bestanden paneel | |
|
| `` <esc> `` | Ga terug naar het bestanden paneel | |
|
||||||
|
|
||||||
## Normaal
|
## Normaal
|
||||||
|
@@ -193,7 +193,7 @@ _Legenda: `<c-b>` oznacza ctrl+b, `<a-b>` oznacza alt+b, `B` oznacza shift+b_
|
|||||||
| `` z `` | Cofnij | Cofnij ostatnie rozwiązanie konfliktu scalania. |
|
| `` z `` | Cofnij | Cofnij ostatnie rozwiązanie konfliktu scalania. |
|
||||||
| `` e `` | Edytuj plik | Otwórz plik w zewnętrznym edytorze. |
|
| `` e `` | Edytuj plik | Otwórz plik w zewnętrznym edytorze. |
|
||||||
| `` o `` | Otwórz plik | Otwórz plik w domyślnej aplikacji. |
|
| `` o `` | Otwórz plik | Otwórz plik w domyślnej aplikacji. |
|
||||||
| `` M `` | Otwórz zewnętrzne narzędzie scalania | Uruchom `git mergetool`. |
|
| `` M `` | View merge conflict options | View options for resolving merge conflicts. |
|
||||||
| `` <esc> `` | Wróć do panelu plików | |
|
| `` <esc> `` | Wróć do panelu plików | |
|
||||||
|
|
||||||
## Panel główny (zatwierdzanie)
|
## Panel główny (zatwierdzanie)
|
||||||
@@ -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). |
|
| `` 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'. |
|
| `` ` `` | 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) | |
|
| `` <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. |
|
| `` f `` | Pobierz | Pobierz zmiany ze zdalnego serwera. |
|
||||||
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
| `` = `` | Expand all files | Expand all directories in the file tree |
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
|
@@ -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). |
|
| `` 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'. |
|
| `` ` `` | 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) | |
|
| `` <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. |
|
| `` f `` | Buscar | Buscar alterações do controle remoto. |
|
||||||
| `` - `` | Recolher todos os arquivos | Recolher todos os diretórios na árvore de arquivos |
|
| `` - `` | 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 |
|
| `` = `` | Expandir todos os arquivos | Expandir todos os diretórios na árvore do arquivo |
|
||||||
@@ -278,7 +278,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| `` z `` | Desfazer | Desfazer resolução de conflitos de última mesclagem. |
|
| `` z `` | Desfazer | Desfazer resolução de conflitos de última mesclagem. |
|
||||||
| `` e `` | Editar arquivo | Abrir arquivo no editor externo. |
|
| `` e `` | Editar arquivo | Abrir arquivo no editor externo. |
|
||||||
| `` o `` | Abrir arquivo | Abrir arquivo no aplicativo padrão. |
|
| `` o `` | Abrir arquivo | Abrir arquivo no aplicativo padrão. |
|
||||||
| `` M `` | Abrir ferramenta de merge externa | Execute `git mergetool`. |
|
| `` M `` | View merge conflict options | View options for resolving merge conflicts. |
|
||||||
| `` <esc> `` | Retornar ao painel de arquivos | |
|
| `` <esc> `` | Retornar ao painel de arquivos | |
|
||||||
|
|
||||||
## Painel principal (patch build)
|
## Painel principal (patch build)
|
||||||
|
@@ -122,7 +122,7 @@ _Связки клавиш_
|
|||||||
| `` z `` | Отменить | Undo last merge conflict resolution. |
|
| `` z `` | Отменить | Undo last merge conflict resolution. |
|
||||||
| `` e `` | Редактировать файл | Open file in external editor. |
|
| `` e `` | Редактировать файл | Open file in external editor. |
|
||||||
| `` o `` | Открыть файл | Open file in default application. |
|
| `` o `` | Открыть файл | Open file in default application. |
|
||||||
| `` M `` | Открыть внешний инструмент слияния (git mergetool) | Run `git mergetool`. |
|
| `` M `` | View merge conflict options | View options for resolving merge conflicts. |
|
||||||
| `` <esc> `` | Вернуться к панели файлов | |
|
| `` <esc> `` | Вернуться к панели файлов | |
|
||||||
|
|
||||||
## Главная панель (сборка патчей)
|
## Главная панель (сборка патчей)
|
||||||
@@ -390,7 +390,7 @@ _Связки клавиш_
|
|||||||
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
|
| `` 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'. |
|
| `` ` `` | Переключить вид дерева файлов | 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) | |
|
| `` <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. |
|
| `` f `` | Получить изменения | Fetch changes from remote. |
|
||||||
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
| `` = `` | Expand all files | Expand all directories in the file tree |
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
|
@@ -216,7 +216,7 @@ _图例:`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
|
|||||||
| `` D `` | 重置 | 查看工作树的重置选项(例如:清除工作树)。 |
|
| `` 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'. |
|
| `` ` `` | 切换文件树视图 | 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) | |
|
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||||
| `` M `` | 打开外部合并工具(git mergetool) | 执行 `git mergetool`. |
|
| `` M `` | View merge conflict options | View options for resolving merge conflicts. |
|
||||||
| `` f `` | 抓取 | 从远程获取变更 |
|
| `` f `` | 抓取 | 从远程获取变更 |
|
||||||
| `` - `` | 折叠全部文件 | 折叠文件树中的全部目录 |
|
| `` - `` | 折叠全部文件 | 折叠文件树中的全部目录 |
|
||||||
| `` = `` | 展开全部文件 | 展开文件树中的全部目录 |
|
| `` = `` | 展开全部文件 | 展开文件树中的全部目录 |
|
||||||
@@ -305,7 +305,7 @@ _图例:`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
|
|||||||
| `` z `` | 撤销 | 撤消上次合并冲突解决 |
|
| `` z `` | 撤销 | 撤消上次合并冲突解决 |
|
||||||
| `` e `` | 编辑文件 | 使用外部编辑器打开文件 |
|
| `` e `` | 编辑文件 | 使用外部编辑器打开文件 |
|
||||||
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
|
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
|
||||||
| `` M `` | 打开外部合并工具(git mergetool) | 执行 `git mergetool`. |
|
| `` M `` | View merge conflict options | View options for resolving merge conflicts. |
|
||||||
| `` <esc> `` | 返回文件面板 | |
|
| `` <esc> `` | 返回文件面板 | |
|
||||||
|
|
||||||
## 正在暂存
|
## 正在暂存
|
||||||
|
@@ -97,7 +97,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B
|
|||||||
| `` z `` | 復原 | Undo last merge conflict resolution. |
|
| `` z `` | 復原 | Undo last merge conflict resolution. |
|
||||||
| `` e `` | 編輯檔案 | 使用外部編輯器開啟 |
|
| `` e `` | 編輯檔案 | 使用外部編輯器開啟 |
|
||||||
| `` o `` | 開啟檔案 | 使用預設軟體開啟 |
|
| `` o `` | 開啟檔案 | 使用預設軟體開啟 |
|
||||||
| `` M `` | 開啟外部合併工具 | 執行 `git mergetool`。 |
|
| `` M `` | View merge conflict options | View options for resolving merge conflicts. |
|
||||||
| `` <esc> `` | 返回檔案面板 | |
|
| `` <esc> `` | 返回檔案面板 | |
|
||||||
|
|
||||||
## 主面板(預存)
|
## 主面板(預存)
|
||||||
@@ -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). |
|
| `` 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'. |
|
| `` ` `` | 顯示檔案樹狀視圖 | 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) | |
|
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
|
||||||
| `` M `` | 開啟外部合併工具 | 執行 `git mergetool`。 |
|
| `` M `` | View merge conflict options | View options for resolving merge conflicts. |
|
||||||
| `` f `` | 擷取 | 同步遠端異動 |
|
| `` f `` | 擷取 | 同步遠端異動 |
|
||||||
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
| `` = `` | Expand all files | Expand all directories in the file tree |
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
|
@@ -5,6 +5,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
@@ -407,3 +408,46 @@ func (self *WorkingTreeCommands) ResetMixed(ref string) error {
|
|||||||
|
|
||||||
return self.cmd.New(cmdArgs).Run()
|
return self.cmd.New(cmdArgs).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *WorkingTreeCommands) ShowFileAtStage(path string, stage int) (string, error) {
|
||||||
|
cmdArgs := NewGitCmd("show").
|
||||||
|
Arg(fmt.Sprintf(":%d:%s", stage, path)).
|
||||||
|
ToArgv()
|
||||||
|
|
||||||
|
return self.cmd.New(cmdArgs).RunWithOutput()
|
||||||
|
}
|
||||||
|
|
||||||
|
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) MergeFileForFiles(strategy string, oursFilepath string, baseFilepath string, theirsFilepath string) (string, error) {
|
||||||
|
cmdArgs := NewGitCmd("merge-file").
|
||||||
|
Arg(strategy).
|
||||||
|
Arg("--stdout").
|
||||||
|
Arg(oursFilepath, baseFilepath, theirsFilepath).
|
||||||
|
ToArgv()
|
||||||
|
|
||||||
|
return self.cmd.New(cmdArgs).RunWithOutput()
|
||||||
|
}
|
||||||
|
|
||||||
|
// OIDs mode (Git 2.43+)
|
||||||
|
func (self *WorkingTreeCommands) MergeFileForObjectIDs(strategy string, oursID string, baseID string, theirsID string) (string, error) {
|
||||||
|
cmdArgs := NewGitCmd("merge-file").
|
||||||
|
Arg(strategy).
|
||||||
|
Arg("--stdout").
|
||||||
|
Arg("--object-id").
|
||||||
|
Arg(oursID, baseID, theirsID).
|
||||||
|
ToArgv()
|
||||||
|
|
||||||
|
return self.cmd.New(cmdArgs).RunWithOutput()
|
||||||
|
}
|
||||||
|
@@ -272,6 +272,7 @@ func computeMigratedConfig(path string, content []byte, changes *ChangesSet) ([]
|
|||||||
{[]string{"gui", "skipUnstageLineWarning"}, "skipDiscardChangeWarning"},
|
{[]string{"gui", "skipUnstageLineWarning"}, "skipDiscardChangeWarning"},
|
||||||
{[]string{"keybinding", "universal", "executeCustomCommand"}, "executeShellCommand"},
|
{[]string{"keybinding", "universal", "executeCustomCommand"}, "executeShellCommand"},
|
||||||
{[]string{"gui", "windowSize"}, "screenMode"},
|
{[]string{"gui", "windowSize"}, "screenMode"},
|
||||||
|
{[]string{"keybinding", "files", "openMergeTool"}, "openMergeOptions"},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pathToReplace := range pathsToReplace {
|
for _, pathToReplace := range pathsToReplace {
|
||||||
|
@@ -897,7 +897,7 @@ keybinding:
|
|||||||
toggleStagedAll: a
|
toggleStagedAll: a
|
||||||
viewResetOptions: D
|
viewResetOptions: D
|
||||||
fetch: f
|
fetch: f
|
||||||
openMergeTool: M
|
openMergeOptions: M
|
||||||
openStatusFilter: <c-b>
|
openStatusFilter: <c-b>
|
||||||
copyFileInfoToClipboard: "y"
|
copyFileInfoToClipboard: "y"
|
||||||
collapseAll: '-'
|
collapseAll: '-'
|
||||||
|
@@ -487,7 +487,7 @@ type KeybindingFilesConfig struct {
|
|||||||
ViewResetOptions string `yaml:"viewResetOptions"`
|
ViewResetOptions string `yaml:"viewResetOptions"`
|
||||||
Fetch string `yaml:"fetch"`
|
Fetch string `yaml:"fetch"`
|
||||||
ToggleTreeView string `yaml:"toggleTreeView"`
|
ToggleTreeView string `yaml:"toggleTreeView"`
|
||||||
OpenMergeTool string `yaml:"openMergeTool"`
|
OpenMergeOptions string `yaml:"openMergeOptions"`
|
||||||
OpenStatusFilter string `yaml:"openStatusFilter"`
|
OpenStatusFilter string `yaml:"openStatusFilter"`
|
||||||
CopyFileInfoToClipboard string `yaml:"copyFileInfoToClipboard"`
|
CopyFileInfoToClipboard string `yaml:"copyFileInfoToClipboard"`
|
||||||
CollapseAll string `yaml:"collapseAll"`
|
CollapseAll string `yaml:"collapseAll"`
|
||||||
@@ -950,7 +950,7 @@ func GetDefaultConfig() *UserConfig {
|
|||||||
ViewResetOptions: "D",
|
ViewResetOptions: "D",
|
||||||
Fetch: "f",
|
Fetch: "f",
|
||||||
ToggleTreeView: "`",
|
ToggleTreeView: "`",
|
||||||
OpenMergeTool: "M",
|
OpenMergeOptions: "M",
|
||||||
OpenStatusFilter: "<c-b>",
|
OpenStatusFilter: "<c-b>",
|
||||||
ConfirmDiscard: "x",
|
ConfirmDiscard: "x",
|
||||||
CopyFileInfoToClipboard: "y",
|
CopyFileInfoToClipboard: "y",
|
||||||
|
@@ -124,8 +124,8 @@ func (gui *Gui) getRandomTip() string {
|
|||||||
formattedKey(config.Universal.Remove),
|
formattedKey(config.Universal.Remove),
|
||||||
),
|
),
|
||||||
fmt.Sprintf(
|
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'",
|
"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.OpenMergeTool),
|
formattedKey(config.Files.OpenMergeOptions),
|
||||||
),
|
),
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"To revert a commit, press '%s' on that commit",
|
"To revert a commit, press '%s' on that commit",
|
||||||
|
@@ -98,7 +98,7 @@ func (gui *Gui) resetHelpersAndControllers() {
|
|||||||
Bisect: bisectHelper,
|
Bisect: bisectHelper,
|
||||||
Suggestions: suggestionsHelper,
|
Suggestions: suggestionsHelper,
|
||||||
Files: helpers.NewFilesHelper(helperCommon),
|
Files: helpers.NewFilesHelper(helperCommon),
|
||||||
WorkingTree: helpers.NewWorkingTreeHelper(helperCommon, refsHelper, commitsHelper, gpgHelper),
|
WorkingTree: helpers.NewWorkingTreeHelper(helperCommon, refsHelper, commitsHelper, gpgHelper, rebaseHelper),
|
||||||
Tags: helpers.NewTagsHelper(helperCommon, commitsHelper, gpgHelper),
|
Tags: helpers.NewTagsHelper(helperCommon, commitsHelper, gpgHelper),
|
||||||
BranchesHelper: helpers.NewBranchesHelper(helperCommon, worktreeHelper),
|
BranchesHelper: helpers.NewBranchesHelper(helperCommon, worktreeHelper),
|
||||||
GPG: helpers.NewGpgHelper(helperCommon),
|
GPG: helpers.NewGpgHelper(helperCommon),
|
||||||
|
@@ -178,10 +178,13 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types
|
|||||||
Description: self.c.Tr.OpenDiffTool,
|
Description: self.c.Tr.OpenDiffTool,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Files.OpenMergeTool),
|
Key: opts.GetKey(opts.Config.Files.OpenMergeOptions),
|
||||||
Handler: self.c.Helpers().WorkingTree.OpenMergeTool,
|
Handler: self.withItems(self.openMergeConflictMenu),
|
||||||
Description: self.c.Tr.OpenMergeTool,
|
Description: self.c.Tr.ViewMergeConflictOptions,
|
||||||
Tooltip: self.c.Tr.OpenMergeToolTooltip,
|
Tooltip: self.c.Tr.ViewMergeConflictOptionsTooltip,
|
||||||
|
GetDisabledReason: self.require(self.itemsSelected(self.canOpenMergeConflictMenu)),
|
||||||
|
OpensMenu: true,
|
||||||
|
DisplayOnScreen: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Files.Fetch),
|
Key: opts.GetKey(opts.Config.Files.Fetch),
|
||||||
@@ -1024,6 +1027,34 @@ func (self *FilesController) createStashMenu() error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *FilesController) openMergeConflictMenu(nodes []*filetree.FileNode) error {
|
||||||
|
normalizedNodes := flattenSelectedNodesToFiles(nodes)
|
||||||
|
|
||||||
|
fileNodesWithConflicts := lo.Filter(normalizedNodes, func(node *filetree.FileNode, _ int) bool {
|
||||||
|
return node.File != nil && node.File.HasInlineMergeConflicts
|
||||||
|
})
|
||||||
|
|
||||||
|
filepaths := lo.Map(fileNodesWithConflicts, func(node *filetree.FileNode, _ int) string {
|
||||||
|
return node.GetPath()
|
||||||
|
})
|
||||||
|
|
||||||
|
return self.c.Helpers().WorkingTree.CreateMergeConflictMenu(filepaths)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FilesController) canOpenMergeConflictMenu(nodes []*filetree.FileNode) *types.DisabledReason {
|
||||||
|
normalizedNodes := flattenSelectedNodesToFiles(nodes)
|
||||||
|
|
||||||
|
hasFileNodesWithConflicts := lo.SomeBy(normalizedNodes, func(node *filetree.FileNode) bool {
|
||||||
|
return node.File != nil && node.File.HasInlineMergeConflicts
|
||||||
|
})
|
||||||
|
|
||||||
|
if !hasFileNodesWithConflicts {
|
||||||
|
return &types.DisabledReason{Text: self.c.Tr.NoFilesWithMergeConflicts}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (self *FilesController) openCopyMenu() error {
|
func (self *FilesController) openCopyMenu() error {
|
||||||
node := self.context().GetSelected()
|
node := self.context().GetSelected()
|
||||||
|
|
||||||
@@ -1237,6 +1268,38 @@ func isDescendentOfSelectedNodes(node *filetree.FileNode, selectedNodes []*filet
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BFS algorithm for expanding directories into their children,
|
||||||
|
// and for collecting the unique file nodes
|
||||||
|
func flattenSelectedNodesToFiles(selectedNodes []*filetree.FileNode) []*filetree.FileNode {
|
||||||
|
queue := append(make([]*filetree.FileNode, 0, len(selectedNodes)), selectedNodes...)
|
||||||
|
visited := set.New[string]()
|
||||||
|
var files []*filetree.FileNode
|
||||||
|
|
||||||
|
for len(queue) > 0 {
|
||||||
|
// pop node from queue
|
||||||
|
node := queue[0]
|
||||||
|
queue = queue[1:]
|
||||||
|
|
||||||
|
nodeID := node.ID()
|
||||||
|
if visited.Includes(nodeID) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
visited.Add(nodeID)
|
||||||
|
|
||||||
|
if node.File != nil {
|
||||||
|
// unique file node -> collect it
|
||||||
|
files = append(files, node)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// directory node -> enqueue children
|
||||||
|
for _, ch := range node.Children {
|
||||||
|
queue = append(queue, &filetree.FileNode{Node: ch})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return files
|
||||||
|
}
|
||||||
|
|
||||||
func someNodesHaveUnstagedChanges(nodes []*filetree.FileNode) bool {
|
func someNodesHaveUnstagedChanges(nodes []*filetree.FileNode) bool {
|
||||||
return lo.SomeBy(nodes, (*filetree.FileNode).GetHasUnstagedChanges)
|
return lo.SomeBy(nodes, (*filetree.FileNode).GetHasUnstagedChanges)
|
||||||
}
|
}
|
||||||
|
@@ -3,21 +3,24 @@ package helpers
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/config"
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WorkingTreeHelper struct {
|
type WorkingTreeHelper struct {
|
||||||
c *HelperCommon
|
c *HelperCommon
|
||||||
refHelper *RefsHelper
|
refHelper *RefsHelper
|
||||||
commitsHelper *CommitsHelper
|
commitsHelper *CommitsHelper
|
||||||
gpgHelper *GpgHelper
|
gpgHelper *GpgHelper
|
||||||
|
mergeAndRebaseHelper *MergeAndRebaseHelper
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWorkingTreeHelper(
|
func NewWorkingTreeHelper(
|
||||||
@@ -25,12 +28,14 @@ func NewWorkingTreeHelper(
|
|||||||
refHelper *RefsHelper,
|
refHelper *RefsHelper,
|
||||||
commitsHelper *CommitsHelper,
|
commitsHelper *CommitsHelper,
|
||||||
gpgHelper *GpgHelper,
|
gpgHelper *GpgHelper,
|
||||||
|
mergeAndRebaseHelper *MergeAndRebaseHelper,
|
||||||
) *WorkingTreeHelper {
|
) *WorkingTreeHelper {
|
||||||
return &WorkingTreeHelper{
|
return &WorkingTreeHelper{
|
||||||
c: c,
|
c: c,
|
||||||
refHelper: refHelper,
|
refHelper: refHelper,
|
||||||
commitsHelper: commitsHelper,
|
commitsHelper: commitsHelper,
|
||||||
gpgHelper: gpgHelper,
|
gpgHelper: gpgHelper,
|
||||||
|
mergeAndRebaseHelper: mergeAndRebaseHelper,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,3 +252,135 @@ func (self *WorkingTreeHelper) commitPrefixConfigsForRepo() []config.CommitPrefi
|
|||||||
|
|
||||||
return self.c.UserConfig().Git.CommitPrefix
|
return self.c.UserConfig().Git.CommitPrefix
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *WorkingTreeHelper) mergeFile(filepath string, strategy string) (string, error) {
|
||||||
|
if self.c.Git().Version.IsOlderThan(2, 43, 0) {
|
||||||
|
return self.mergeFileWithTempFiles(filepath, strategy)
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.mergeFileWithObjectIDs(filepath, strategy)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *WorkingTreeHelper) mergeFileWithTempFiles(filepath string, strategy string) (string, error) {
|
||||||
|
showToTempFile := func(stage int, label string) (string, error) {
|
||||||
|
output, err := self.c.Git().WorkingTree.ShowFileAtStage(filepath, stage)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.CreateTemp(self.c.GetConfig().GetTempDir(), "mergefile-"+label+"-*")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
if _, err := f.Write([]byte(output)); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return f.Name(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
baseFilepath, err := showToTempFile(1, "base")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer os.Remove(baseFilepath)
|
||||||
|
|
||||||
|
oursFilepath, err := showToTempFile(2, "ours")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer os.Remove(oursFilepath)
|
||||||
|
|
||||||
|
theirsFilepath, err := showToTempFile(3, "theirs")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer os.Remove(theirsFilepath)
|
||||||
|
|
||||||
|
return self.c.Git().WorkingTree.MergeFileForFiles(strategy, oursFilepath, baseFilepath, theirsFilepath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *WorkingTreeHelper) mergeFileWithObjectIDs(filepath, strategy string) (string, error) {
|
||||||
|
baseID, err := self.c.Git().WorkingTree.ObjectIDAtStage(filepath, 1)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
oursID, err := self.c.Git().WorkingTree.ObjectIDAtStage(filepath, 2)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
theirsID, err := self.c.Git().WorkingTree.ObjectIDAtStage(filepath, 3)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.c.Git().WorkingTree.MergeFileForObjectIDs(strategy, oursID, baseID, theirsID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *WorkingTreeHelper) CreateMergeConflictMenu(selectedFilepaths []string) error {
|
||||||
|
onMergeStrategySelected := func(strategy string) error {
|
||||||
|
for _, filepath := range selectedFilepaths {
|
||||||
|
output, err := self.mergeFile(filepath, strategy)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = os.WriteFile(filepath, []byte(output), 0o644); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := self.c.Git().WorkingTree.StageFiles(selectedFilepaths, nil)
|
||||||
|
self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.FILES}})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdColor := style.FgBlue
|
||||||
|
return self.c.Menu(types.CreateMenuOptions{
|
||||||
|
Title: self.c.Tr.MergeConflictOptionsTitle,
|
||||||
|
Items: []*types.MenuItem{
|
||||||
|
{
|
||||||
|
LabelColumns: []string{
|
||||||
|
self.c.Tr.UseCurrentChanges,
|
||||||
|
cmdColor.Sprint("git merge-file --ours"),
|
||||||
|
},
|
||||||
|
OnPress: func() error {
|
||||||
|
return onMergeStrategySelected("--ours")
|
||||||
|
},
|
||||||
|
Key: 'c',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
LabelColumns: []string{
|
||||||
|
self.c.Tr.UseIncomingChanges,
|
||||||
|
cmdColor.Sprint("git merge-file --theirs"),
|
||||||
|
},
|
||||||
|
OnPress: func() error {
|
||||||
|
return onMergeStrategySelected("--theirs")
|
||||||
|
},
|
||||||
|
Key: 'i',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
LabelColumns: []string{
|
||||||
|
self.c.Tr.UseBothChanges,
|
||||||
|
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.OpenMergeTool,
|
||||||
|
Key: 'm',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@@ -112,10 +112,11 @@ func (self *MergeConflictsController) GetKeybindings(opts types.KeybindingsOpts)
|
|||||||
Tag: "navigation",
|
Tag: "navigation",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Files.OpenMergeTool),
|
Key: opts.GetKey(opts.Config.Files.OpenMergeOptions),
|
||||||
Handler: self.c.Helpers().WorkingTree.OpenMergeTool,
|
Handler: self.openMergeConflictMenu,
|
||||||
Description: self.c.Tr.OpenMergeTool,
|
Description: self.c.Tr.ViewMergeConflictOptions,
|
||||||
Tooltip: self.c.Tr.OpenMergeToolTooltip,
|
Tooltip: self.c.Tr.ViewMergeConflictOptionsTooltip,
|
||||||
|
OpensMenu: true,
|
||||||
DisplayOnScreen: true,
|
DisplayOnScreen: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -320,6 +321,11 @@ func (self *MergeConflictsController) onLastConflictResolved() {
|
|||||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}})
|
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *MergeConflictsController) openMergeConflictMenu() error {
|
||||||
|
filepath := self.context().GetState().GetPath()
|
||||||
|
return self.c.Helpers().WorkingTree.CreateMergeConflictMenu([]string{filepath})
|
||||||
|
}
|
||||||
|
|
||||||
func (self *MergeConflictsController) withRenderAndFocus(f func() error) func() error {
|
func (self *MergeConflictsController) withRenderAndFocus(f func() error) func() error {
|
||||||
return self.withLock(func() error {
|
return self.withLock(func() error {
|
||||||
if err := f(); err != nil {
|
if err := f(); err != nil {
|
||||||
|
@@ -63,7 +63,6 @@ type TranslationSet struct {
|
|||||||
ToggleTreeViewTooltip string
|
ToggleTreeViewTooltip string
|
||||||
OpenDiffTool string
|
OpenDiffTool string
|
||||||
OpenMergeTool string
|
OpenMergeTool string
|
||||||
OpenMergeToolTooltip string
|
|
||||||
Refresh string
|
Refresh string
|
||||||
RefreshTooltip string
|
RefreshTooltip string
|
||||||
Push string
|
Push string
|
||||||
@@ -898,6 +897,13 @@ type TranslationSet struct {
|
|||||||
BreakingChangesTitle string
|
BreakingChangesTitle string
|
||||||
BreakingChangesMessage string
|
BreakingChangesMessage string
|
||||||
BreakingChangesByVersion map[string]string
|
BreakingChangesByVersion map[string]string
|
||||||
|
ViewMergeConflictOptions string
|
||||||
|
ViewMergeConflictOptionsTooltip string
|
||||||
|
NoFilesWithMergeConflicts string
|
||||||
|
MergeConflictOptionsTitle string
|
||||||
|
UseCurrentChanges string
|
||||||
|
UseIncomingChanges string
|
||||||
|
UseBothChanges string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Bisect struct {
|
type Bisect struct {
|
||||||
@@ -1136,7 +1142,6 @@ func EnglishTranslationSet() *TranslationSet {
|
|||||||
ToggleTreeViewTooltip: "Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory.\n\nThe default can be changed in the config file with the key 'gui.showFileTree'.",
|
ToggleTreeViewTooltip: "Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory.\n\nThe default can be changed in the config file with the key 'gui.showFileTree'.",
|
||||||
OpenDiffTool: "Open external diff tool (git difftool)",
|
OpenDiffTool: "Open external diff tool (git difftool)",
|
||||||
OpenMergeTool: "Open external merge tool",
|
OpenMergeTool: "Open external merge tool",
|
||||||
OpenMergeToolTooltip: "Run `git mergetool`.",
|
|
||||||
Refresh: "Refresh",
|
Refresh: "Refresh",
|
||||||
RefreshTooltip: "Refresh the git state (i.e. run `git status`, `git branch`, etc in background to update the contents of panels). This does not run `git fetch`.",
|
RefreshTooltip: "Refresh the git state (i.e. run `git status`, `git branch`, etc in background to update the contents of panels). This does not run `git fetch`.",
|
||||||
Push: "Push",
|
Push: "Push",
|
||||||
@@ -1970,6 +1975,13 @@ func EnglishTranslationSet() *TranslationSet {
|
|||||||
CustomCommands: "Custom commands",
|
CustomCommands: "Custom commands",
|
||||||
NoApplicableCommandsInThisContext: "(No applicable commands in this context)",
|
NoApplicableCommandsInThisContext: "(No applicable commands in this context)",
|
||||||
SelectCommitsOfCurrentBranch: "Select commits of current branch",
|
SelectCommitsOfCurrentBranch: "Select commits of current branch",
|
||||||
|
ViewMergeConflictOptions: "View merge conflict options",
|
||||||
|
ViewMergeConflictOptionsTooltip: "View options for resolving merge conflicts.",
|
||||||
|
NoFilesWithMergeConflicts: "There are no files with merge conflicts.",
|
||||||
|
MergeConflictOptionsTitle: "Resolve merge conflicts",
|
||||||
|
UseCurrentChanges: "Use current changes",
|
||||||
|
UseIncomingChanges: "Use incoming changes",
|
||||||
|
UseBothChanges: "Use both",
|
||||||
|
|
||||||
Actions: Actions{
|
Actions: Actions{
|
||||||
// TODO: combine this with the original keybinding descriptions (those are all in lowercase atm)
|
// TODO: combine this with the original keybinding descriptions (those are all in lowercase atm)
|
||||||
|
77
pkg/integration/tests/conflicts/merge_file_both.go
Normal file
77
pkg/integration/tests/conflicts/merge_file_both.go
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
package conflicts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/integration/tests/shared"
|
||||||
|
)
|
||||||
|
|
||||||
|
func testDataBoth() (original, current, incoming, final string) {
|
||||||
|
original = `
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
6
|
||||||
|
`
|
||||||
|
current = `
|
||||||
|
1a
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5a
|
||||||
|
6
|
||||||
|
`
|
||||||
|
incoming = `
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3b
|
||||||
|
4
|
||||||
|
5b
|
||||||
|
6
|
||||||
|
`
|
||||||
|
final = `
|
||||||
|
1a
|
||||||
|
2
|
||||||
|
3b
|
||||||
|
4
|
||||||
|
5a
|
||||||
|
5b
|
||||||
|
6
|
||||||
|
`
|
||||||
|
return original, current, incoming, final
|
||||||
|
}
|
||||||
|
|
||||||
|
var MergeFileBoth = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Conflicting file can be resolved to 'union' (both changes) version via merge-file",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
original, current, incoming, _ := testDataBoth()
|
||||||
|
shared.CreateMergeConflictFileForMergeFileTests(shell, original, current, incoming)
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
_, _, _, expected := testDataBoth()
|
||||||
|
|
||||||
|
t.Views().Files().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains("file").IsSelected(),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.GlobalPress(keys.Files.OpenMergeOptions)
|
||||||
|
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Equals("Resolve merge conflicts")).
|
||||||
|
Select(Contains("Use both")). // merge-file --union
|
||||||
|
Confirm()
|
||||||
|
|
||||||
|
t.Common().ContinueOnConflictsResolved("merge")
|
||||||
|
|
||||||
|
t.Views().Files().IsEmpty()
|
||||||
|
|
||||||
|
t.FileSystem().FileContent("file", Equals(expected))
|
||||||
|
},
|
||||||
|
})
|
76
pkg/integration/tests/conflicts/merge_file_current.go
Normal file
76
pkg/integration/tests/conflicts/merge_file_current.go
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
package conflicts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/integration/tests/shared"
|
||||||
|
)
|
||||||
|
|
||||||
|
func testDataCurrent() (original, current, incoming, final string) {
|
||||||
|
original = `
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
6
|
||||||
|
`
|
||||||
|
current = `
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5a
|
||||||
|
6
|
||||||
|
`
|
||||||
|
incoming = `
|
||||||
|
1b
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5b
|
||||||
|
6
|
||||||
|
`
|
||||||
|
final = `
|
||||||
|
1b
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5a
|
||||||
|
6
|
||||||
|
`
|
||||||
|
return original, current, incoming, final
|
||||||
|
}
|
||||||
|
|
||||||
|
var MergeFileCurrent = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Conflicting file can be resolved to 'ours' (current changes) version via merge-file",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
original, current, incoming, _ := testDataCurrent()
|
||||||
|
shared.CreateMergeConflictFileForMergeFileTests(shell, original, current, incoming)
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
_, _, _, expected := testDataCurrent()
|
||||||
|
|
||||||
|
t.Views().Files().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains("file").IsSelected(),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.GlobalPress(keys.Files.OpenMergeOptions)
|
||||||
|
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Equals("Resolve merge conflicts")).
|
||||||
|
Select(Contains("Use current changes")). // merge-file --ours
|
||||||
|
Confirm()
|
||||||
|
|
||||||
|
t.Common().ContinueOnConflictsResolved("merge")
|
||||||
|
|
||||||
|
t.Views().Files().IsEmpty()
|
||||||
|
|
||||||
|
t.FileSystem().FileContent("file", Equals(expected))
|
||||||
|
},
|
||||||
|
})
|
76
pkg/integration/tests/conflicts/merge_file_incoming.go
Normal file
76
pkg/integration/tests/conflicts/merge_file_incoming.go
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
package conflicts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/integration/tests/shared"
|
||||||
|
)
|
||||||
|
|
||||||
|
func testDataIncoming() (original, current, incoming, final string) {
|
||||||
|
original = `
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
6
|
||||||
|
`
|
||||||
|
current = `
|
||||||
|
1a
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5a
|
||||||
|
6
|
||||||
|
`
|
||||||
|
incoming = `
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5b
|
||||||
|
6
|
||||||
|
`
|
||||||
|
final = `
|
||||||
|
1a
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5b
|
||||||
|
6
|
||||||
|
`
|
||||||
|
return original, current, incoming, final
|
||||||
|
}
|
||||||
|
|
||||||
|
var MergeFileIncoming = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Conflicting file can be resolved to 'theirs' (incoming changes) version via merge-file",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
original, current, incoming, _ := testDataIncoming()
|
||||||
|
shared.CreateMergeConflictFileForMergeFileTests(shell, original, current, incoming)
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
_, _, _, expected := testDataIncoming()
|
||||||
|
|
||||||
|
t.Views().Files().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains("file").IsSelected(),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.GlobalPress(keys.Files.OpenMergeOptions)
|
||||||
|
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Equals("Resolve merge conflicts")).
|
||||||
|
Select(Contains("Use incoming changes")). // merge-file --theirs
|
||||||
|
Confirm()
|
||||||
|
|
||||||
|
t.Common().ContinueOnConflictsResolved("merge")
|
||||||
|
|
||||||
|
t.Views().Files().IsEmpty()
|
||||||
|
|
||||||
|
t.FileSystem().FileContent("file", Equals(expected))
|
||||||
|
},
|
||||||
|
})
|
@@ -157,3 +157,20 @@ var CreateMergeConflictFileMultiple = func(shell *Shell) {
|
|||||||
|
|
||||||
shell.RunCommandExpectError([]string{"git", "merge", "--no-edit", "second-change-branch"})
|
shell.RunCommandExpectError([]string{"git", "merge", "--no-edit", "second-change-branch"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var CreateMergeConflictFileForMergeFileTests = func(shell *Shell, originalFileContent string, currentChangeFileContent string, incomingChangeFileContent string) {
|
||||||
|
shell.
|
||||||
|
NewBranch("original-branch").
|
||||||
|
EmptyCommit("one").
|
||||||
|
CreateFileAndAdd("file", originalFileContent).
|
||||||
|
Commit("original").
|
||||||
|
NewBranch("current-change-branch").
|
||||||
|
UpdateFileAndAdd("file", currentChangeFileContent).
|
||||||
|
Commit("first change").
|
||||||
|
Checkout("original-branch").
|
||||||
|
NewBranch("incoming-change-branch").
|
||||||
|
UpdateFileAndAdd("file", incomingChangeFileContent).
|
||||||
|
Commit("second change").
|
||||||
|
Checkout("current-change-branch").
|
||||||
|
RunCommandExpectError([]string{"git", "merge", "--no-edit", "incoming-change-branch"})
|
||||||
|
}
|
||||||
|
@@ -150,6 +150,9 @@ var tests = []*components.IntegrationTest{
|
|||||||
config.NegativeRefspec,
|
config.NegativeRefspec,
|
||||||
config.RemoteNamedStar,
|
config.RemoteNamedStar,
|
||||||
conflicts.Filter,
|
conflicts.Filter,
|
||||||
|
conflicts.MergeFileBoth,
|
||||||
|
conflicts.MergeFileCurrent,
|
||||||
|
conflicts.MergeFileIncoming,
|
||||||
conflicts.ResolveExternally,
|
conflicts.ResolveExternally,
|
||||||
conflicts.ResolveMultipleFiles,
|
conflicts.ResolveMultipleFiles,
|
||||||
conflicts.ResolveNoAutoStage,
|
conflicts.ResolveNoAutoStage,
|
||||||
|
@@ -1115,7 +1115,7 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "`"
|
"default": "`"
|
||||||
},
|
},
|
||||||
"openMergeTool": {
|
"openMergeOptions": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "M"
|
"default": "M"
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user