1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-06-15 00:15:32 +02:00

Add command to squash all fixups in the current branch ()

Add command to squash all fixups in the current branch.

To do that, change the "Apply fixup commits" command to show a menu with
the two choices "in current branch" and "above the selected commit"; we
make "in current branch" the default, as it's the more useful one most
of the time, even though it is a breaking change for those who are used
to "shift-S enter" meaning "squash above selected".

Fixes .
This commit is contained in:
Stefan Haller
2024-01-29 10:05:40 +01:00
committed by GitHub
14 changed files with 133 additions and 31 deletions

@ -89,7 +89,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
| `` p `` | Pick | Mark the selected commit to be picked (when mid-rebase). This means that the commit will be retained upon continuing the rebase. |
| `` F `` | Create fixup commit | Create 'fixup!' commit for the selected commit. Later on, you can press `S` on this same commit to apply all above fixup commits. |
| `` S `` | Apply fixup commits | Squash all 'fixup!' commits above selected commit (autosquash). |
| `` S `` | Apply fixup commits | Squash all 'fixup!' commits, either above the selected commit, or all in current branch (autosquash). |
| `` <c-j> `` | Move commit down one | |
| `` <c-k> `` | Move commit up one | |
| `` V `` | Paste (cherry-pick) | |

@ -106,7 +106,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
| `` p `` | Pick | Mark the selected commit to be picked (when mid-rebase). This means that the commit will be retained upon continuing the rebase. |
| `` F `` | Create fixup commit | このコミットに対するfixupコミットを作成 |
| `` S `` | Apply fixup commits | Squash all 'fixup!' commits above selected commit (autosquash). |
| `` S `` | Apply fixup commits | Squash all 'fixup!' commits, either above the selected commit, or all in current branch (autosquash). |
| `` <c-j> `` | コミットを1つ下に移動 | |
| `` <c-k> `` | コミットを1つ上に移動 | |
| `` V `` | コミットを貼り付け (cherry-pick) | |

