summaryrefslogtreecommitdiffstats
path: root/pkg/gui
diff options
context:
space:
mode:
authorStefan Haller <stefan@haller-berlin.de>2023-06-11 08:08:55 +0200
committerStefan Haller <stefan@haller-berlin.de>2023-07-31 08:41:41 +0200
commit66de981e9108c83ddb1d778eb92e948050c85311 (patch)
treefcc5c35ee5909cd71157c331ef10beb200fe05ee /pkg/gui
parent375451785c2f72da368e0cafaff9dc2e9f40a5b4 (diff)
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.
Diffstat (limited to 'pkg/gui')
-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.go16
-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
10 files changed, 109 insertions, 10 deletions
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 a8df8811c..49f664a29 100644
--- a/pkg/gui/controllers/local_commits_controller.go
+++ b/pkg/gui/controllers/local_commits_controller.go
@@ -103,6 +103,12 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
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
}