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
1 change: 1 addition & 0 deletions docs-master/keybindings/Keybindings_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` o `` | Open file | Open file in default application. |
| `` e `` | Edit file | Open file in external editor. |
| `` <space> `` | Toggle lines in patch | |
| `` d `` | Remove lines from commit | Remove the selected lines from this commit. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes these lines. |
| `` <esc> `` | Exit custom patch builder | |
| `` / `` | Search the current view by text | |

Expand Down
1 change: 1 addition & 0 deletions docs-master/keybindings/Keybindings_ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ _凡例:`<c-b>` はctrl+b、`<a-b>` はalt+b、`B` はshift+bを意味
| `` o `` | ファイルを開く | デフォルトのアプリケーションでファイルを開きます。 |
| `` e `` | ファイルを編集 | 外部エディタでファイルを開きます。 |
| `` <space> `` | パッチ内の行を切り替え | |
| `` d `` | Remove lines from commit | Remove the selected lines from this commit. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes these lines. |
| `` <esc> `` | カスタムパッチビルダーを終了 | |
| `` / `` | 現在のビューをテキストで検索 | |

Expand Down
1 change: 1 addition & 0 deletions docs-master/keybindings/Keybindings_ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` o `` | 파일 닫기 | Open file in default application. |
| `` e `` | 파일 편집 | Open file in external editor. |
| `` <space> `` | Line(s)을 패치에 추가/삭제 | |
| `` d `` | Remove lines from commit | Remove the selected lines from this commit. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes these lines. |
| `` <esc> `` | Exit custom patch builder | |
| `` / `` | 검색 시작 | |

Expand Down
1 change: 1 addition & 0 deletions docs-master/keybindings/Keybindings_nl.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` o `` | Open bestand | Open file in default application. |
| `` e `` | Verander bestand | Open file in external editor. |
| `` <space> `` | Voeg toe/verwijder lijn(en) in patch | |
| `` d `` | Remove lines from commit | Remove the selected lines from this commit. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes these lines. |
| `` <esc> `` | Sluit lijn-bij-lijn modus | |
| `` / `` | Start met zoeken | |

Expand Down
1 change: 1 addition & 0 deletions docs-master/keybindings/Keybindings_pl.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ _Legenda: `<c-b>` oznacza ctrl+b, `<a-b>` oznacza alt+b, `B` oznacza shift+b_
| `` o `` | Otwórz plik | Otwórz plik w domyślnej aplikacji. |
| `` e `` | Edytuj plik | Otwórz plik w zewnętrznym edytorze. |
| `` <space> `` | Przełącz linie w łatce | |
| `` d `` | Remove lines from commit | Remove the selected lines from this commit. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes these lines. |
| `` <esc> `` | Wyjdź z budowniczego niestandardowej łatki | |
| `` / `` | Szukaj w bieżącym widoku po tekście | |

Expand Down
1 change: 1 addition & 0 deletions docs-master/keybindings/Keybindings_pt.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` o `` | Abrir arquivo | Abrir arquivo no aplicativo padrão. |
| `` e `` | Editar arquivo | Abrir arquivo no editor externo. |
| `` <space> `` | Alternar linhas no caminho | |
| `` d `` | Remove lines from commit | Remove the selected lines from this commit. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes these lines. |
| `` <esc> `` | Sair do construtor de patch personalizado | |
| `` / `` | Search the current view by text | |

Expand Down
1 change: 1 addition & 0 deletions docs-master/keybindings/Keybindings_ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ _Связки клавиш_
| `` o `` | Открыть файл | Open file in default application. |
| `` e `` | Редактировать файл | Open file in external editor. |
| `` <space> `` | Добавить/удалить строку(и) для патча | |
| `` d `` | Remove lines from commit | Remove the selected lines from this commit. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes these lines. |
| `` <esc> `` | Выйти из сборщика пользовательских патчей | |
| `` / `` | Найти | |

