diff options
author | Noah <noah.fraiture@gmail.com> | 2024-05-16 12:48:59 +0200 |
---|---|---|
committer | Jesse Duffield <jessedduffield@gmail.com> | 2024-06-30 11:01:03 +1000 |
commit | 232be05785c4f1b12c7d0ddda2c64f12ec525562 (patch) | |
tree | 097e5a811b6cc536e4695f8d9960d17ee966f571 | |
parent | 89900263586c87880af12ffcbb62c976f7592e8e (diff) |
feat: squash merge
-rw-r--r-- | docs/Config.md | 3 | ||||
-rw-r--r-- | docs/keybindings/Keybindings_en.md | 4 | ||||
-rw-r--r-- | docs/keybindings/Keybindings_ja.md | 4 | ||||
-rw-r--r-- | docs/keybindings/Keybindings_ko.md | 4 | ||||
-rw-r--r-- | docs/keybindings/Keybindings_nl.md | 4 | ||||
-rw-r--r-- | docs/keybindings/Keybindings_ru.md | 4 | ||||
-rw-r--r-- | docs/keybindings/Keybindings_zh-CN.md | 4 | ||||
-rw-r--r-- | docs/keybindings/Keybindings_zh-TW.md | 4 | ||||
-rw-r--r-- | pkg/commands/git_commands/branch.go | 5 | ||||
-rw-r--r-- | pkg/config/user_config.go | 7 | ||||
-rw-r--r-- | pkg/gui/controllers/branches_controller.go | 14 | ||||
-rw-r--r-- | pkg/gui/controllers/helpers/merge_and_rebase_helper.go | 87 | ||||
-rw-r--r-- | pkg/i18n/english.go | 22 | ||||
-rw-r--r-- | pkg/integration/tests/branch/squash_merge.go | 64 | ||||
-rw-r--r-- | pkg/integration/tests/test_list.go | 1 | ||||
-rw-r--r-- | pkg/integration/tests/ui/mode_specific_keybinding_suggestions.go | 6 | ||||
-rw-r--r-- | schema/config.json | 5 |
17 files changed, 203 insertions, 39 deletions
diff --git a/docs/Config.md b/docs/Config.md index ac296532f..358e7be5b 100644 --- a/docs/Config.md +++ b/docs/Config.md @@ -283,6 +283,9 @@ git: # Extra args passed to `git merge`, e.g. --no-ff args: "" + # The commit message to use for a squash merge commit. Can contain "{{selectedRef}}" and "{{currentBranch}}" placeholders. + squashMergeMessage: Squash merge {{selectedRef}} into {{currentBranch}} + # list of branches that are considered 'main' branches, used when displaying commits mainBranches: - master diff --git a/docs/keybindings/Keybindings_en.md b/docs/keybindings/Keybindings_en.md index a777a5578..b4e566c9f 100644 --- a/docs/keybindings/Keybindings_en.md +++ b/docs/keybindings/Keybindings_en.md @@ -162,7 +162,7 @@ If you would instead like to start an interactive rebase from the selected commi | `` F `` | Force checkout | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. | | `` d `` | Delete | View delete options for local/remote branch. | | `` r `` | Rebase | Rebase the checked-out branch onto the selected branch. | -| `` M `` | Merge | Merge selected branch into currently checked out branch. | +| `` M `` | Merge | View options for merging the selected item into the current branch (regular merge, squash merge) | | `` f `` | Fast-forward | Fast-forward selected branch from its upstream. | | `` T `` | New tag | | | `` s `` | Sort order | | @@ -265,7 +265,7 @@ If you would instead like to start an interactive rebase from the selected commi | `` <c-o> `` | Copy branch name to clipboard | | | `` <space> `` | Checkout | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. | | `` n `` | New branch | | -| `` M `` | Merge | Merge selected branch into currently checked out branch. | +| `` M `` | Merge | View options for merging the selected item into the current branch (regular merge, squash merge) | | `` r `` | Rebase | Rebase the checked-out branch onto the selected branch. | | `` d `` | Delete | Delete the remote branch from the remote. | | `` u `` | Set as upstream | Set the selected remote branch as the upstream of the checked-out branch. | diff --git a/docs/keybindings/Keybindings_ja.md b/docs/keybindings/Keybindings_ja.md index 1e511ee74..39741ee7c 100644 --- a/docs/keybindings/Keybindings_ja.md +++ b/docs/keybindings/Keybindings_ja.md @@ -232,7 +232,7 @@ If you would instead like to start an interactive rebase from the selected commi | `` F `` | Force checkout | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. | | `` d `` | Delete | View delete options for local/remote branch. | | `` r `` | Rebase | Rebase the checked-out branch onto the selected branch. | -| `` M `` | 現在のブランチにマージ | Merge selected branch into currently checked out branch. | +| `` M `` | 現在のブランチにマージ | View options for merging the selected item into the current branch (regular merge, squash merge) | | `` f `` | Fast-forward | Fast-forward selected branch from its upstream. | | `` T `` | タグを作成 | | | `` s `` | 並び替え | | @@ -329,7 +329,7 @@ If you would instead like to start an interactive rebase from the selected commi | `` <c-o> `` | ブランチ名をクリップボードにコピー | | | `` <space> `` | チェックアウト | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. | | `` n `` | 新しいブランチを作成 | | -| `` M `` | 現在のブランチにマージ | Merge selected branch into currently checked out branch. | +| `` M `` | 現在のブランチにマージ | View options for merging the selected item into the current branch (regular merge, squash merge) | | `` r `` | Rebase | Rebase the checked-out branch onto the selected branch. | | `` d `` | Delete | Delete the remote branch from the remote. | | `` u `` | Set as upstream | Set the selected remote branch as the upstream of the checked-out branch. | diff --git a/docs/keybindings/Keybindings_ko.md b/docs/keybindings/Keybindings_ko.md index af81c92b1..37696b385 100644 --- a/docs/keybindings/Keybindings_ko.md +++ b/docs/keybindings/Keybindings_ko.md @@ -189,7 +189,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_ | `` F `` | 강제 체크아웃 | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. | | `` d `` | Delete | View delete options for local/remote branch. | | `` r `` | 체크아웃된 브랜치를 이 브랜치에 리베이스 | Rebase the checked-out branch onto the selected branch. | -| `` M `` | 현재 브랜치에 병합 | Merge selected branch into currently checked out branch. | +| `` M `` | 현재 브랜치에 병합 | View options for merging the selected item into the current branch (regular merge, squash merge) | | `` f `` | Fast-forward this branch from its upstream | Fast-forward selected branch from its upstream. | | `` T `` | 태그를 생성 | | | `` s `` | Sort order | | @@ -242,7 +242,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_ | `` <c-o> `` | 브랜치명을 클립보드에 복사 | | | `` <space> `` | 체크아웃 | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. | | `` n `` | 새 브랜치 생성 | | -| `` M `` | 현재 브랜치에 병합 | Merge selected branch into currently checked out branch. | +| `` M `` | 현재 브랜치에 병합 | View options for merging the selected item into the current branch (regular merge, squash merge) | | `` r `` | 체크아웃된 브랜치를 이 브랜치에 리베이스 | Rebase the checked-out branch onto the selected branch. | | `` d `` | Delete | Delete the remote branch from the remote. | | `` u `` | Set as upstream | Set the selected remote branch as the upstream of the checked-out branch. | diff --git a/docs/keybindings/Keybindings_nl.md b/docs/keybindings/Keybindings_nl.md index d7c5e7dc9..f0f117ab0 100644 --- a/docs/keybindings/Keybindings_nl.md +++ b/docs/keybindings/Keybindings_nl.md @@ -101,7 +101,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_ | `` F `` | Forceer checkout | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. | | `` d `` | Delete | View delete options for local/remote branch. | | `` r `` | Rebase branch | Rebase the checked-out branch onto the selected branch. | -| `` M `` | Merge in met huidige checked out branch | Merge selected branch into currently checked out branch. | +| `` M `` | Merge in met huidige checked out branch | View options for merging the selected item into the current branch (regular merge, squash merge) | | `` f `` | Fast-forward deze branch vanaf zijn upstream | Fast-forward selected branch from its upstream. | | `` T `` | Creëer tag | | | `` s `` | Sort order | | @@ -243,7 +243,7 @@ If you would instead like to start an interactive rebase from the selected commi | `` <c-o> `` | Kopieer branch name naar klembord | | | `` <space> `` | Uitchecken | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. | | `` n `` | Nieuwe branch | | -| `` M `` | Merge in met huidige checked out branch | Merge selected branch into currently checked out branch. | +| `` M `` | Merge in met huidige checked out branch | View options for merging the selected item into the current branch (regular merge, squash merge) | | `` r `` | Rebase branch | Rebase the checked-out branch onto the selected branch. | | `` d `` | Delete | Delete the remote branch from the remote. | | `` u `` | Set as upstream | Stel in als upstream van uitgecheckte branch | diff --git a/docs/keybindings/Keybindings_ru.md b/docs/keybindings/Keybindings_ru.md index e7f88c7c9..479df5261 100644 --- a/docs/keybindings/Keybindings_ru.md +++ b/docs/keybindings/Keybindings_ru.md @@ -189,7 +189,7 @@ If you would instead like to start an interactive rebase from the selected commi | `` F `` | Принудительное переключение | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. | | `` d `` | Delete | View delete options for local/remote branch. | | `` r `` | Перебазировать переключённую ветку на эту ветку | Rebase the checked-out branch onto the selected branch. | -| `` M `` | Слияние с текущей переключённой веткой | Merge selected branch into currently checked out branch. | +| `` M `` | Слияние с текущей переключённой веткой | View options for merging the selected item into the current branch (regular merge, squash merge) | | `` f `` | Перемотать эту ветку вперёд из её upstream-ветки | Fast-forward selected branch from its upstream. | | `` T `` | Создать тег | | | `` s `` | Порядок сортировки | | @@ -299,7 +299,7 @@ If you would instead like to start an interactive rebase from the selected commi | `` <c-o> `` | Скопировать название ветки в буфер обмена | | | `` <space> `` | Переключить | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. | | `` n `` | Новая ветка | | -| `` M `` | Слияние с текущей переключённой веткой | Merge selected branch into currently checked out branch. | +| `` M `` | Слияние с текущей переключённой веткой | View options for merging the selected item into the current branch (regular merge, squash merge) | | `` r `` | Перебазировать переключённую ветку на эту ветку | Rebase the checked-out branch onto the selected branch. | | `` d `` | Delete | Delete the remote branch from the remote. | | `` u `` | Set as upstream | Установить как upstream-ветку переключённую ветку | diff --git a/docs/keybindings/Keybindings_zh-CN.md b/docs/keybindings/Keybindings_zh-CN.md index eaff6d141..3c8e7d3ce 100644 --- a/docs/keybindings/Keybindings_zh-CN.md +++ b/docs/keybindings/Keybindings_zh-CN.md @@ -91,7 +91,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_ | `` F `` | 强制检出 | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. | | `` d `` | Delete | View delete options for local/remote branch. | | `` r `` | 将已检出的分支变基到该分支 | Rebase the checked-out branch onto the selected branch. | -| `` M `` | 合并到当前检出的分支 | Merge selected branch into currently checked out branch. | +| `` M `` | 合并到当前检出的分支 | View options for merging the selected item into the current branch (regular merge, squash merge) | | `` f `` | 从上游快进此分支 | Fast-forward selected branch from its upstream. | | `` T `` | 创建标签 | | | `` s `` | Sort order | | @@ -342,7 +342,7 @@ If you would instead like to start an interactive rebase from the selected commi | `` <c-o> `` | 将分支名称复制到剪贴板 | | | `` <space> `` | 检出 | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. | | `` n `` | 新分支 | | -| `` M `` | 合并到当前检出的分支 | Merge selected branch into currently checked out branch. | +| `` M `` | 合并到当前检出的分支 | View options for merging the selected item into the current branch (regular merge, squash merge) | | `` r `` | 将已检出的分支变基到该分支 | Rebase the checked-out branch onto the selected branch. | | `` d `` | Delete | Delete the remote branch from the remote. | | `` u `` | Set as upstream | 设置为检出分支的上游 | diff --git a/docs/keybindings/Keybindings_zh-TW.md b/docs/keybindings/Keybindings_zh-TW.md index 1a891b05f..a90334dad 100644 --- a/docs/keybindings/Keybindings_zh-TW.md +++ b/docs/keybindings/Keybindings_zh-TW.md @@ -264,7 +264,7 @@ If you would instead like to start an interactive rebase from the selected commi | `` F `` | 強制檢出 | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. | | `` d `` | Delete | View delete options for local/remote branch. | | `` r `` | 將已檢出的分支變基至此分支 | Rebase the checked-out branch onto the selected branch. | -| `` M `` | 合併到當前檢出的分支 | Merge selected branch into currently checked out branch. | +| `` M `` | 合併到當前檢出的分支 | View options for merging the selected item into the current branch (regular merge, squash merge) | | `` f `` | 從上游快進此分支 | Fast-forward selected branch from its upstream. | | `` T `` | 建立標籤 | | | `` s `` | Sort order | | @@ -353,7 +353,7 @@ If you would instead like to start an interactive rebase from the selected commi | `` <c-o> `` | 複製分支名稱到剪貼簿 | | | `` <space> `` | 檢出 | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. | | `` n `` | 新分支 | | -| `` M `` | 合併到當前檢出的分支 | Merge selected branch into currently checked out branch. | +| `` M `` | 合併到當前檢出的分支 | View options for merging the selected item into the current branch (regular merge, squash merge) | | `` r `` | 將已檢出的分支變基至此分支 | Rebase the checked-out branch onto the selected branch. | | `` d `` | Delete | Delete the remote branch from the remote. | | `` u `` | Set as upstream | 將此分支設為當前分支之上游 | diff --git a/pkg/commands/git_commands/branch.go b/pkg/commands/git_commands/branch.go index 8212b29b3..79e418d7f 100644 --- a/pkg/commands/git_commands/branch.go +++ b/pkg/commands/git_commands/branch.go @@ -216,13 +216,18 @@ func (self *BranchCommands) Rename(oldName string, newName string) error { type MergeOpts struct { FastForwardOnly bool + Squash bool } func (self *BranchCommands) Merge(branchName string, opts MergeOpts) error { + if opts.Squash && opts.FastForwardOnly { + panic("Squash and FastForwardOnly can't both be true") + } cmdArgs := NewGitCmd("merge"). Arg("--no-edit"). Arg(strings.Fields(self.UserConfig.Git.Merging.Args)...). ArgIf(opts.FastForwardOnly, "--ff-only"). + ArgIf(opts.Squash, "--squash", "--ff"). Arg(branchName). ToArgv() diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index 2c3baaa1b..b5bccba45 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -285,6 +285,8 @@ type MergingConfig struct { ManualCommit bool `yaml:"manualCommit"` // Extra args passed to `git merge`, e.g. --no-ff Args string `yaml:"args" jsonschema:"example=--no-ff"` + // The commit message to use for a squash merge commit. Can contain "{{selectedRef}}" and "{{currentBranch}}" placeholders. + SquashMergeMessage string `yaml:"squashMergeMessage"` } type LogConfig struct { @@ -730,8 +732,9 @@ func GetDefaultConfig() *UserConfig { AutoWrapWidth: 72, }, Merging: MergingConfig{ - ManualCommit: false, - Args: "", + ManualCommit: false, + Args: "", + SquashMergeMessage: "Squash merge {{selectedRef}} into {{currentBranch}}", }, Log: LogConfig{ Order: "topo-order", diff --git a/pkg/gui/controllers/branches_controller.go b/pkg/gui/controllers/branches_controller.go index 8b4a5d395..9f5ba7f05 100644 --- a/pkg/gui/controllers/branches_controller.go +++ b/pkg/gui/controllers/branches_controller.go @@ -111,10 +111,11 @@ func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*ty { Key: opts.GetKey(opts.Config.Branches.MergeIntoCurrentBranch), Handler: opts.Guards.OutsideFilterMode(self.merge), - GetDisabledReason: self.require(self.singleItemSelected()), + GetDisabledReason: self.require(self.singleItemSelected(self.notMergingIntoYourself)), Description: self.c.Tr.Merge, Tooltip: self.c.Tr.MergeBranchTooltip, DisplayOnScreen: true, + OpensMenu: true, }, { Key: opts.GetKey(opts.Config.Branches.FastForward), @@ -826,3 +827,14 @@ func (self *BranchesController) branchIsReal(branch *models.Branch) *types.Disab return nil } + +func (self *BranchesController) notMergingIntoYourself(branch *models.Branch) *types.DisabledReason { + selectedBranchName := branch.Name + checkedOutBranch := self.c.Helpers().Refs.GetCheckedOutRef().Name + + if checkedOutBranch == selectedBranchName { + return &types.DisabledReason{Text: self.c.Tr.CantMergeBranchIntoItself} + } + + return nil +} diff --git a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go index c5ad78c47..a5554aa58 100644 --- a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go +++ b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go @@ -369,25 +369,84 @@ func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) e if checkedOutBranchName == refName { return errors.New(self.c.Tr.CantMergeBranchIntoItself) } - prompt := utils.ResolvePlaceholderString( - self.c.Tr.ConfirmMerge, - map[string]string{ - "checkedOutBranch": checkedOutBranchName, - "selectedBranch": refName, - }, - ) - return self.c.Confirm(types.ConfirmOpts{ - Title: self.c.Tr.MergeConfirmTitle, - Prompt: prompt, - HandleConfirm: func() error { - self.c.LogAction(self.c.Tr.Actions.Merge) - err := self.c.Git().Branch.Merge(refName, git_commands.MergeOpts{}) - return self.CheckMergeOrRebase(err) + return self.c.Menu(types.CreateMenuOptions{ + Title: self.c.Tr.Merge, + Items: []*types.MenuItem{ + { + Label: self.c.Tr.RegularMerge, + OnPress: self.RegularMerge(refName), + Key: 'm', + Tooltip: utils.ResolvePlaceholderString( + self.c.Tr.RegularMergeTooltip, + map[string]string{ + "checkedOutBranch": checkedOutBranchName, + "selectedBranch": refName, + }, + ), + }, + { + Label: self.c.Tr.SquashMergeUncommittedTitle, + OnPress: self.SquashMergeUncommitted(refName), + Key: 's', + Tooltip: utils.ResolvePlaceholderString( + self.c.Tr.SquashMergeUncommitted, + map[string]string{ + "selectedBranch": refName, + }, + ), + }, + { + Label: self.c.Tr.SquashMergeCommittedTitle, + OnPress: self.SquashMergeCommitted(refName, checkedOutBranchName), + Key: 'S', + Tooltip: utils.ResolvePlaceholderString( + self.c.Tr.SquashMergeCommitted, + map[string]string{ + "checkedOutBranch": checkedOutBranchName, + "selectedBranch": refName, + }, + ), + }, }, }) } +func (self *MergeAndRebaseHelper) RegularMerge(refName string) func() error { + return func() error { + self.c.LogAction(self.c.Tr.Actions.Merge) + err := self.c.Git().Branch.Merge(refName, git_commands.MergeOpts{}) + return self.CheckMergeOrRebase(err) + } +} + +func (self *MergeAndRebaseHelper) SquashMergeUncommitted(refName string) func() error { + return func() error { + self.c.LogAction(self.c.Tr.Actions.SquashMerge) + err := self.c.Git().Branch.Merge(refName, git_commands.MergeOpts{Squash: true}) + return self.CheckMergeOrRebase(err) + } +} + +func (self *MergeAndRebaseHelper) SquashMergeCommitted(refName, checkedOutBranchName string) func() error { + return func() error { + self.c.LogAction(self.c.Tr.Actions.SquashMerge) + err := self.c.Git().Branch.Merge(refName, git_commands.MergeOpts{Squash: true}) + if err = self.CheckMergeOrRebase(err); err != nil { + return err + } + message := utils.ResolvePlaceholderString(self.c.UserConfig.Git.Merging.SquashMergeMessage, map[string]string{ + "selectedRef": refName, + "currentBranch": checkedOutBranchName, + }) + err = self.c.Git().Commit.CommitCmdObj(message, "").Run() + if err != nil { + return err + } + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) + } +} + func (self *MergeAndRebaseHelper) ResetMarkedBaseCommit() error { self.c.Modes().MarkedBaseCommit.Reset() return self.c.PostRefreshUpdate(self.c.Contexts().LocalCommits) diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 3665ae8b1..949e96b7d 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -24,7 +24,11 @@ type TranslationSet struct { MainTitle string StagingTitle string MergingTitle string - MergeConfirmTitle string + SquashMergeUncommittedTitle string + SquashMergeCommittedTitle string + SquashMergeUncommitted string + SquashMergeCommitted string + RegularMergeTooltip string NormalTitle string LogTitle string CommitSummary string @@ -133,6 +137,7 @@ type TranslationSet struct { SureFixupThisCommit string SureSquashThisCommit string Squash string + SquashMerge string PickCommitTooltip string Pick string CantPickDisabledReason string @@ -229,6 +234,7 @@ type TranslationSet struct { ExcludeFile string RefreshFiles string Merge string + RegularMerge string MergeBranchTooltip string ConfirmQuit string SwitchRepo string @@ -296,7 +302,6 @@ type TranslationSet struct { InteractiveRebaseTooltip string RebaseOntoBaseBranchTooltip string MustSelectTodoCommits string - ConfirmMerge string FwdNoUpstream string FwdNoLocalUpstream string FwdCommitsToPush string @@ -841,6 +846,7 @@ type Actions struct { DeleteLocalBranch string DeleteBranch string Merge string + SquashMerge string RebaseBranch string RenameBranch string CreateBranch string @@ -993,7 +999,8 @@ func EnglishTranslationSet() *TranslationSet { UnstagedChanges: "Unstaged changes", StagedChanges: "Staged changes", MainTitle: "Main", - MergeConfirmTitle: "Merge", + SquashMergeUncommittedTitle: "Squash merge and leave uncommitted", + SquashMergeCommittedTitle: "Squash merge and commit", StagingTitle: "Main panel (staging)", MergingTitle: "Main panel (merging)", NormalTitle: "Main panel (normal)", @@ -1105,6 +1112,7 @@ func EnglishTranslationSet() *TranslationSet { SureFixupThisCommit: "Are you sure you want to 'fixup' the selected commit(s) into the commit below?", SureSquashThisCommit: "Are you sure you want to squash the selected commit(s) into the commit below?", Squash: "Squash", + SquashMerge: "Squash Merge", PickCommitTooltip: "Mark the selected commit to be picked (when mid-rebase). This means that the commit will be retained upon continuing the rebase.", Pick: "Pick", CantPickDisabledReason: "Cannot pick a commit when not mid-rebase", @@ -1200,7 +1208,8 @@ func EnglishTranslationSet() *TranslationSet { ExcludeFile: `Add to .git/info/exclude`, RefreshFiles: `Refresh files`, Merge: `Merge`, - MergeBranchTooltip: "Merge selected branch into currently checked out branch.", + RegularMerge: "Regular merge", + MergeBranchTooltip: "View options for merging the selected item into the current branch (regular merge, squash merge)", ConfirmQuit: `Are you sure you want to quit?`, SwitchRepo: `Switch to a recent repo`, AllBranchesLogGraph: `Show all branch logs`, @@ -1271,7 +1280,9 @@ func EnglishTranslationSet() *TranslationSet { InteractiveRebaseTooltip: "Begin an interactive rebase with a break at the start, so you can update the TODO commits before continuing.", RebaseOntoBaseBranchTooltip: "Rebase the checked out branch onto its base branch (i.e. the closest main branch).", MustSelectTodoCommits: "When rebasing, this action only works on a selection of TODO commits.", - ConfirmMerge: "Are you sure you want to merge '{{.selectedBranch}}' into '{{.checkedOutBranch}}'?", + SquashMergeUncommitted: "Squash merge '{{.selectedBranch}}' into the working tree.", + SquashMergeCommitted: "Squash merge '{{.selectedBranch}}' into '{{.checkedOutBranch}}' as a single commit.", + RegularMergeTooltip: "Merge '{{.selectedBranch}}' into '{{.checkedOutBranch}}'.", FwdNoUpstream: "Cannot fast-forward a branch with no upstream", FwdNoLocalUpstream: "Cannot fast-forward a branch whose remote is not registered locally", FwdCommitsToPush: "Cannot fast-forward a branch with commits to push", @@ -1770,6 +1781,7 @@ func EnglishTranslationSet() *TranslationSet { DeleteLocalBranch: "Delete local branch", DeleteBranch: "Delete branch", Merge: "Merge", + SquashMerge: "Squash merge", RebaseBranch: "Rebase branch", RenameBranch: "Rename branch", CreateBranch: "Create branch", diff --git a/pkg/integration/tests/branch/squash_merge.go b/pkg/integration/tests/branch/squash_merge.go new file mode 100644 index 000000000..509073cbe --- /dev/null +++ b/pkg/integration/tests/branch/squash_merge.go @@ -0,0 +1,64 @@ +package branch + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var SquashMerge = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Squash merge a branch both with and without committing", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) {}, + SetupRepo: func(shell *Shell) { + shell.NewBranch("original-branch"). + EmptyCommit("one"). + NewBranch("change-worktree-branch"). + CreateFileAndAdd("work", "content"). + Commit("work"). + Checkout("original-branch"). + NewBranch("change-commit-branch"). + CreateFileAndAdd("file", "content"). + Commit("file"). + Checkout("original-branch") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Commits().TopLines( + Contains("one"), + ) + + t.Views().Branches(). + Focus(). + Lines( + Contains("original-branch").IsSelected(), + Contains("change-commit-branch"), + Contains("change-worktree-branch"), + ). + SelectNextItem(). + Press(keys.Branches.MergeIntoCurrentBranch) + + t.ExpectPopup().Menu(). + Title(Equals("Merge")). + Select(Contains("Squash merge and commit")). + Confirm() + + t.Views().Commits().TopLines( + Contains("Squash merge change-commit-branch into original-branch"), + Contains("one"), + ) + + t.Views().Branches(). + Focus(). + NavigateToLine(Contains("change-worktree-branch")). + Press(keys.Branches.MergeIntoCurrentBranch) + + t.ExpectPopup().Menu(). + Title(Equals("Merge")). + Select(Contains("Squash merge and leave uncommitted")). + Confirm() + + t.Views().Files().Focus().Lines( + Contains("work"), + ) + }, +}) diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index b6ebad021..22072be97 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -61,6 +61,7 @@ var tests = []*components.IntegrationTest{ branch.ShowDivergenceFromUpstream, branch.SortLocalBranches, branch.SortRemoteBranches, + branch.SquashMerge, branch.Suggestions, branch.UnsetUpstream, cherry_pick.CherryPick, diff --git a/pkg/integration/tests/ui/mode_specific_keybinding_suggestions.go b/pkg/integration/tests/ui/mode_specific_keybinding_suggestions.go index f11e5fd27..5cd412146 100644 --- a/pkg/integration/tests/ui/mode_specific_keybinding_suggestions.go +++ b/pkg/integration/tests/ui/mode_specific_keybinding_suggestions.go @@ -93,7 +93,7 @@ var ModeSpecificKeybindingSuggestions = NewIntegrationTest(NewIntegrationTestArg t.Views().Options().Content(DoesNotContain(customPatchSuggestion)) }) - // Test merge options suggestion + // Test merge options suggestion t.Views().Branches(). Focus(). NavigateToLine(Contains("first-change-branch")). @@ -101,9 +101,9 @@ var ModeSpecificKeybindingSuggestions = NewIntegrationTest(NewIntegrationTestArg NavigateToLine(Contains("second-change-branch")). Press(keys.Branches.MergeIntoCurrentBranch). Tap(func() { - t.ExpectPopup().Confirmation(). + t.ExpectPopup().Menu(). Title(Equals("Merge")). - Content(Contains("Are you sure you want to merge")). + Select(Contains("Regular merge")). Confirm() t.Common().AcknowledgeConflicts() diff --git a/schema/config.json b/schema/config.json index ba422388a..580765c0f 100644 --- a/schema/config.json +++ b/schema/config.json @@ -530,6 +530,11 @@ "examples": [ "--no-ff" ] + }, + "squashMergeMessage": { + "type": "string", + "description": "The commit message to use for a squash merge commit. Can contain \"{{selectedRef}}\" and \"{{currentBranch}}\" placeholders.", + "default": "Squash merge {{selectedRef}} into {{currentBranch}}" } }, "additionalProperties": false, |