1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-02-07 13:42:01 +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:
Stefan Haller 2023-06-11 08:08:55 +02:00
parent 375451785c
commit 66de981e91
24 changed files with 237 additions and 10 deletions

View File

@ -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

View File

@ -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

View File

@ -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>: 커밋 되돌리기

View File

@ -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

View File

@ -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

View File

@ -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>: Отменить коммит

View File

@ -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>: 还原提交

View File

@ -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>: 還原提交

View File

@ -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()

View File

@ -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>",

View File

@ -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(),

View File

@ -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(),

View File

@ -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)
}

View File

@ -82,6 +82,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 {

View File

@ -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())
}

View File

@ -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

View 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
}

View File

@ -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

View File

@ -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,

View File

@ -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
}

View File

@ -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",

View 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"),
)
},
})

View File

@ -44,6 +44,7 @@ var tests = []*components.IntegrationTest{
branch.RebaseAndDrop,
branch.RebaseCancelOnConflict,
branch.RebaseDoesNotAutosquash,
branch.RebaseFromMarkedBase,
branch.Reset,
branch.ResetUpstream,
branch.SetUpstream,

View File

@ -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 = style.New()
DiffTerminalColor = style.FgMagenta
@ -55,6 +58,10 @@ func UpdateTheme(themeConfig config.ThemeConfig) {
cherryPickedCommitFgTextStyle := GetTextStyle(themeConfig.CherryPickedCommitFgColor, false)
CherryPickedCommitTextStyle = cherryPickedCommitBgTextStyle.MergeStyle(cherryPickedCommitFgTextStyle)
markedBaseCommitBgTextStyle := GetTextStyle(themeConfig.MarkedBaseCommitBgColor, true)
markedBaseCommitFgTextStyle := GetTextStyle(themeConfig.MarkedBaseCommitFgColor, false)
MarkedBaseCommitTextStyle = markedBaseCommitBgTextStyle.MergeStyle(markedBaseCommitFgTextStyle)
unstagedChangesTextStyle := GetTextStyle(themeConfig.UnstagedChangesColor, false)
UnstagedChangesColor = unstagedChangesTextStyle