Expand Down
1 change: 1 addition & 0 deletions docs-master/keybindings/Keybindings_zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ _图例:`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
| `` e `` | 编辑文件 | 使用外部编辑器打开文件 |
| `` <space> `` | 添加/移除 行到补丁 | |
| `` d `` | Remove lines from commit | Remove the selected lines from this commit. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes these lines. |
| `` <esc> `` | 退出逐行模式 | |
| `` / `` | 开始搜索 | |

Expand Down
1 change: 1 addition & 0 deletions docs-master/keybindings/Keybindings_zh-TW.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B
| `` o `` | 開啟檔案 | 使用預設軟體開啟 |
| `` e `` | 編輯檔案 | 使用外部編輯器開啟 |
| `` <space> `` | 向 (或從) 補丁中添加/刪除行 | |
| `` d `` | Remove lines from commit | Remove the selected lines from this commit. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes these lines. |
| `` <esc> `` | 退出自訂補丁建立器 | |
| `` / `` | 搜尋 | |

Expand Down
88 changes: 88 additions & 0 deletions pkg/gui/controllers/patch_building_controller.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package controllers

import (
"fmt"

"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/samber/lo"
)
Expand Down Expand Up @@ -42,6 +45,14 @@ func (self *PatchBuildingController) GetKeybindings(opts types.KeybindingsOpts)
Description: self.c.Tr.ToggleSelectionForPatch,
DisplayOnScreen: true,
},
{
Key: opts.GetKey(opts.Config.Universal.Remove),
Handler: self.DiscardSelection,
GetDisabledReason: self.getDisabledReasonForDiscard,
Description: self.c.Tr.RemoveSelectionFromPatch,
Tooltip: self.c.Tr.RemoveSelectionFromPatchTooltip,
DisplayOnScreen: true,
},
{
Key: opts.GetKey(opts.Config.Universal.Return),
Handler: self.Escape,
Expand Down Expand Up @@ -168,6 +179,83 @@ func (self *PatchBuildingController) toggleSelection() error {
return nil
}

func (self *PatchBuildingController) getDisabledReasonForDiscard() *types.DisabledReason {
if !self.c.Git().Patch.PatchBuilder.CanRebase {
return &types.DisabledReason{Text: self.c.Tr.CanOnlyRemoveLinesFromLocalCommits}
}
if !self.c.Git().Patch.PatchBuilder.IsEmpty() {
return &types.DisabledReason{Text: self.c.Tr.MustClearPatchBeforeRemovingLines}
}
return nil
}

func (self *PatchBuildingController) DiscardSelection() error {
if self.c.UserConfig().Git.DiffContextSize == 0 {
return fmt.Errorf(self.c.Tr.Actions.NotEnoughContextToRemoveLines,
keybindings.Label(self.c.UserConfig().Keybinding.Universal.IncreaseContextInDiffView))
}

if ok, err := self.c.Helpers().PatchBuilding.ValidateNormalWorkingTreeState(); !ok {
return err
}

self.c.Confirm(types.ConfirmOpts{
Title: self.c.Tr.RemoveLinesFromCommitTitle,
Prompt: self.c.Tr.RemoveLinesFromCommitPrompt,
HandleConfirm: func() error {
return self.removeSelectionFromCommit()
},
})

return nil
}

func (self *PatchBuildingController) addSelectionToPatch() error {
self.context().GetMutex().Lock()
defer self.context().GetMutex().Unlock()

filename := self.c.Contexts().CommitFiles.GetSelectedPath()
if filename == "" {
return nil
}

state := self.context().GetState()
lineIndicesToToggle := state.LineIndicesOfAddedOrDeletedLinesInSelectedPatchRange()
if len(lineIndicesToToggle) == 0 {
return nil
}

return self.c.Git().Patch.PatchBuilder.AddFileLineRange(filename, lineIndicesToToggle)
}

func (self *PatchBuildingController) removeSelectionFromCommit() error {
if err := self.addSelectionToPatch(); err != nil {
return err
}

if self.c.Git().Patch.PatchBuilder.IsEmpty() {
return nil
}

self.c.Helpers().PatchBuilding.Escape()

return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
commitIndex := self.getPatchCommitIndex()
self.c.LogAction(self.c.Tr.Actions.RemovePatchFromCommit)
err := self.c.Git().Patch.DeletePatchesFromCommit(self.c.Model().Commits, commitIndex)
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
})
}

func (self *PatchBuildingController) getPatchCommitIndex() int {
for index, commit := range self.c.Model().Commits {
if commit.Hash() == self.c.Git().Patch.PatchBuilder.To {
return index
}
}
return -1
}

func (self *PatchBuildingController) Escape() error {
context := self.c.Contexts().CustomPatchBuilder
state := context.GetState()
Expand Down
14 changes: 14 additions & 0 deletions pkg/i18n/english.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,8 @@ type TranslationSet struct {
ToggleSelectHunkTooltip string
HunkStagingHint string
ToggleSelectionForPatch string
RemoveSelectionFromPatch string
RemoveSelectionFromPatchTooltip string
EditHunk string
EditHunkTooltip string
ToggleStagingView string
Expand Down Expand Up @@ -434,6 +436,8 @@ type TranslationSet struct {
CheckoutCommitFileTooltip string
CannotCheckoutWithModifiedFilesErr string
CanOnlyDiscardFromLocalCommits string
CanOnlyRemoveLinesFromLocalCommits string
MustClearPatchBeforeRemovingLines string
Remove string
DiscardOldFileChangeTooltip string
DiscardFileChangesTitle string
Expand Down Expand Up @@ -686,6 +690,8 @@ type TranslationSet struct {
BranchUnknown string
DiscardChangeTitle string
DiscardChangePrompt string
RemoveLinesFromCommitTitle string
RemoveLinesFromCommitPrompt string
CreateNewBranchFromCommit string
BuildingPatch string
ViewCommits string
Expand Down Expand Up @@ -1007,6 +1013,7 @@ type Actions struct {
ResolveConflictByDeletingFile string
NotEnoughContextToStage string
NotEnoughContextToDiscard string
NotEnoughContextToRemoveLines string
NotEnoughContextForCustomPatch string
IgnoreExcludeFile string
IgnoreFileErr string
Expand Down Expand Up @@ -1405,6 +1412,8 @@ func EnglishTranslationSet() *TranslationSet {
ToggleSelectHunkTooltip: "Toggle line-by-line vs. hunk selection mode.",
HunkStagingHint: englishHunkStagingHint,
ToggleSelectionForPatch: `Toggle lines in patch`,
RemoveSelectionFromPatch: `Remove lines from commit`,
RemoveSelectionFromPatchTooltip: "Remove the selected lines from this commit. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes these lines.",
EditHunk: `Edit hunk`,
EditHunkTooltip: "Edit selected hunk in external editor.",
ToggleStagingView: "Switch view",
Expand Down Expand Up @@ -1542,6 +1551,8 @@ func EnglishTranslationSet() *TranslationSet {
CheckoutCommitFileTooltip: "Checkout file. This replaces the file in your working tree with the version from the selected commit.",
CannotCheckoutWithModifiedFilesErr: "You have local modifications for the file(s) you are trying to check out. You need to stash or discard these first.",
CanOnlyDiscardFromLocalCommits: "Changes can only be discarded from local commits",
CanOnlyRemoveLinesFromLocalCommits: "Lines can only be removed from local commits",
MustClearPatchBeforeRemovingLines: "Clear the current custom patch first before removing lines from the commit",
Remove: "Remove",
DiscardOldFileChangeTooltip: "Discard this commit's changes to this file. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes this file.",
DiscardFileChangesTitle: "Discard file changes",
Expand Down Expand Up @@ -1794,6 +1805,8 @@ func EnglishTranslationSet() *TranslationSet {
BranchUnknown: "Branch unknown",
DiscardChangeTitle: "Discard change",
DiscardChangePrompt: "Are you sure you want to discard this change (git reset)? It is irreversible.\nTo disable this dialogue set the config key of 'gui.skipDiscardChangeWarning' to true",
RemoveLinesFromCommitTitle: "Remove lines from commit",
RemoveLinesFromCommitPrompt: "Are you sure you want to remove the selected lines from this commit?",
CreateNewBranchFromCommit: "Create new branch off of commit",
BuildingPatch: "Building patch",
ViewCommits: "View commits",
Expand Down Expand Up @@ -2075,6 +2088,7 @@ func EnglishTranslationSet() *TranslationSet {
ResolveConflictByDeletingFile: "Resolve by deleting file",
NotEnoughContextToStage: "Staging or unstaging changes is not possible with a diff context size of 0. Increase the context using '%s'.",
NotEnoughContextToDiscard: "Discarding changes is not possible with a diff context size of 0. Increase the context using '%s'.",
NotEnoughContextToRemoveLines: "Removing lines from a commit is not possible with a diff context size of 0. Increase the context using '%s'.",
NotEnoughContextForCustomPatch: "Creating custom patches is not possible with a diff context size of 0. Increase the context using '%s'.",
IgnoreExcludeFile: "Ignore or exclude file",
IgnoreFileErr: "Cannot ignore .gitignore",
Expand Down
63 changes: 63 additions & 0 deletions pkg/integration/tests/patch_building/remove_lines_from_commit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package patch_building

import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)

var RemoveLinesFromCommit = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Remove specific lines from a commit using the 'd' shortcut in the patch building view",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) {
shell.EmptyCommit("first commit")

shell.CreateFileAndAdd("file1", "1st line\n2nd line\n3rd line\n")
shell.Commit("commit to remove from")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Commits().
Focus().
Lines(
Contains("commit to remove from").IsSelected(),
Contains("first commit"),
).
PressEnter()

t.Views().CommitFiles().
IsFocused().
Lines(
Contains("A file1").IsSelected(),
).
PressEnter()

// Select the second line (+2nd line) and press 'd' to remove it
t.Views().PatchBuilding().
IsFocused().
SelectNextItem().
SelectedLines(
Contains("+2nd line"),
).
Press(keys.Universal.Remove)

t.ExpectPopup().Confirmation().
Title(Equals("Remove lines from commit")).
Content(Equals("Are you sure you want to remove the selected lines from this commit?")).
Confirm()

// After the rebase, we should be back at the commit files view
// and the commit should now only contain the 1st and 3rd lines
t.Views().CommitFiles().
IsFocused().
Lines(
Contains("A file1").IsSelected(),
).
PressEscape()

t.Views().Main().ContainsLines(
Equals("+1st line"),
Equals("+3rd line"),
)
},
})
1 change: 1 addition & 0 deletions pkg/integration/tests/test_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ var tests = []*components.IntegrationTest{
patch_building.MoveToNewCommitInLastCommitOfStackedBranch,
patch_building.MoveToNewCommitPartialHunk,
patch_building.RemoveFromCommit,
patch_building.RemoveLinesFromCommit,
patch_building.RemovePartsOfAddedFile,
patch_building.ResetWithEscape,
patch_building.SelectAllFiles,
Expand Down