@ -167,13 +167,13 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
},
{
Key: opts.GetKey(opts.Config.Commits.SquashAboveCommits),
Handler: self.withItem(self.squashAllAboveFixupCommits),
Handler: self.squashFixupCommits,
GetDisabledReason: self.require(
self.notMidRebase(self.c.Tr.AlreadyRebasing),
self.singleItemSelected(),
),
Description: self.c.Tr.SquashAboveCommits,
Tooltip: self.c.Tr.SquashAboveCommitsTooltip,
OpensMenu: true,
},
{
Key: opts.GetKey(opts.Config.Commits.MoveDownCommit),
@ -816,25 +816,62 @@ func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) err
})
}
func (self *LocalCommitsController) squashAllAboveFixupCommits(commit *models.Commit) error {
prompt := utils.ResolvePlaceholderString(
self.c.Tr.SureSquashAboveCommits,
map[string]string{"commit": commit.Sha},
)
return self.c.Confirm(types.ConfirmOpts{
Title: self.c.Tr.SquashAboveCommits,
Prompt: prompt,
HandleConfirm: func() error {
return self.c.WithWaitingStatus(self.c.Tr.SquashingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.SquashAllAboveFixupCommits)
err := self.c.Git().Rebase.SquashAllAboveFixupCommits(commit)
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
})
func (self *LocalCommitsController) squashFixupCommits() error {
return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.SquashAboveCommits,
Items: []*types.MenuItem{
{
Label: self.c.Tr.SquashCommitsInCurrentBranch,
OnPress: self.squashAllFixupsInCurrentBranch,
DisabledReason: self.canFindCommitForSquashFixupsInCurrentBranch(),
Key: 'b',
Tooltip: self.c.Tr.SquashCommitsInCurrentBranchTooltip,
},
{
Label: self.c.Tr.SquashCommitsAboveSelectedCommit,
OnPress: self.withItem(self.squashAllFixupsAboveSelectedCommit),
DisabledReason: self.singleItemSelected()(),
Key: 'a',
Tooltip: self.c.Tr.SquashCommitsAboveSelectedTooltip,
},
},
})
}
func (self *LocalCommitsController) squashAllFixupsAboveSelectedCommit(commit *models.Commit) error {
return self.c.WithWaitingStatus(self.c.Tr.SquashingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.SquashAllAboveFixupCommits)
err := self.c.Git().Rebase.SquashAllAboveFixupCommits(commit)
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
})
}
func (self *LocalCommitsController) squashAllFixupsInCurrentBranch() error {
commit, err := self.findCommitForSquashFixupsInCurrentBranch()
if err != nil {
return self.c.Error(err)
}
return self.c.WithWaitingStatus(self.c.Tr.SquashingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.SquashAllAboveFixupCommits)
err := self.c.Git().Rebase.SquashAllAboveFixupCommits(commit)
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
})
}
func (self *LocalCommitsController) findCommitForSquashFixupsInCurrentBranch() (*models.Commit, error) {
commits := self.c.Model().Commits
_, index, ok := lo.FindIndexOf(commits, func(c *models.Commit) bool {
return c.IsMerge() || c.Status == models.StatusMerged
})
if !ok || index == 0 {
return nil, errors.New(self.c.Tr.CannotSquashCommitsInCurrentBranch)
}
return commits[index-1], nil
}
func (self *LocalCommitsController) createTag(commit *models.Commit) error {
return self.c.Helpers().Tags.OpenCreateTagPrompt(commit.Sha, func() {})
}
@ -1019,6 +1056,14 @@ func (self *LocalCommitsController) canFindCommitForQuickStart() *types.Disabled
return nil
}
func (self *LocalCommitsController) canFindCommitForSquashFixupsInCurrentBranch() *types.DisabledReason {
if _, err := self.findCommitForSquashFixupsInCurrentBranch(); err != nil {
return &types.DisabledReason{Text: err.Error()}
}
return nil
}
func (self *LocalCommitsController) canSquashOrFixup(_selectedCommits []*models.Commit, startIdx int, endIdx int) *types.DisabledReason {
if endIdx >= len(self.c.Model().Commits)-1 {
return &types.DisabledReason{Text: self.c.Tr.CannotSquashOrFixupFirstCommit}

@ -254,7 +254,6 @@ func chineseTranslationSet() TranslationSet {
ViewResetOptions: `查看重置选项`,
CreateFixupCommit: `为此提交创建修正`,
SquashAboveCommitsTooltip: `压缩在所选提交之上的所有“fixup!”提交(自动压缩)`,
SureSquashAboveCommits: `您确定要压缩在 {{.commit}} 之上的所有“fixup!”提交吗?`,
CreateFixupCommitTooltip: `创建修正提交`,
SureCreateFixupCommit: `您确定要对 {{.commit}} 创建修正提交吗?`,
ExecuteCustomCommand: "执行自定义命令",

@ -217,7 +217,6 @@ func dutchTranslationSet() TranslationSet {
HardReset: "Harde reset",
CreateFixupCommit: `Creëer fixup commit voor deze commit`,
SquashAboveCommitsTooltip: `Squash bovenstaande commits`,
SureSquashAboveCommits: `Weet je zeker dat je alles wil squash/fixup! voor de bovenstaand commits {{.commit}}?`,
CreateFixupCommitTooltip: `Creëer fixup commit`,
SureCreateFixupCommit: `Weet je zeker dat je een fixup wil maken! commit voor commit {{.commit}}?`,
ExecuteCustomCommand: "Voer aangepaste commando uit",

@ -386,8 +386,12 @@ type TranslationSet struct {
CreateFixupCommitDescription string
CreateFixupCommitTooltip string
SquashAboveCommitsTooltip string
SquashCommitsAboveSelectedTooltip string
SquashCommitsInCurrentBranchTooltip string
SquashAboveCommits string
SureSquashAboveCommits string
SquashCommitsInCurrentBranch string
SquashCommitsAboveSelectedCommit string
CannotSquashCommitsInCurrentBranch string
SureCreateFixupCommit string
ExecuteCustomCommand string
ExecuteCustomCommandTooltip string
@ -1322,8 +1326,12 @@ func EnglishTranslationSet() TranslationSet {
CreateFixupCommitDescription: `Create fixup commit`,
CreateFixupCommitTooltip: "Create 'fixup!' commit for the selected commit. Later on, you can press `{{.squashAbove}}` on this same commit to apply all above fixup commits.",
SquashAboveCommits: "Apply fixup commits",
SquashAboveCommitsTooltip: `Squash all 'fixup!' commits above selected commit (autosquash).`,
SureSquashAboveCommits: `Are you sure you want to squash all fixup! commits above {{.commit}}?`,
SquashAboveCommitsTooltip: `Squash all 'fixup!' commits, either above the selected commit, or all in current branch (autosquash).`,
SquashCommitsAboveSelectedTooltip: `Squash all 'fixup!' commits above the selected commit (autosquash).`,
SquashCommitsInCurrentBranchTooltip: `Squash all 'fixup!' commits in the current branch (autosquash).`,
SquashCommitsInCurrentBranch: "In current branch",
SquashCommitsAboveSelectedCommit: "Above the selected commit",
CannotSquashCommitsInCurrentBranch: "Cannot squash commits in current branch: the HEAD commit is a merge commit or is present on the main branch.",
CreateFixupCommit: `Create fixup commit`,
SureCreateFixupCommit: `Are you sure you want to create a fixup! commit for commit {{.commit}}?`,
ExecuteCustomCommand: "Execute custom command",

@ -263,7 +263,6 @@ func japaneseTranslationSet() TranslationSet {
CreateFixupCommitTooltip: `このコミットに対するfixupコミットを作成`,
// LcSquashAboveCommits: `squash all 'fixup!' commits above selected commit (autosquash)`,
// SquashAboveCommits: `Squash all 'fixup!' commits above selected commit (autosquash)`,
SureSquashAboveCommits: `{{.commit}}に対するすべての fixup! コミットをsquashします。よろしいですか?`,
CreateFixupCommit: `Fixupコミットを作成`,
SureCreateFixupCommit: `{{.commit}} に対する fixup! コミットを作成します。よろしいですか?`,
ExecuteCustomCommand: "カスタムコマンドを実行",

@ -258,7 +258,6 @@ func koreanTranslationSet() TranslationSet {
ViewResetOptions: `View reset options`,
CreateFixupCommitTooltip: `Create fixup commit for this commit`,
SquashAboveCommitsTooltip: `Squash all 'fixup!' commits above selected commit (autosquash)`,
SureSquashAboveCommits: `Are you sure you want to squash all fixup! commits above {{.commit}}?`,
CreateFixupCommit: `Create fixup commit`,
SureCreateFixupCommit: `Are you sure you want to create a fixup! commit for commit {{.commit}}?`,
ExecuteCustomCommand: "Execute custom command",

@ -180,7 +180,6 @@ func polishTranslationSet() TranslationSet {
ViewResetOptions: "Wyświetl opcje resetu",
CreateFixupCommitTooltip: "Utwórz commit naprawczy dla tego commita",
SquashAboveCommitsTooltip: `Spłaszcz wszystkie commity naprawcze powyżej zaznaczonych commitów (autosquash)`,
SureSquashAboveCommits: `Na pewno chcesz spłaszczyć wszystkie commity naprawcze powyżej {{.commit}}?`,
CreateFixupCommit: `Utwóż commit naprawczy`,
SureCreateFixupCommit: `Na pewno utworzyć commit naprawczy dla commita {{.commit}}?`,
ExecuteCustomCommand: "Wykonaj własną komendę",

@ -314,7 +314,6 @@ func RussianTranslationSet() TranslationSet {
ViewResetOptions: `Просмотреть параметры сброса`,
CreateFixupCommitTooltip: `Создать fixup коммит для этого коммита`,
SquashAboveCommitsTooltip: `Объединить все 'fixup!' коммиты выше в выбранный коммит (автосохранение)`,
SureSquashAboveCommits: `Вы уверены, что хотите объединить все fixup! коммиты выше {{.commit}}?`,
CreateFixupCommit: `Создать fixup коммит`,
SureCreateFixupCommit: `Вы уверены, что хотите создать fixup! коммит для коммита {{.commit}}?`,
ExecuteCustomCommand: "Выполнить пользовательскую команду",

@ -341,7 +341,6 @@ func traditionalChineseTranslationSet() TranslationSet {
ViewResetOptions: "檢視重設選項",
CreateFixupCommitTooltip: "為此提交建立修復提交",
SquashAboveCommitsTooltip: "壓縮上方所有的“fixup!”提交 (自動壓縮)",
SureSquashAboveCommits: "你確定要壓縮{{.commit}}上方所有的fixup!提交嗎?",
CreateFixupCommit: "建立修復提交",
SureCreateFixupCommit: "你確定要為提交{{.commit}}建立fixup!提交嗎?",
ExecuteCustomCommand: "執行自訂命令",

@ -33,9 +33,9 @@ var SquashFixupsAboveFirstCommit = NewIntegrationTest(NewIntegrationTestArgs{
NavigateToLine(Contains("commit 01").DoesNotContain("fixup!")).
Press(keys.Commits.SquashAboveCommits).
Tap(func() {
t.ExpectPopup().Confirmation().
t.ExpectPopup().Menu().
Title(Equals("Apply fixup commits")).
Content(Contains("Are you sure you want to squash all fixup! commits above")).
Select(Contains("Above the selected commit")).
Confirm()
}).
Lines(

@ -0,0 +1,55 @@
package interactive_rebase
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var SquashFixupsInCurrentBranch = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Squashes all fixups in the current branch.",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) {
shell.
CreateFileAndAdd("file1", "file1").
Commit("master commit").
NewBranch("branch").
// Test the pathological case that the first commit of a branch is a
// fixup for the last master commit below it. We _don't_ want this to
// be squashed.
UpdateFileAndAdd("file1", "changed file1").
Commit("fixup! master commit").
CreateNCommits(2).
CreateFileAndAdd("fixup-file", "fixup content").
Commit("fixup! commit 01")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Commits().
Focus().
Lines(
Contains("fixup! commit 01"),
Contains("commit 02"),
Contains("commit 01"),
Contains("fixup! master commit"),
Contains("master commit"),
).
Press(keys.Commits.SquashAboveCommits).
Tap(func() {
t.ExpectPopup().Menu().
Title(Equals("Apply fixup commits")).
Select(Contains("In current branch")).
Confirm()
}).
Lines(
Contains("commit 02"),
Contains("commit 01"),
Contains("fixup! master commit"),
Contains("master commit"),
).
NavigateToLine(Contains("commit 01"))
t.Views().Main().
Content(Contains("fixup content"))
},
})

@ -183,6 +183,7 @@ var tests = []*components.IntegrationTest{
interactive_rebase.SquashDownFirstCommit,
interactive_rebase.SquashDownSecondCommit,
interactive_rebase.SquashFixupsAboveFirstCommit,
interactive_rebase.SquashFixupsInCurrentBranch,
interactive_rebase.SwapInRebaseWithConflict,
interactive_rebase.SwapInRebaseWithConflictAndEdit,
interactive_rebase.SwapWithConflict,