summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Haller <stefan@haller-berlin.de>2023-07-31 08:52:58 +0200
committerGitHub <noreply@github.com>2023-07-31 08:52:58 +0200
commit71d2fd37e2ff8214d5af3135ab3a355971789dc2 (patch)
treefcc5c35ee5909cd71157c331ef10beb200fe05ee
parenta6af31a4cb294e87e9b16ac077411d7a6531071b (diff)
parent66de981e9108c83ddb1d778eb92e948050c85311 (diff)
Rebase onto branch from a marked base commit (#2835)
-rw-r--r--docs/keybindings/Keybindings_en.md1
-rw-r--r--docs/keybindings/Keybindings_ja.md1
-rw-r--r--docs/keybindings/Keybindings_ko.md1
-rw-r--r--docs/keybindings/Keybindings_nl.md1
-rw-r--r--docs/keybindings/Keybindings_pl.md1
-rw-r--r--docs/keybindings/Keybindings_ru.md1
-rw-r--r--docs/keybindings/Keybindings_zh-CN.md1
-rw-r--r--docs/keybindings/Keybindings_zh-TW.md1
-rw-r--r--pkg/commands/git_commands/rebase.go18
-rw-r--r--pkg/config/user_config.go6
-rw-r--r--pkg/gui/context/local_commits_context.go1
-rw-r--r--pkg/gui/context/sub_commits_context.go1
-rw-r--r--pkg/gui/controllers/helpers/merge_and_rebase_helper.go32
-rw-r--r--pkg/gui/controllers/helpers/mode_helper.go10
-rw-r--r--pkg/gui/controllers/local_commits_controller.go18
-rw-r--r--pkg/gui/gui.go8
-rw-r--r--pkg/gui/modes/marked_base_commit/marked_base_commit.go25
-rw-r--r--pkg/gui/presentation/commits.go16
-rw-r--r--pkg/gui/presentation/commits_test.go2
-rw-r--r--pkg/gui/types/modes.go8
-rw-r--r--pkg/i18n/english.go10
-rw-r--r--pkg/integration/tests/branch/rebase_from_marked_base.go78
-rw-r--r--pkg/integration/tests/test_list.go1
-rw-r--r--pkg/theme/theme.go7
24 files changed, 238 insertions, 11 deletions
diff --git a/docs/keybindings/Keybindings_en.md b/docs/keybindings/Keybindings_en.md
index 3357d3619..a0e811f66 100644
--- a/docs/keybindings/Keybindings_en.md
+++ b/docs/keybindings/Keybindings_en.md
@@ -84,6 +84,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
<kbd>&lt;c-j&gt;</kbd>: Move commit down one
<kbd>&lt;c-k&gt;</kbd>: Move commit up one
<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>: Set/Reset commit author
<kbd>t</kbd>: Revert commit
diff --git a/docs/keybindings/Keybindings_ja.md b/docs/keybindings/Keybindings_ja.md
index 1adf2de3a..d34463b81 100644
--- a/docs/keybindings/Keybindings_ja.md
+++ b/docs/keybindings/Keybindings_ja.md
@@ -103,6 +103,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
<kbd>&lt;c-j&gt;</kbd>: コミットを1つ下に移動
<kbd>&lt;c-k&gt;</kbd>: コミットを1つ上に移動
<kbd>v</kbd>: コミットを貼り付け (cherry-pick)
+ <kbd>B</kbd>: Mark commit as base commit for rebase
<kbd>A</kbd>: ステージされた変更でamendコミット
<kbd>a</kbd>: Set/Reset commit author
<kbd>t</kbd>: コミットをrevert
diff --git a/docs/keybindings/Keybindings_ko.md b/docs/keybindings/Keybindings_ko.md
index 837043947..5446c24aa 100644
--- a/docs/keybindings/Keybindings_ko.md
+++ b/docs/keybindings/Keybindings_ko.md
@@ -265,6 +265,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
<kbd>&lt;c-j&gt;</kbd>: 커밋을 1개 아래로 이동
<kbd>&lt;c-k&gt;</kbd>: 커밋을 1개 위로 이동
<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>: Set/Reset commit author
<kbd>t</kbd>: 커밋 되돌리기
diff --git a/docs/keybindings/Keybindings_nl.md b/docs/keybindings/Keybindings_nl.md
index 13010a4d1..1593fc56d 100644
--- a/docs/keybindings/Keybindings_nl.md
+++ b/docs/keybindings/Keybindings_nl.md
@@ -143,6 +143,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
<kbd>&lt;c-j&gt;</kbd>: Verplaats commit 1 naar beneden
<kbd>&lt;c-k&gt;</kbd>: Verplaats commit 1 naar boven
<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>: Set/Reset commit author
<kbd>t</kbd>: Commit ongedaan maken
diff --git a/docs/keybindings/Keybindings_pl.md b/docs/keybindings/Keybindings_pl.md
index 9876d26a7..01a7a621c 100644
--- a/docs/keybindings/Keybindings_pl.md
+++ b/docs/keybindings/Keybindings_pl.md
@@ -69,6 +69,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
<kbd>&lt;c-j&gt;</kbd>: Przenieś commit 1 w dół
<kbd>&lt;c-k&gt;</kbd>: Przenieś commit 1 w górę
<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>: Set/Reset commit author
<kbd>t</kbd>: Odwróć commit
diff --git a/docs/keybindings/Keybindings_ru.md b/docs/keybindings/Keybindings_ru.md
index fa59d9949..6ae627bc9 100644
--- a/docs/keybindings/Keybindings_ru.md
+++ b/docs/keybindings/Keybindings_ru.md
@@ -151,6 +151,7 @@ _Связки клавиш_
<kbd>&lt;c-j&gt;</kbd>: Переместить коммит вниз на один
<kbd>&lt;c-k&gt;</kbd>: Переместить коммит вверх на один
<kbd>v</kbd>: Вставить отобранные коммиты (cherry-pick)
+ <kbd>B</kbd>: Mark commit as base commit for rebase
<kbd>A</kbd>: Править последний коммит с проиндексированными изменениями
<kbd>a</kbd>: Установить/убрать автора коммита
<kbd>t</kbd>: Отменить коммит
diff --git a/docs/keybindings/Keybindings_zh-CN.md b/docs/keybindings/Keybindings_zh-CN.md
index 1fcfe987f..924607639 100644
--- a/docs/keybindings/Keybindings_zh-CN.md
+++ b/docs/keybindings/Keybindings_zh-CN.md
@@ -147,6 +147,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
<kbd>&lt;c-j&gt;</kbd>: 下移提交
<kbd>&lt;c-k&gt;</kbd>: 上移提交
<kbd>v</kbd>: 粘贴提交(拣选)
+ <kbd>B</kbd>: Mark commit as base commit for rebase
<kbd>A</kbd>: 用已暂存的更改来修补提交
<kbd>a</kbd>: Set/Reset commit author
<kbd>t</kbd>: 还原提交
diff --git a/docs/keybindings/Keybindings_zh-TW.md b/docs/keybindings/Keybindings_zh-TW.md
index 960eee73a..4103a88ec 100644
--- a/docs/keybindings/Keybindings_zh-TW.md
+++ b/docs/keybindings/Keybindings_zh-TW.md
@@ -191,6 +191,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
<kbd>&lt;c-j&gt;</kbd>: 向下移動提交
<kbd>&lt;c-k&gt;</kbd>: 向上移動提交
<kbd>v</kbd>: 貼上提交 (揀選)
+ <kbd>B</kbd>: Mark commit as base commit for rebase
<kbd>A</kbd>: 使用已預存的更改修正提交
<kbd>a</kbd>: 設置/重設提交作者
<kbd>t</kbd>: 還原提交
diff --git a/pkg/commands/git_commands/rebase.go b/pkg/commands/git_commands/rebase.go
index 83c3fbe09..d491b6f5e 100644
--- a/pkg/commands/git_commands/rebase.go
+++ b/pkg/commands/git_commands/rebase.go
@@ -156,6 +156,15 @@ func (self *RebaseCommands) EditRebase(branchRef string) error {
}).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 {
changeTodoStr := strings.Join(lo.Map(changes, func(c daemon.ChangeTodoAction, _ int) string {
return fmt.Sprintf("%s:%s", c.Sha, c.NewAction)
@@ -165,6 +174,7 @@ func logTodoChanges(changes []daemon.ChangeTodoAction) string {
type PrepareInteractiveRebaseCommandOpts struct {
baseShaOrRoot string
+ onto string
instruction daemon.Instruction
overrideEditor bool
keepCommitsThatBecomeEmpty bool
@@ -183,6 +193,7 @@ func (self *RebaseCommands) PrepareInteractiveRebaseCommand(opts PrepareInteract
ArgIf(opts.keepCommitsThatBecomeEmpty && !self.version.IsOlderThan(2, 26, 0), "--empty=keep").
Arg("--no-autosquash").
ArgIf(!self.version.IsOlderThan(2, 22, 0), "--rebase-merges").
+ ArgIf(opts.onto != "", "--onto", opts.onto).
Arg(opts.baseShaOrRoot).
ToArgv()
@@ -306,6 +317,13 @@ func (self *RebaseCommands) RebaseBranch(branchName string) error {
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 {
cmdArgs := NewGitCmd(commandType).Arg("--" + command).ToArgv()
diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go
index a5121f0c5..0426086fc 100644
--- a/pkg/config/user_config.go
+++ b/pkg/config/user_config.go
@@ -67,6 +67,8 @@ type ThemeConfig struct {
SelectedRangeBgColor []string `yaml:"selectedRangeBgColor"`
CherryPickedCommitBgColor []string `yaml:"cherryPickedCommitBgColor"`
CherryPickedCommitFgColor []string `yaml:"cherryPickedCommitFgColor"`
+ MarkedBaseCommitBgColor []string `yaml:"markedBaseCommitBgColor"`
+ MarkedBaseCommitFgColor []string `yaml:"markedBaseCommitFgColor"`
UnstagedChangesColor []string `yaml:"unstagedChangesColor"`
DefaultFgColor []string `yaml:"defaultFgColor"`
}
@@ -267,6 +269,7 @@ type KeybindingCommitsConfig struct {
CherryPickCopy string `yaml:"cherryPickCopy"`
CherryPickCopyRange string `yaml:"cherryPickCopyRange"`
PasteCommits string `yaml:"pasteCommits"`
+ MarkCommitAsBaseForRebase string `yaml:"markCommitAsBaseForRebase"`
CreateTag string `yaml:"tagCommit"`
CheckoutCommit string `yaml:"checkoutCommit"`
ResetCherryPick string `yaml:"resetCherryPick"`
@@ -432,6 +435,8 @@ func GetDefaultConfig() *UserConfig {
SelectedRangeBgColor: []string{"blue"},
CherryPickedCommitBgColor: []string{"cyan"},
CherryPickedCommitFgColor: []string{"blue"},
+ MarkedBaseCommitBgColor: []string{"yellow"},
+ MarkedBaseCommitFgColor: []string{"blue"},
UnstagedChangesColor: []string{"red"},
DefaultFgColor: []string{"default"},
},
@@ -613,6 +618,7 @@ func GetDefaultConfig() *UserConfig {
CherryPickCopy: "c",
CherryPickCopyRange: "C",
PasteCommits: "v",
+ MarkCommitAsBaseForRebase: "B",
CreateTag: "T",
CheckoutCommit: "<space>",
ResetCherryPick: "<c-R>",
diff --git a/pkg/gui/context/local_commits_context.go b/pkg/gui/context/local_commits_context.go
index 417a4f30a..f8f7848f2 100644
--- a/pkg/gui/context/local_commits_context.go
+++ b/pkg/gui/context/local_commits_context.go
@@ -49,6 +49,7 @@ func NewLocalCommitsContext(c *ContextCommon) *LocalCommitsContext {
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
c.Modes().CherryPicking.SelectedShaSet(),
c.Modes().Diffing.Ref,
+ c.Modes().MarkedBaseCommit.GetSha(),
c.UserConfig.Gui.TimeFormat,
c.UserConfig.Gui.ShortTimeFormat,
time.Now(),
diff --git a/pkg/gui/context/sub_commits_context.go b/pkg/gui/context/sub_commits_context.go
index ba2f5e3f6..2643d294b 100644
--- a/pkg/gui/context/sub_commits_context.go
+++ b/pkg/gui/context/sub_commits_context.go
@@ -65,6 +65,7 @@ func NewSubCommitsContext(
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
c.Modes().CherryPicking.SelectedShaSet(),
c.Modes().Diffing.Ref,
+ "",
c.UserConfig.Gui.TimeFormat,
c.UserConfig.Gui.ShortTimeFormat,
time.Now(),
diff --git a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go
index e9140e102..03c3abb4b 100644
--- a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go
+++ b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go
@@ -224,8 +224,18 @@ func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error {
Key: 's',
OnPress: func() error {
self.c.LogAction(self.c.Tr.Actions.RebaseBranch)
- err := self.c.Git().Rebase.RebaseBranch(ref)
- return self.CheckMergeOrRebase(err)
+ baseCommit := self.c.Modes().MarkedBaseCommit.GetSha()
+ 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,
OnPress: func() error {
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 {
return err
}
+ self.c.Modes().MarkedBaseCommit.Reset()
return self.c.PushContext(self.c.Contexts().LocalCommits)
},
},
}
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{
"checkedOutBranch": checkedOutBranch,
"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)
+}
diff --git a/pkg/gui/controllers/helpers/mode_helper.go b/pkg/gui/controllers/helpers/mode_helper.go
index f5f3c738c..b3d9549a4 100644
--- a/pkg/gui/controllers/helpers/mode_helper.go
+++ b/pkg/gui/controllers/helpers/mode_helper.go
@@ -83,6 +83,16 @@ func (self *ModeHelper) Statuses() []ModeStatus {
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,
Description: func() string {
copiedCount := len(self.c.Modes().CherryPicking.CherryPickedCommits)
diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go
index 5d796fca8..49f664a29 100644
--- a/pkg/gui/controllers/local_commits_controller.go
+++ b/pkg/gui/controllers/local_commits_controller.go
@@ -100,9 +100,15 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
},
{
Key: opts.GetKey(opts.Config.Commits.PasteCommits),
- Handler: opts.Guards.OutsideFilterMode(self.paste),
+ Handler: self.paste,
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
// more commits on demand
{
@@ -840,6 +846,16 @@ func (self *LocalCommitsController) paste() error {
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 {
return models.IsHeadCommit(self.c.Model().Commits, self.context().GetSelectedLineIdx())
}
diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go
index 8db98238c..4da5d5e96 100644
--- a/pkg/gui/gui.go
+++ b/pkg/gui/gui.go
@@ -24,6 +24,7 @@ import (
"github.com/jesseduffield/lazygit/pkg/gui/modes/cherrypicking"
"github.com/jesseduffield/lazygit/pkg/gui/modes/diffing"
"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/presentation"
"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{},
},
Modes: &types.Modes{
- Filtering: filtering.New(startArgs.FilterPath),
- CherryPicking: cherrypicking.New(),
- Diffing: diffing.New(),
+ Filtering: filtering.New(startArgs.FilterPath),
+ CherryPicking: cherrypicking.New(),
+ Diffing: diffing.New(),
+ MarkedBaseCommit: marked_base_commit.New(),
},
ScreenMode: initialScreenMode,
// TODO: only use contexts from context manager
diff --git a/pkg/gui/modes/marked_base_commit/marked_base_commit.go b/pkg/gui/modes/marked_base_commit/marked_base_commit.go
new file mode 100644
index 000000000..516dd0f2f
--- /dev/null
+++ b/pkg/gui/modes/marked_base_commit/marked_base_commit.go
@@ -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
+}
diff --git a/pkg/gui/presentation/commits.go b/pkg/gui/presentation/commits.go
index c00564e9d..f5915a7ee 100644
--- a/pkg/gui/presentation/commits.go
+++ b/pkg/gui/presentation/commits.go
@@ -45,6 +45,7 @@ func GetCommitListDisplayStrings(
fullDescription bool,
cherryPickedCommitShaSet *set.Set[string],
diffName string,
+ markedBaseCommit string,
timeFormat string,
shortTimeFormat string,
now time.Time,
@@ -128,6 +129,7 @@ func GetCommitListDisplayStrings(
lines := make([][]string, 0, len(filteredCommits))
var bisectStatus BisectStatus
+ willBeRebased := markedBaseCommit == ""
for i, commit := range filteredCommits {
unfilteredIdx := i + startIdx
bisectStatus = getBisectStatus(unfilteredIdx, commit.Sha, bisectInfo, bisectBounds)
@@ -136,11 +138,17 @@ func GetCommitListDisplayStrings(
isYouAreHereCommit = true
showYouAreHereLabel = false
}
+ isMarkedBaseCommit := commit.Sha != "" && commit.Sha == markedBaseCommit
+ if isMarkedBaseCommit {
+ willBeRebased = true
+ }
lines = append(lines, displayCommit(
common,
commit,
branchHeadsToVisualize,
cherryPickedCommitShaSet,
+ isMarkedBaseCommit,
+ willBeRebased,
diffName,
timeFormat,
shortTimeFormat,
@@ -290,6 +298,8 @@ func displayCommit(
commit *models.Commit,
branchHeadsToVisualize *set.Set[string],
cherryPickedCommitShaSet *set.Set[string],
+ isMarkedBaseCommit bool,
+ willBeRebased bool,
diffName string,
timeFormat string,
shortTimeFormat string,
@@ -335,6 +345,12 @@ func displayCommit(
color := lo.Ternary(commit.Action == models.ActionConflict, style.FgRed, style.FgYellow)
youAreHere := color.Sprintf("<-- %s ---", common.Tr.YouAreHere)
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
diff --git a/pkg/gui/presentation/commits_test.go b/pkg/gui/presentation/commits_test.go
index 4bf4c09af..65122961e 100644
--- a/pkg/gui/presentation/commits_test.go
+++ b/pkg/gui/presentation/commits_test.go
@@ -33,6 +33,7 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
hasUpdateRefConfig bool
fullDescription bool
cherryPickedCommitShaSet *set.Set[string]
+ markedBaseCommit string
diffName string
timeFormat string
shortTimeFormat string
@@ -408,6 +409,7 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
s.fullDescription,
s.cherryPickedCommitShaSet,
s.diffName,
+ s.markedBaseCommit,
s.timeFormat,
s.shortTimeFormat,
s.now,
diff --git a/pkg/gui/types/modes.go b/pkg/gui/types/modes.go
index ba135de63..a11ed0081 100644
--- a/pkg/gui/types/modes.go
+++ b/pkg/gui/types/modes.go
@@ -4,10 +4,12 @@ import (
"github.com/jesseduffield/lazygit/pkg/gui/modes/cherrypicking"
"github.com/jesseduffield/lazygit/pkg/gui/modes/diffing"
"github.com/jesseduffield/lazygit/pkg/gui/modes/filtering"
+ "github.com/jesseduffield/lazygit/pkg/gui/modes/marked_base_commit"
)
type Modes struct {
- Filtering filtering.Filtering
- CherryPicking *cherrypicking.CherryPicking
- Diffing diffing.Diffing
+ Filtering filtering.Filtering
+ CherryPicking *cherrypicking.CherryPicking
+ Diffing diffing.Diffing
+ MarkedBaseCommit marked_base_commit.MarkedBaseCommit
}
diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go
index ecfa6a2ae..5aa6bd3c9 100644
--- a/pkg/i18n/english.go
+++ b/pkg/i18n/english.go
@@ -209,6 +209,7 @@ type TranslationSet struct {
ConflictsResolved string
Continue string
RebasingTitle string
+ RebasingFromBaseCommitTitle string
SimpleRebase string
InteractiveRebase string
InteractiveRebaseTooltip string
@@ -578,6 +579,10 @@ type TranslationSet struct {
Name string
Branch string
Path string
+ MarkedBaseCommitStatus string
+ MarkAsBaseCommit string
+ MarkAsBaseCommitTooltip string
+ MarkedCommitMarker string
Actions Actions
Bisect Bisect
}
@@ -947,6 +952,7 @@ func EnglishTranslationSet() TranslationSet {
Continue: "Continue",
Keybindings: "Keybindings",
RebasingTitle: "Rebase '{{.checkedOutBranch}}' onto '{{.ref}}'",
+ RebasingFromBaseCommitTitle: "Rebase '{{.checkedOutBranch}}' from marked base onto '{{.ref}}'",
SimpleRebase: "Simple rebase",
InteractiveRebase: "Interactive rebase",
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",
Branch: "Branch",
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{
// TODO: combine this with the original keybinding descriptions (those are all in lowercase atm)
CheckoutCommit: "Checkout commit",
diff --git a/pkg/integration/tests/branch/rebase_from_marked_base.go b/pkg/integration/tests/branch/rebase_from_marked_base.go
new file mode 100644
index 000000000..fb6ede722
--- /dev/null
+++ b/pkg/integration/tests/branch/rebase_from_marked_base.go
@@ -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"),
+ )
+ },
+})
diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go
index 9dcb57dee..dfcd6c0ea 100644
--- a/pkg/integration/tests/test_list.go
+++ b/pkg/integration/tests/test_list.go
@@ -44,6 +44,7 @@ var tests = []*components.IntegrationTest{
branch.RebaseAndDrop,
branch.RebaseCancelOnConflict,
branch.RebaseDoesNotAutosquash,
+ branch.RebaseFromMarkedBase,
branch.Reset,
branch.ResetUpstream,
branch.SetUpstream,
diff --git a/pkg/theme/theme.go b/pkg/theme/theme.go
index 0a1624029..20832f6d3 100644
--- a/pkg/theme/theme.go
+++ b/pkg/theme/theme.go
@@ -36,6 +36,9 @@ var (
// CherryPickedCommitColor is the text style when cherry picking a commit
CherryPickedCommitTextStyle = style.New()
+ // MarkedBaseCommitTextStyle is the text style of the marked rebase base commit
+ MarkedBaseCommitTextStyle = style.New()
+
OptionsFgColor