mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-02-09 13:47:11 +02:00
Add a "Mark commit as base commit for rebase" command
This allows to do the equivalent of "git rebase --onto <target> <base>", by first marking the <base> commit with the new command, and then selecting the target branch and invoking the usual rebase command there.
This commit is contained in:
parent
375451785c
commit
66de981e91
@ -84,6 +84,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd><c-j></kbd>: Move commit down one
|
<kbd><c-j></kbd>: Move commit down one
|
||||||
<kbd><c-k></kbd>: Move commit up one
|
<kbd><c-k></kbd>: Move commit up one
|
||||||
<kbd>v</kbd>: Paste commits (cherry-pick)
|
<kbd>v</kbd>: Paste commits (cherry-pick)
|
||||||
|
<kbd>B</kbd>: Mark commit as base commit for rebase
|
||||||
<kbd>A</kbd>: Amend commit with staged changes
|
<kbd>A</kbd>: Amend commit with staged changes
|
||||||
<kbd>a</kbd>: Set/Reset commit author
|
<kbd>a</kbd>: Set/Reset commit author
|
||||||
<kbd>t</kbd>: Revert commit
|
<kbd>t</kbd>: Revert commit
|
||||||
|
@ -103,6 +103,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd><c-j></kbd>: コミットを1つ下に移動
|
<kbd><c-j></kbd>: コミットを1つ下に移動
|
||||||
<kbd><c-k></kbd>: コミットを1つ上に移動
|
<kbd><c-k></kbd>: コミットを1つ上に移動
|
||||||
<kbd>v</kbd>: コミットを貼り付け (cherry-pick)
|
<kbd>v</kbd>: コミットを貼り付け (cherry-pick)
|
||||||
|
<kbd>B</kbd>: Mark commit as base commit for rebase
|
||||||
<kbd>A</kbd>: ステージされた変更でamendコミット
|
<kbd>A</kbd>: ステージされた変更でamendコミット
|
||||||
<kbd>a</kbd>: Set/Reset commit author
|
<kbd>a</kbd>: Set/Reset commit author
|
||||||
<kbd>t</kbd>: コミットをrevert
|
<kbd>t</kbd>: コミットをrevert
|
||||||
|
@ -265,6 +265,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd><c-j></kbd>: 커밋을 1개 아래로 이동
|
<kbd><c-j></kbd>: 커밋을 1개 아래로 이동
|
||||||
<kbd><c-k></kbd>: 커밋을 1개 위로 이동
|
<kbd><c-k></kbd>: 커밋을 1개 위로 이동
|
||||||
<kbd>v</kbd>: 커밋을 붙여넣기 (cherry-pick)
|
<kbd>v</kbd>: 커밋을 붙여넣기 (cherry-pick)
|
||||||
|
<kbd>B</kbd>: Mark commit as base commit for rebase
|
||||||
<kbd>A</kbd>: Amend commit with staged changes
|
<kbd>A</kbd>: Amend commit with staged changes
|
||||||
<kbd>a</kbd>: Set/Reset commit author
|
<kbd>a</kbd>: Set/Reset commit author
|
||||||
<kbd>t</kbd>: 커밋 되돌리기
|
<kbd>t</kbd>: 커밋 되돌리기
|
||||||
|
@ -143,6 +143,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd><c-j></kbd>: Verplaats commit 1 naar beneden
|
<kbd><c-j></kbd>: Verplaats commit 1 naar beneden
|
||||||
<kbd><c-k></kbd>: Verplaats commit 1 naar boven
|
<kbd><c-k></kbd>: Verplaats commit 1 naar boven
|
||||||
<kbd>v</kbd>: Plak commits (cherry-pick)
|
<kbd>v</kbd>: Plak commits (cherry-pick)
|
||||||
|
<kbd>B</kbd>: Mark commit as base commit for rebase
|
||||||
<kbd>A</kbd>: Wijzig commit met staged veranderingen
|
<kbd>A</kbd>: Wijzig commit met staged veranderingen
|
||||||
<kbd>a</kbd>: Set/Reset commit author
|
<kbd>a</kbd>: Set/Reset commit author
|
||||||
<kbd>t</kbd>: Commit ongedaan maken
|
<kbd>t</kbd>: Commit ongedaan maken
|
||||||
|
@ -69,6 +69,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd><c-j></kbd>: Przenieś commit 1 w dół
|
<kbd><c-j></kbd>: Przenieś commit 1 w dół
|
||||||
<kbd><c-k></kbd>: Przenieś commit 1 w górę
|
<kbd><c-k></kbd>: Przenieś commit 1 w górę
|
||||||
<kbd>v</kbd>: Wklej commity (przebieranie)
|
<kbd>v</kbd>: Wklej commity (przebieranie)
|
||||||
|
<kbd>B</kbd>: Mark commit as base commit for rebase
|
||||||
<kbd>A</kbd>: Popraw commit zmianami z poczekalni
|
<kbd>A</kbd>: Popraw commit zmianami z poczekalni
|
||||||
<kbd>a</kbd>: Set/Reset commit author
|
<kbd>a</kbd>: Set/Reset commit author
|
||||||
<kbd>t</kbd>: Odwróć commit
|
<kbd>t</kbd>: Odwróć commit
|
||||||
|
@ -151,6 +151,7 @@ _Связки клавиш_
|
|||||||
<kbd><c-j></kbd>: Переместить коммит вниз на один
|
<kbd><c-j></kbd>: Переместить коммит вниз на один
|
||||||
<kbd><c-k></kbd>: Переместить коммит вверх на один
|
<kbd><c-k></kbd>: Переместить коммит вверх на один
|
||||||
<kbd>v</kbd>: Вставить отобранные коммиты (cherry-pick)
|
<kbd>v</kbd>: Вставить отобранные коммиты (cherry-pick)
|
||||||
|
<kbd>B</kbd>: Mark commit as base commit for rebase
|
||||||
<kbd>A</kbd>: Править последний коммит с проиндексированными изменениями
|
<kbd>A</kbd>: Править последний коммит с проиндексированными изменениями
|
||||||
<kbd>a</kbd>: Установить/убрать автора коммита
|
<kbd>a</kbd>: Установить/убрать автора коммита
|
||||||
<kbd>t</kbd>: Отменить коммит
|
<kbd>t</kbd>: Отменить коммит
|
||||||
|
@ -147,6 +147,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd><c-j></kbd>: 下移提交
|
<kbd><c-j></kbd>: 下移提交
|
||||||
<kbd><c-k></kbd>: 上移提交
|
<kbd><c-k></kbd>: 上移提交
|
||||||
<kbd>v</kbd>: 粘贴提交(拣选)
|
<kbd>v</kbd>: 粘贴提交(拣选)
|
||||||
|
<kbd>B</kbd>: Mark commit as base commit for rebase
|
||||||
<kbd>A</kbd>: 用已暂存的更改来修补提交
|
<kbd>A</kbd>: 用已暂存的更改来修补提交
|
||||||
<kbd>a</kbd>: Set/Reset commit author
|
<kbd>a</kbd>: Set/Reset commit author
|
||||||
<kbd>t</kbd>: 还原提交
|
<kbd>t</kbd>: 还原提交
|
||||||
|
@ -191,6 +191,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
<kbd><c-j></kbd>: 向下移動提交
|
<kbd><c-j></kbd>: 向下移動提交
|
||||||
<kbd><c-k></kbd>: 向上移動提交
|
<kbd><c-k></kbd>: 向上移動提交
|
||||||
<kbd>v</kbd>: 貼上提交 (揀選)
|
<kbd>v</kbd>: 貼上提交 (揀選)
|
||||||
|
<kbd>B</kbd>: Mark commit as base commit for rebase
|
||||||
<kbd>A</kbd>: 使用已預存的更改修正提交
|
<kbd>A</kbd>: 使用已預存的更改修正提交
|
||||||
<kbd>a</kbd>: 設置/重設提交作者
|
<kbd>a</kbd>: 設置/重設提交作者
|
||||||
<kbd>t</kbd>: 還原提交
|
<kbd>t</kbd>: 還原提交
|
||||||
|
@ -156,6 +156,15 @@ func (self *RebaseCommands) EditRebase(branchRef string) error {
|
|||||||
}).Run()
|
}).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *RebaseCommands) EditRebaseFromBaseCommit(targetBranchName string, baseCommit string) error {
|
||||||
|
self.os.LogCommand(fmt.Sprintf("Beginning interactive rebase from '%s' onto '%s", baseCommit, targetBranchName), false)
|
||||||
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
|
baseShaOrRoot: baseCommit,
|
||||||
|
onto: targetBranchName,
|
||||||
|
instruction: daemon.NewInsertBreakInstruction(),
|
||||||
|
}).Run()
|
||||||
|
}
|
||||||
|
|
||||||
func logTodoChanges(changes []daemon.ChangeTodoAction) string {
|
func logTodoChanges(changes []daemon.ChangeTodoAction) string {
|
||||||
changeTodoStr := strings.Join(lo.Map(changes, func(c daemon.ChangeTodoAction, _ int) string {
|
changeTodoStr := strings.Join(lo.Map(changes, func(c daemon.ChangeTodoAction, _ int) string {
|
||||||
return fmt.Sprintf("%s:%s", c.Sha, c.NewAction)
|
return fmt.Sprintf("%s:%s", c.Sha, c.NewAction)
|
||||||
@ -165,6 +174,7 @@ func logTodoChanges(changes []daemon.ChangeTodoAction) string {
|
|||||||
|
|
||||||
type PrepareInteractiveRebaseCommandOpts struct {
|
type PrepareInteractiveRebaseCommandOpts struct {
|
||||||
baseShaOrRoot string
|
baseShaOrRoot string
|
||||||
|
onto string
|
||||||
instruction daemon.Instruction
|
instruction daemon.Instruction
|
||||||
overrideEditor bool
|
overrideEditor bool
|
||||||
keepCommitsThatBecomeEmpty bool
|
keepCommitsThatBecomeEmpty bool
|
||||||
@ -183,6 +193,7 @@ func (self *RebaseCommands) PrepareInteractiveRebaseCommand(opts PrepareInteract
|
|||||||
ArgIf(opts.keepCommitsThatBecomeEmpty && !self.version.IsOlderThan(2, 26, 0), "--empty=keep").
|
ArgIf(opts.keepCommitsThatBecomeEmpty && !self.version.IsOlderThan(2, 26, 0), "--empty=keep").
|
||||||
Arg("--no-autosquash").
|
Arg("--no-autosquash").
|
||||||
ArgIf(!self.version.IsOlderThan(2, 22, 0), "--rebase-merges").
|
ArgIf(!self.version.IsOlderThan(2, 22, 0), "--rebase-merges").
|
||||||
|
ArgIf(opts.onto != "", "--onto", opts.onto).
|
||||||
Arg(opts.baseShaOrRoot).
|
Arg(opts.baseShaOrRoot).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
@ -306,6 +317,13 @@ func (self *RebaseCommands) RebaseBranch(branchName string) error {
|
|||||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{baseShaOrRoot: branchName}).Run()
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{baseShaOrRoot: branchName}).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *RebaseCommands) RebaseBranchFromBaseCommit(targetBranchName string, baseCommit string) error {
|
||||||
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
|
baseShaOrRoot: baseCommit,
|
||||||
|
onto: targetBranchName,
|
||||||
|
}).Run()
|
||||||
|
}
|
||||||
|
|
||||||
func (self *RebaseCommands) GenericMergeOrRebaseActionCmdObj(commandType string, command string) oscommands.ICmdObj {
|
func (self *RebaseCommands) GenericMergeOrRebaseActionCmdObj(commandType string, command string) oscommands.ICmdObj {
|
||||||
cmdArgs := NewGitCmd(commandType).Arg("--" + command).ToArgv()
|
cmdArgs := NewGitCmd(commandType).Arg("--" + command).ToArgv()
|
||||||
|
|
||||||
|
@ -67,6 +67,8 @@ type ThemeConfig struct {
|
|||||||
SelectedRangeBgColor []string `yaml:"selectedRangeBgColor"`
|
SelectedRangeBgColor []string `yaml:"selectedRangeBgColor"`
|
||||||
CherryPickedCommitBgColor []string `yaml:"cherryPickedCommitBgColor"`
|
CherryPickedCommitBgColor []string `yaml:"cherryPickedCommitBgColor"`
|
||||||
CherryPickedCommitFgColor []string `yaml:"cherryPickedCommitFgColor"`
|
CherryPickedCommitFgColor []string `yaml:"cherryPickedCommitFgColor"`
|
||||||
|
MarkedBaseCommitBgColor []string `yaml:"markedBaseCommitBgColor"`
|
||||||
|
MarkedBaseCommitFgColor []string `yaml:"markedBaseCommitFgColor"`
|
||||||
UnstagedChangesColor []string `yaml:"unstagedChangesColor"`
|
UnstagedChangesColor []string `yaml:"unstagedChangesColor"`
|
||||||
DefaultFgColor []string `yaml:"defaultFgColor"`
|
DefaultFgColor []string `yaml:"defaultFgColor"`
|
||||||
}
|
}
|
||||||
@ -267,6 +269,7 @@ type KeybindingCommitsConfig struct {
|
|||||||
CherryPickCopy string `yaml:"cherryPickCopy"`
|
CherryPickCopy string `yaml:"cherryPickCopy"`
|
||||||
CherryPickCopyRange string `yaml:"cherryPickCopyRange"`
|
CherryPickCopyRange string `yaml:"cherryPickCopyRange"`
|
||||||
PasteCommits string `yaml:"pasteCommits"`
|
PasteCommits string `yaml:"pasteCommits"`
|
||||||
|
MarkCommitAsBaseForRebase string `yaml:"markCommitAsBaseForRebase"`
|
||||||
CreateTag string `yaml:"tagCommit"`
|
CreateTag string `yaml:"tagCommit"`
|
||||||
CheckoutCommit string `yaml:"checkoutCommit"`
|
CheckoutCommit string `yaml:"checkoutCommit"`
|
||||||
ResetCherryPick string `yaml:"resetCherryPick"`
|
ResetCherryPick string `yaml:"resetCherryPick"`
|
||||||
@ -432,6 +435,8 @@ func GetDefaultConfig() *UserConfig {
|
|||||||
SelectedRangeBgColor: []string{"blue"},
|
SelectedRangeBgColor: []string{"blue"},
|
||||||
CherryPickedCommitBgColor: []string{"cyan"},
|
CherryPickedCommitBgColor: []string{"cyan"},
|
||||||
CherryPickedCommitFgColor: []string{"blue"},
|
CherryPickedCommitFgColor: []string{"blue"},
|
||||||
|
MarkedBaseCommitBgColor: []string{"yellow"},
|
||||||
|
MarkedBaseCommitFgColor: []string{"blue"},
|
||||||
UnstagedChangesColor: []string{"red"},
|
UnstagedChangesColor: []string{"red"},
|
||||||
DefaultFgColor: []string{"default"},
|
DefaultFgColor: []string{"default"},
|
||||||
},
|
},
|
||||||
@ -613,6 +618,7 @@ func GetDefaultConfig() *UserConfig {
|
|||||||
CherryPickCopy: "c",
|
CherryPickCopy: "c",
|
||||||
CherryPickCopyRange: "C",
|
CherryPickCopyRange: "C",
|
||||||
PasteCommits: "v",
|
PasteCommits: "v",
|
||||||
|
MarkCommitAsBaseForRebase: "B",
|
||||||
CreateTag: "T",
|
CreateTag: "T",
|
||||||
CheckoutCommit: "<space>",
|
CheckoutCommit: "<space>",
|
||||||
ResetCherryPick: "<c-R>",
|
ResetCherryPick: "<c-R>",
|
||||||
|
@ -49,6 +49,7 @@ func NewLocalCommitsContext(c *ContextCommon) *LocalCommitsContext {
|
|||||||
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
|
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
|
||||||
c.Modes().CherryPicking.SelectedShaSet(),
|
c.Modes().CherryPicking.SelectedShaSet(),
|
||||||
c.Modes().Diffing.Ref,
|
c.Modes().Diffing.Ref,
|
||||||
|
c.Modes().MarkedBaseCommit.GetSha(),
|
||||||
c.UserConfig.Gui.TimeFormat,
|
c.UserConfig.Gui.TimeFormat,
|
||||||
c.UserConfig.Gui.ShortTimeFormat,
|
c.UserConfig.Gui.ShortTimeFormat,
|
||||||
time.Now(),
|
time.Now(),
|
||||||
|
@ -65,6 +65,7 @@ func NewSubCommitsContext(
|
|||||||
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
|
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
|
||||||
c.Modes().CherryPicking.SelectedShaSet(),
|
c.Modes().CherryPicking.SelectedShaSet(),
|
||||||
c.Modes().Diffing.Ref,
|
c.Modes().Diffing.Ref,
|
||||||
|
"",
|
||||||
c.UserConfig.Gui.TimeFormat,
|
c.UserConfig.Gui.TimeFormat,
|
||||||
c.UserConfig.Gui.ShortTimeFormat,
|
c.UserConfig.Gui.ShortTimeFormat,
|
||||||
time.Now(),
|
time.Now(),
|
||||||
|
@ -224,8 +224,18 @@ func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error {
|
|||||||
Key: 's',
|
Key: 's',
|
||||||
OnPress: func() error {
|
OnPress: func() error {
|
||||||
self.c.LogAction(self.c.Tr.Actions.RebaseBranch)
|
self.c.LogAction(self.c.Tr.Actions.RebaseBranch)
|
||||||
err := self.c.Git().Rebase.RebaseBranch(ref)
|
baseCommit := self.c.Modes().MarkedBaseCommit.GetSha()
|
||||||
return self.CheckMergeOrRebase(err)
|
var err error
|
||||||
|
if baseCommit != "" {
|
||||||
|
err = self.c.Git().Rebase.RebaseBranchFromBaseCommit(ref, baseCommit)
|
||||||
|
} else {
|
||||||
|
err = self.c.Git().Rebase.RebaseBranch(ref)
|
||||||
|
}
|
||||||
|
err = self.CheckMergeOrRebase(err)
|
||||||
|
if err == nil {
|
||||||
|
self.c.Modes().MarkedBaseCommit.Reset()
|
||||||
|
}
|
||||||
|
return err
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -234,17 +244,26 @@ func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error {
|
|||||||
Tooltip: self.c.Tr.InteractiveRebaseTooltip,
|
Tooltip: self.c.Tr.InteractiveRebaseTooltip,
|
||||||
OnPress: func() error {
|
OnPress: func() error {
|
||||||
self.c.LogAction(self.c.Tr.Actions.RebaseBranch)
|
self.c.LogAction(self.c.Tr.Actions.RebaseBranch)
|
||||||
err := self.c.Git().Rebase.EditRebase(ref)
|
baseCommit := self.c.Modes().MarkedBaseCommit.GetSha()
|
||||||
|
var err error
|
||||||
|
if baseCommit != "" {
|
||||||
|
err = self.c.Git().Rebase.EditRebaseFromBaseCommit(ref, baseCommit)
|
||||||
|
} else {
|
||||||
|
err = self.c.Git().Rebase.EditRebase(ref)
|
||||||
|
}
|
||||||
if err = self.CheckMergeOrRebase(err); err != nil {
|
if err = self.CheckMergeOrRebase(err); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
self.c.Modes().MarkedBaseCommit.Reset()
|
||||||
return self.c.PushContext(self.c.Contexts().LocalCommits)
|
return self.c.PushContext(self.c.Contexts().LocalCommits)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
title := utils.ResolvePlaceholderString(
|
title := utils.ResolvePlaceholderString(
|
||||||
self.c.Tr.RebasingTitle,
|
lo.Ternary(self.c.Modes().MarkedBaseCommit.GetSha() != "",
|
||||||
|
self.c.Tr.RebasingFromBaseCommitTitle,
|
||||||
|
self.c.Tr.RebasingTitle),
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"checkedOutBranch": checkedOutBranch,
|
"checkedOutBranch": checkedOutBranch,
|
||||||
"ref": ref,
|
"ref": ref,
|
||||||
@ -283,3 +302,8 @@ func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) e
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *MergeAndRebaseHelper) ResetMarkedBaseCommit() error {
|
||||||
|
self.c.Modes().MarkedBaseCommit.Reset()
|
||||||
|
return self.c.PostRefreshUpdate(self.c.Contexts().LocalCommits)
|
||||||
|
}
|
||||||
|
@ -82,6 +82,16 @@ func (self *ModeHelper) Statuses() []ModeStatus {
|
|||||||
},
|
},
|
||||||
Reset: self.ExitFilterMode,
|
Reset: self.ExitFilterMode,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
IsActive: self.c.Modes().MarkedBaseCommit.Active,
|
||||||
|
Description: func() string {
|
||||||
|
return self.withResetButton(
|
||||||
|
self.c.Tr.MarkedBaseCommitStatus,
|
||||||
|
style.FgCyan,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Reset: self.mergeAndRebaseHelper.ResetMarkedBaseCommit,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
IsActive: self.c.Modes().CherryPicking.Active,
|
IsActive: self.c.Modes().CherryPicking.Active,
|
||||||
Description: func() string {
|
Description: func() string {
|
||||||
|
@ -103,6 +103,12 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
|||||||
Handler: self.paste,
|
Handler: self.paste,
|
||||||
Description: self.c.Tr.PasteCommits,
|
Description: self.c.Tr.PasteCommits,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Key: opts.GetKey(opts.Config.Commits.MarkCommitAsBaseForRebase),
|
||||||
|
Handler: self.checkSelected(self.markAsBaseCommit),
|
||||||
|
Description: self.c.Tr.MarkAsBaseCommit,
|
||||||
|
Tooltip: self.c.Tr.MarkAsBaseCommitTooltip,
|
||||||
|
},
|
||||||
// overriding these navigation keybindings because we might need to load
|
// overriding these navigation keybindings because we might need to load
|
||||||
// more commits on demand
|
// more commits on demand
|
||||||
{
|
{
|
||||||
@ -840,6 +846,16 @@ func (self *LocalCommitsController) paste() error {
|
|||||||
return self.c.Helpers().CherryPick.Paste()
|
return self.c.Helpers().CherryPick.Paste()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *LocalCommitsController) markAsBaseCommit(commit *models.Commit) error {
|
||||||
|
if commit.Sha == self.c.Modes().MarkedBaseCommit.GetSha() {
|
||||||
|
// Reset when invoking it again on the marked commit
|
||||||
|
self.c.Modes().MarkedBaseCommit.SetSha("")
|
||||||
|
} else {
|
||||||
|
self.c.Modes().MarkedBaseCommit.SetSha(commit.Sha)
|
||||||
|
}
|
||||||
|
return self.c.PostRefreshUpdate(self.c.Contexts().LocalCommits)
|
||||||
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) isHeadCommit() bool {
|
func (self *LocalCommitsController) isHeadCommit() bool {
|
||||||
return models.IsHeadCommit(self.c.Model().Commits, self.context().GetSelectedLineIdx())
|
return models.IsHeadCommit(self.c.Model().Commits, self.context().GetSelectedLineIdx())
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
"github.com/jesseduffield/lazygit/pkg/gui/modes/cherrypicking"
|
"github.com/jesseduffield/lazygit/pkg/gui/modes/cherrypicking"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/modes/diffing"
|
"github.com/jesseduffield/lazygit/pkg/gui/modes/diffing"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/modes/filtering"
|
"github.com/jesseduffield/lazygit/pkg/gui/modes/filtering"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/modes/marked_base_commit"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/popup"
|
"github.com/jesseduffield/lazygit/pkg/gui/popup"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
|
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/presentation/authors"
|
"github.com/jesseduffield/lazygit/pkg/gui/presentation/authors"
|
||||||
@ -362,9 +363,10 @@ func (gui *Gui) resetState(startArgs appTypes.StartArgs) types.Context {
|
|||||||
Authors: map[string]*models.Author{},
|
Authors: map[string]*models.Author{},
|
||||||
},
|
},
|
||||||
Modes: &types.Modes{
|
Modes: &types.Modes{
|
||||||
Filtering: filtering.New(startArgs.FilterPath),
|
Filtering: filtering.New(startArgs.FilterPath),
|
||||||
CherryPicking: cherrypicking.New(),
|
CherryPicking: cherrypicking.New(),
|
||||||
Diffing: diffing.New(),
|
Diffing: diffing.New(),
|
||||||
|
MarkedBaseCommit: marked_base_commit.New(),
|
||||||
},
|
},
|
||||||
ScreenMode: initialScreenMode,
|
ScreenMode: initialScreenMode,
|
||||||
// TODO: only use contexts from context manager
|
// TODO: only use contexts from context manager
|
||||||
|
25
pkg/gui/modes/marked_base_commit/marked_base_commit.go
Normal file
25
pkg/gui/modes/marked_base_commit/marked_base_commit.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package marked_base_commit
|
||||||
|
|
||||||
|
type MarkedBaseCommit struct {
|
||||||
|
sha string // the sha of the commit used as a rebase base commit; empty string when unset
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() MarkedBaseCommit {
|
||||||
|
return MarkedBaseCommit{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MarkedBaseCommit) Active() bool {
|
||||||
|
return m.sha != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MarkedBaseCommit) Reset() {
|
||||||
|
m.sha = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MarkedBaseCommit) SetSha(sha string) {
|
||||||
|
m.sha = sha
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MarkedBaseCommit) GetSha() string {
|
||||||
|
return m.sha
|
||||||
|
}
|
@ -45,6 +45,7 @@ func GetCommitListDisplayStrings(
|
|||||||
fullDescription bool,
|
fullDescription bool,
|
||||||
cherryPickedCommitShaSet *set.Set[string],
|
cherryPickedCommitShaSet *set.Set[string],
|
||||||
diffName string,
|
diffName string,
|
||||||
|
markedBaseCommit string,
|
||||||
timeFormat string,
|
timeFormat string,
|
||||||
shortTimeFormat string,
|
shortTimeFormat string,
|
||||||
now time.Time,
|
now time.Time,
|
||||||
@ -128,6 +129,7 @@ func GetCommitListDisplayStrings(
|
|||||||
|
|
||||||
lines := make([][]string, 0, len(filteredCommits))
|
lines := make([][]string, 0, len(filteredCommits))
|
||||||
var bisectStatus BisectStatus
|
var bisectStatus BisectStatus
|
||||||
|
willBeRebased := markedBaseCommit == ""
|
||||||
for i, commit := range filteredCommits {
|
for i, commit := range filteredCommits {
|
||||||
unfilteredIdx := i + startIdx
|
unfilteredIdx := i + startIdx
|
||||||
bisectStatus = getBisectStatus(unfilteredIdx, commit.Sha, bisectInfo, bisectBounds)
|
bisectStatus = getBisectStatus(unfilteredIdx, commit.Sha, bisectInfo, bisectBounds)
|
||||||
@ -136,11 +138,17 @@ func GetCommitListDisplayStrings(
|
|||||||
isYouAreHereCommit = true
|
isYouAreHereCommit = true
|
||||||
showYouAreHereLabel = false
|
showYouAreHereLabel = false
|
||||||
}
|
}
|
||||||
|
isMarkedBaseCommit := commit.Sha != "" && commit.Sha == markedBaseCommit
|
||||||
|
if isMarkedBaseCommit {
|
||||||
|
willBeRebased = true
|
||||||
|
}
|
||||||
lines = append(lines, displayCommit(
|
lines = append(lines, displayCommit(
|
||||||
common,
|
common,
|
||||||
commit,
|
commit,
|
||||||
branchHeadsToVisualize,
|
branchHeadsToVisualize,
|
||||||
cherryPickedCommitShaSet,
|
cherryPickedCommitShaSet,
|
||||||
|
isMarkedBaseCommit,
|
||||||
|
willBeRebased,
|
||||||
diffName,
|
diffName,
|
||||||
timeFormat,
|
timeFormat,
|
||||||
shortTimeFormat,
|
shortTimeFormat,
|
||||||
@ -290,6 +298,8 @@ func displayCommit(
|
|||||||
commit *models.Commit,
|
commit *models.Commit,
|
||||||
branchHeadsToVisualize *set.Set[string],
|
branchHeadsToVisualize *set.Set[string],
|
||||||
cherryPickedCommitShaSet *set.Set[string],
|
cherryPickedCommitShaSet *set.Set[string],
|
||||||
|
isMarkedBaseCommit bool,
|
||||||
|
willBeRebased bool,
|
||||||
diffName string,
|
diffName string,
|
||||||
timeFormat string,
|
timeFormat string,
|
||||||
shortTimeFormat string,
|
shortTimeFormat string,
|
||||||
@ -335,6 +345,12 @@ func displayCommit(
|
|||||||
color := lo.Ternary(commit.Action == models.ActionConflict, style.FgRed, style.FgYellow)
|
color := lo.Ternary(commit.Action == models.ActionConflict, style.FgRed, style.FgYellow)
|
||||||
youAreHere := color.Sprintf("<-- %s ---", common.Tr.YouAreHere)
|
youAreHere := color.Sprintf("<-- %s ---", common.Tr.YouAreHere)
|
||||||
name = fmt.Sprintf("%s %s", youAreHere, name)
|
name = fmt.Sprintf("%s %s", youAreHere, name)
|
||||||
|
} else if isMarkedBaseCommit {
|
||||||
|
rebaseFromHere := style.FgYellow.Sprint(common.Tr.MarkedCommitMarker)
|
||||||
|
name = fmt.Sprintf("%s %s", rebaseFromHere, name)
|
||||||
|
} else if !willBeRebased {
|
||||||
|
willBeRebased := style.FgYellow.Sprint("✓")
|
||||||
|
name = fmt.Sprintf("%s %s", willBeRebased, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
authorFunc := authors.ShortAuthor
|
authorFunc := authors.ShortAuthor
|
||||||
|
@ -33,6 +33,7 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
|
|||||||
hasUpdateRefConfig bool
|
hasUpdateRefConfig bool
|
||||||
fullDescription bool
|
fullDescription bool
|
||||||
cherryPickedCommitShaSet *set.Set[string]
|
cherryPickedCommitShaSet *set.Set[string]
|
||||||
|
markedBaseCommit string
|
||||||
diffName string
|
diffName string
|
||||||
timeFormat string
|
timeFormat string
|
||||||
shortTimeFormat string
|
shortTimeFormat string
|
||||||
@ -408,6 +409,7 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
|
|||||||
s.fullDescription,
|
s.fullDescription,
|
||||||
s.cherryPickedCommitShaSet,
|
s.cherryPickedCommitShaSet,
|
||||||
s.diffName,
|
s.diffName,
|
||||||
|
s.markedBaseCommit,
|
||||||
s.timeFormat,
|
s.timeFormat,
|
||||||
s.shortTimeFormat,
|
s.shortTimeFormat,
|
||||||
s.now,
|
s.now,
|
||||||
|
@ -4,10 +4,12 @@ import (
|
|||||||
"github.com/jesseduffield/lazygit/pkg/gui/modes/cherrypicking"
|
"github.com/jesseduffield/lazygit/pkg/gui/modes/cherrypicking"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/modes/diffing"
|
"github.com/jesseduffield/lazygit/pkg/gui/modes/diffing"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/modes/filtering"
|
"github.com/jesseduffield/lazygit/pkg/gui/modes/filtering"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/modes/marked_base_commit"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Modes struct {
|
type Modes struct {
|
||||||
Filtering filtering.Filtering
|
Filtering filtering.Filtering
|
||||||
CherryPicking *cherrypicking.CherryPicking
|
CherryPicking *cherrypicking.CherryPicking
|
||||||
Diffing diffing.Diffing
|
Diffing diffing.Diffing
|
||||||
|
MarkedBaseCommit marked_base_commit.MarkedBaseCommit
|
||||||
}
|
}
|
||||||
|
@ -209,6 +209,7 @@ type TranslationSet struct {
|
|||||||
ConflictsResolved string
|
ConflictsResolved string
|
||||||
Continue string
|
Continue string
|
||||||
RebasingTitle string
|
RebasingTitle string
|
||||||
|
RebasingFromBaseCommitTitle string
|
||||||
SimpleRebase string
|
SimpleRebase string
|
||||||
InteractiveRebase string
|
InteractiveRebase string
|
||||||
InteractiveRebaseTooltip string
|
InteractiveRebaseTooltip string
|
||||||
@ -578,6 +579,10 @@ type TranslationSet struct {
|
|||||||
Name string
|
Name string
|
||||||
Branch string
|
Branch string
|
||||||
Path string
|
Path string
|
||||||
|
MarkedBaseCommitStatus string
|
||||||
|
MarkAsBaseCommit string
|
||||||
|
MarkAsBaseCommitTooltip string
|
||||||
|
MarkedCommitMarker string
|
||||||
Actions Actions
|
Actions Actions
|
||||||
Bisect Bisect
|
Bisect Bisect
|
||||||
}
|
}
|
||||||
@ -947,6 +952,7 @@ func EnglishTranslationSet() TranslationSet {
|
|||||||
Continue: "Continue",
|
Continue: "Continue",
|
||||||
Keybindings: "Keybindings",
|
Keybindings: "Keybindings",
|
||||||
RebasingTitle: "Rebase '{{.checkedOutBranch}}' onto '{{.ref}}'",
|
RebasingTitle: "Rebase '{{.checkedOutBranch}}' onto '{{.ref}}'",
|
||||||
|
RebasingFromBaseCommitTitle: "Rebase '{{.checkedOutBranch}}' from marked base onto '{{.ref}}'",
|
||||||
SimpleRebase: "Simple rebase",
|
SimpleRebase: "Simple rebase",
|
||||||
InteractiveRebase: "Interactive rebase",
|
InteractiveRebase: "Interactive rebase",
|
||||||
InteractiveRebaseTooltip: "Begin an interactive rebase with a break at the start, so you can update the TODO commits before continuing",
|
InteractiveRebaseTooltip: "Begin an interactive rebase with a break at the start, so you can update the TODO commits before continuing",
|
||||||
@ -1315,6 +1321,10 @@ func EnglishTranslationSet() TranslationSet {
|
|||||||
Name: "Name",
|
Name: "Name",
|
||||||
Branch: "Branch",
|
Branch: "Branch",
|
||||||
Path: "Path",
|
Path: "Path",
|
||||||
|
MarkedBaseCommitStatus: "Marked a base commit for rebase",
|
||||||
|
MarkAsBaseCommit: "Mark commit as base commit for rebase",
|
||||||
|
MarkAsBaseCommitTooltip: "Select a base commit for the next rebase; this will effectively perform a 'git rebase --onto'.",
|
||||||
|
MarkedCommitMarker: "↑↑↑ Will rebase from here ↑↑↑",
|
||||||
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)
|
||||||
CheckoutCommit: "Checkout commit",
|
CheckoutCommit: "Checkout commit",
|
||||||
|
78
pkg/integration/tests/branch/rebase_from_marked_base.go
Normal file
78
pkg/integration/tests/branch/rebase_from_marked_base.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package branch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var RebaseFromMarkedBase = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Rebase onto another branch from a marked base commit",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.
|
||||||
|
NewBranch("base-branch").
|
||||||
|
EmptyCommit("one").
|
||||||
|
EmptyCommit("two").
|
||||||
|
EmptyCommit("three").
|
||||||
|
NewBranch("active-branch").
|
||||||
|
EmptyCommit("active one").
|
||||||
|
EmptyCommit("active two").
|
||||||
|
EmptyCommit("active three").
|
||||||
|
Checkout("base-branch").
|
||||||
|
NewBranch("target-branch").
|
||||||
|
EmptyCommit("target one").
|
||||||
|
EmptyCommit("target two").
|
||||||
|
Checkout("active-branch")
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
t.Views().Commits().
|
||||||
|
Focus().
|
||||||
|
Lines(
|
||||||
|
Contains("active three"),
|
||||||
|
Contains("active two"),
|
||||||
|
Contains("active one"),
|
||||||
|
Contains("three"),
|
||||||
|
Contains("two"),
|
||||||
|
Contains("one"),
|
||||||
|
).
|
||||||
|
NavigateToLine(Contains("active one")).
|
||||||
|
Press(keys.Commits.MarkCommitAsBaseForRebase).
|
||||||
|
Lines(
|
||||||
|
Contains("active three"),
|
||||||
|
Contains("active two"),
|
||||||
|
Contains("↑↑↑ Will rebase from here ↑↑↑ active one"),
|
||||||
|
Contains("three"),
|
||||||
|
Contains("two"),
|
||||||
|
Contains("one"),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Views().Information().Content(Contains("Marked a base commit for rebase"))
|
||||||
|
|
||||||
|
t.Views().Branches().
|
||||||
|
Focus().
|
||||||
|
Lines(
|
||||||
|
Contains("active-branch"),
|
||||||
|
Contains("target-branch"),
|
||||||
|
Contains("base-branch"),
|
||||||
|
).
|
||||||
|
SelectNextItem().
|
||||||
|
Press(keys.Branches.RebaseBranch)
|
||||||
|
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Equals("Rebase 'active-branch' from marked base onto 'target-branch'")).
|
||||||
|
Select(Contains("Simple rebase")).
|
||||||
|
Confirm()
|
||||||
|
|
||||||
|
t.Views().Commits().Lines(
|
||||||
|
Contains("active three"),
|
||||||
|
Contains("active two"),
|
||||||
|
Contains("target two"),
|
||||||
|
Contains("target one"),
|
||||||
|
Contains("three"),
|
||||||
|
Contains("two"),
|
||||||
|
Contains("one"),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
@ -44,6 +44,7 @@ var tests = []*components.IntegrationTest{
|
|||||||
branch.RebaseAndDrop,
|
branch.RebaseAndDrop,
|
||||||
branch.RebaseCancelOnConflict,
|
branch.RebaseCancelOnConflict,
|
||||||
branch.RebaseDoesNotAutosquash,
|
branch.RebaseDoesNotAutosquash,
|
||||||
|
branch.RebaseFromMarkedBase,
|
||||||
branch.Reset,
|
branch.Reset,
|
||||||
branch.ResetUpstream,
|
branch.ResetUpstream,
|
||||||
branch.SetUpstream,
|
branch.SetUpstream,
|
||||||
|
@ -36,6 +36,9 @@ var (
|
|||||||
// CherryPickedCommitColor is the text style when cherry picking a commit
|
// CherryPickedCommitColor is the text style when cherry picking a commit
|
||||||
CherryPickedCommitTextStyle = style.New()
|
CherryPickedCommitTextStyle = style.New()
|
||||||
|
|
||||||
|
// MarkedBaseCommitTextStyle is the text style of the marked rebase base commit
|
||||||
|
MarkedBaseCommitTextStyle = style.New()
|
||||||
|
|
||||||
OptionsFgColor = style.New()
|
OptionsFgColor = style.New()
|
||||||
|
|
||||||
DiffTerminalColor = style.FgMagenta
|
DiffTerminalColor = style.FgMagenta
|
||||||
@ -55,6 +58,10 @@ func UpdateTheme(themeConfig config.ThemeConfig) {
|
|||||||
cherryPickedCommitFgTextStyle := GetTextStyle(themeConfig.CherryPickedCommitFgColor, false)
|
cherryPickedCommitFgTextStyle := GetTextStyle(themeConfig.CherryPickedCommitFgColor, false)
|
||||||
CherryPickedCommitTextStyle = cherryPickedCommitBgTextStyle.MergeStyle(cherryPickedCommitFgTextStyle)
|
CherryPickedCommitTextStyle = cherryPickedCommitBgTextStyle.MergeStyle(cherryPickedCommitFgTextStyle)
|
||||||
|
|
||||||
|
markedBaseCommitBgTextStyle := GetTextStyle(themeConfig.MarkedBaseCommitBgColor, true)
|
||||||
|
markedBaseCommitFgTextStyle := GetTextStyle(themeConfig.MarkedBaseCommitFgColor, false)
|
||||||
|
MarkedBaseCommitTextStyle = markedBaseCommitBgTextStyle.MergeStyle(markedBaseCommitFgTextStyle)
|
||||||
|
|
||||||
unstagedChangesTextStyle := GetTextStyle(themeConfig.UnstagedChangesColor, false)
|
unstagedChangesTextStyle := GetTextStyle(themeConfig.UnstagedChangesColor, false)
|
||||||
UnstagedChangesColor = unstagedChangesTextStyle
|
UnstagedChangesColor = unstagedChangesTextStyle
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user