summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/Config.md3
-rw-r--r--docs/keybindings/Keybindings_en.md4
-rw-r--r--docs/keybindings/Keybindings_ja.md4
-rw-r--r--docs/keybindings/Keybindings_ko.md4
-rw-r--r--docs/keybindings/Keybindings_nl.md4
-rw-r--r--docs/keybindings/Keybindings_ru.md4
-rw-r--r--docs/keybindings/Keybindings_zh-CN.md4
-rw-r--r--docs/keybindings/Keybindings_zh-TW.md4
-rw-r--r--pkg/commands/git_commands/branch.go5
-rw-r--r--pkg/config/user_config.go7
-rw-r--r--pkg/gui/controllers/branches_controller.go14
-rw-r--r--pkg/gui/controllers/helpers/merge_and_rebase_helper.go87
-rw-r--r--pkg/i18n/english.go22
-rw-r--r--pkg/integration/tests/branch/squash_merge.go64
-rw-r--r--pkg/integration/tests/test_list.go1
-rw-r--r--pkg/integration/tests/ui/mode_specific_keybinding_suggestions.go6
-rw-r--r--schema/config.json5
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,