1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-03-31 22:22:14 +02:00

Visualize local branch heads in commits panel, 2nd approach (#2775)

This commit is contained in:
Stefan Haller 2023-07-31 08:40:09 +02:00 committed by GitHub
commit a6af31a4cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 444 additions and 144 deletions

View File

@ -62,7 +62,6 @@ gui:
showListFooter: true # for seeing the '5 of 20' message in list panels
showRandomTip: true
showBranchCommitHash: false # show commit hashes alongside branch names
experimentalShowBranchHeads: false # visualize branch heads with (*) in commits list
showBottomLine: true # for hiding the bottom information line (unless it has important information to tell you)
showCommandLog: true
showIcons: false # deprecated: use nerdFontsVersion instead

View File

@ -6,4 +6,5 @@
* [Keybindings](./keybindings)
* [Undo/Redo](./Undoing.md)
* [Searching/Filtering](./Searching.md)
* [Stacked Branches](./Stacked_Branches.md)
* [Dev docs](./dev)

18
docs/Stacked_Branches.md Normal file
View File

@ -0,0 +1,18 @@
# Working with stacked branches
When working on a large branch it can often be useful to break it down into
smaller pieces, and it can help to create separate branches for each independent
chunk of changes. For example, you could have one branch for preparatory
refactorings, one for backend changes, and one for frontend changes. Those
branches would then all be stacked onto each other.
Git has support for rebasing such a stack as a whole; you can enable it by
setting the git config `rebase.updateRfs` to true. If you then rebase the
topmost branch of the stack, the other ones in the stack will follow. This
includes interactive rebases, so for example amending a commit in the first
branch of the stack will "just work" in the sense that it keeps the other
branches properly stacked onto it.
Lazygit visualizes the invidual branch heads in the stack by marking them with a
cyan asterisk (or a cyan branch symbol if you are using [nerd
fonts](Config.md#display-nerd-fonts-icons)).

View File

@ -70,6 +70,21 @@ func (self *BranchCommands) CurrentBranchInfo() (BranchInfo, error) {
}, nil
}
// CurrentBranchName get name of current branch
func (self *BranchCommands) CurrentBranchName() (string, error) {
cmdArgs := NewGitCmd("rev-parse").
Arg("--abbrev-ref").
Arg("--verify").
Arg("HEAD").
ToArgv()
output, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
if err == nil {
return strings.TrimSpace(output), nil
}
return "", err
}
// Delete delete branch
func (self *BranchCommands) Delete(branch string, force bool) error {
cmdArgs := NewGitCmd("branch").

View File

@ -171,7 +171,7 @@ var branchFields = []string{
"upstream:short",
"upstream:track",
"subject",
fmt.Sprintf("objectname:short=%d", utils.COMMIT_HASH_SHORT_SIZE),
"objectname",
}
// Obtain branch information from parsed line output of getRawBranches()

View File

@ -107,3 +107,7 @@ func (self *ConfigCommands) GetCoreCommentChar() byte {
return '#'
}
func (self *ConfigCommands) GetRebaseUpdateRefs() bool {
return self.gitConfig.GetBool("rebase.updateRefs")
}

View File

@ -1,6 +1,7 @@
package git_commands
import (
"os"
"path/filepath"
"strconv"
"strings"
@ -71,3 +72,14 @@ func IsBareRepo(osCommand *oscommands.OSCommand) (bool, error) {
func (self *StatusCommands) IsInMergeState() (bool, error) {
return self.os.FileExists(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "MERGE_HEAD"))
}
// Full ref (e.g. "refs/heads/mybranch") of the branch that is currently
// being rebased, or empty string when we're not in a rebase
func (self *StatusCommands) BranchBeingRebased() string {
for _, dir := range []string{"rebase-merge", "rebase-apply"} {
if bytesContent, err := os.ReadFile(filepath.Join(self.repoPaths.WorktreeGitDirPath(), dir, "head-name")); err == nil {
return strings.TrimSpace(string(bytesContent))
}
}
return ""
}

View File

@ -27,36 +27,35 @@ type RefresherConfig struct {
}
type GuiConfig struct {
AuthorColors map[string]string `yaml:"authorColors"`
BranchColors map[string]string `yaml:"branchColors"`
ScrollHeight int `yaml:"scrollHeight"`
ScrollPastBottom bool `yaml:"scrollPastBottom"`
MouseEvents bool `yaml:"mouseEvents"`
SkipDiscardChangeWarning bool `yaml:"skipDiscardChangeWarning"`
SkipStashWarning bool `yaml:"skipStashWarning"`
SidePanelWidth float64 `yaml:"sidePanelWidth"`
ExpandFocusedSidePanel bool `yaml:"expandFocusedSidePanel"`
MainPanelSplitMode string `yaml:"mainPanelSplitMode"`
Language string `yaml:"language"`
TimeFormat string `yaml:"timeFormat"`
ShortTimeFormat string `yaml:"shortTimeFormat"`
Theme ThemeConfig `yaml:"theme"`
CommitLength CommitLengthConfig `yaml:"commitLength"`
SkipNoStagedFilesWarning bool `yaml:"skipNoStagedFilesWarning"`
ShowListFooter bool `yaml:"showListFooter"`
ShowFileTree bool `yaml:"showFileTree"`
ShowRandomTip bool `yaml:"showRandomTip"`
ShowCommandLog bool `yaml:"showCommandLog"`
ShowBottomLine bool `yaml:"showBottomLine"`
ShowIcons bool `yaml:"showIcons"`
NerdFontsVersion string `yaml:"nerdFontsVersion"`
ShowBranchCommitHash bool `yaml:"showBranchCommitHash"`
ExperimentalShowBranchHeads bool `yaml:"experimentalShowBranchHeads"`
CommandLogSize int `yaml:"commandLogSize"`
SplitDiff string `yaml:"splitDiff"`
SkipRewordInEditorWarning bool `yaml:"skipRewordInEditorWarning"`
WindowSize string `yaml:"windowSize"`
Border string `yaml:"border"`
AuthorColors map[string]string `yaml:"authorColors"`
BranchColors map[string]string `yaml:"branchColors"`
ScrollHeight int `yaml:"scrollHeight"`
ScrollPastBottom bool `yaml:"scrollPastBottom"`
MouseEvents bool `yaml:"mouseEvents"`
SkipDiscardChangeWarning bool `yaml:"skipDiscardChangeWarning"`
SkipStashWarning bool `yaml:"skipStashWarning"`
SidePanelWidth float64 `yaml:"sidePanelWidth"`
ExpandFocusedSidePanel bool `yaml:"expandFocusedSidePanel"`
MainPanelSplitMode string `yaml:"mainPanelSplitMode"`
Language string `yaml:"language"`
TimeFormat string `yaml:"timeFormat"`
ShortTimeFormat string `yaml:"shortTimeFormat"`
Theme ThemeConfig `yaml:"theme"`
CommitLength CommitLengthConfig `yaml:"commitLength"`
SkipNoStagedFilesWarning bool `yaml:"skipNoStagedFilesWarning"`
ShowListFooter bool `yaml:"showListFooter"`
ShowFileTree bool `yaml:"showFileTree"`
ShowRandomTip bool `yaml:"showRandomTip"`
ShowCommandLog bool `yaml:"showCommandLog"`
ShowBottomLine bool `yaml:"showBottomLine"`
ShowIcons bool `yaml:"showIcons"`
NerdFontsVersion string `yaml:"nerdFontsVersion"`
ShowBranchCommitHash bool `yaml:"showBranchCommitHash"`
CommandLogSize int `yaml:"commandLogSize"`
SplitDiff string `yaml:"splitDiff"`
SkipRewordInEditorWarning bool `yaml:"skipRewordInEditorWarning"`
WindowSize string `yaml:"windowSize"`
Border string `yaml:"border"`
}
type ThemeConfig struct {
@ -436,21 +435,20 @@ func GetDefaultConfig() *UserConfig {
UnstagedChangesColor: []string{"red"},
DefaultFgColor: []string{"default"},
},
CommitLength: CommitLengthConfig{Show: true},
SkipNoStagedFilesWarning: false,
ShowListFooter: true,
ShowCommandLog: true,
ShowBottomLine: true,
ShowFileTree: true,
ShowRandomTip: true,
ShowIcons: false,
NerdFontsVersion: "",
ExperimentalShowBranchHeads: false,
ShowBranchCommitHash: false,
CommandLogSize: 8,
SplitDiff: "auto",
SkipRewordInEditorWarning: false,
Border: "single",
CommitLength: CommitLengthConfig{Show: true},
SkipNoStagedFilesWarning: false,
ShowListFooter: true,
ShowCommandLog: true,
ShowBottomLine: true,
ShowFileTree: true,
ShowRandomTip: true,
ShowIcons: false,
NerdFontsVersion: "",
ShowBranchCommitHash: false,
CommandLogSize: 8,
SplitDiff: "auto",
SkipRewordInEditorWarning: false,
Border: "single",
},
Git: GitConfig{
Paging: PagingConfig{

View File

@ -83,3 +83,7 @@ func (self *BranchesContext) GetDiffTerminals() []string {
}
return nil
}
func (self *BranchesContext) ShowBranchHeadsInSubCommits() bool {
return true
}

View File

@ -38,10 +38,14 @@ func NewLocalCommitsContext(c *ContextCommon) *LocalCommitsContext {
}
showYouAreHereLabel := c.Model().WorkingTreeStateAtLastCommitRefresh == enums.REBASE_MODE_REBASING
showBranchMarkerForHeadCommit := c.Git().Config.GetRebaseUpdateRefs()
return presentation.GetCommitListDisplayStrings(
c.Common,
c.Model().Commits,
c.Model().Branches,
c.Model().CheckedOutBranch,
showBranchMarkerForHeadCommit,
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
c.Modes().CherryPicking.SelectedShaSet(),
c.Modes().Diffing.Ref,

View File

@ -86,3 +86,7 @@ func (self *ReflogCommitsContext) GetDiffTerminals() []string {
return []string{itemId}
}
func (self *ReflogCommitsContext) ShowBranchHeadsInSubCommits() bool {
return false
}

View File

@ -72,3 +72,7 @@ func (self *RemoteBranchesContext) GetDiffTerminals() []string {
return []string{itemId}
}
func (self *RemoteBranchesContext) ShowBranchHeadsInSubCommits() bool {
return true
}

View File

@ -37,6 +37,13 @@ func NewSubCommitsContext(
}
getDisplayStrings := func(startIdx int, length int) [][]string {
// This can happen if a sub-commits view is asked to be rerendered while
// it is invisble; for example when switching screen modes, which
// rerenders all views.
if viewModel.GetRef() == nil {
return [][]string{}
}
selectedCommitSha := ""
if c.CurrentContext().GetKey() == SUB_COMMITS_CONTEXT_KEY {
selectedCommit := viewModel.GetSelected()
@ -44,9 +51,17 @@ func NewSubCommitsContext(
selectedCommitSha = selectedCommit.Sha
}
}
branches := []*models.Branch{}
if viewModel.GetShowBranchHeads() {
branches = c.Model().Branches
}
showBranchMarkerForHeadCommit := c.Git().Config.GetRebaseUpdateRefs()
return presentation.GetCommitListDisplayStrings(
c.Common,
c.Model().SubCommits,
branches,
viewModel.GetRef().RefName(),
showBranchMarkerForHeadCommit,
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
c.Modes().CherryPicking.SelectedShaSet(),
c.Modes().Diffing.Ref,
@ -97,7 +112,8 @@ type SubCommitsViewModel struct {
ref types.Ref
*ListViewModel[*models.Commit]
limitCommits bool
limitCommits bool
showBranchHeads bool
}
func (self *SubCommitsViewModel) SetRef(ref types.Ref) {
@ -108,6 +124,14 @@ func (self *SubCommitsViewModel) GetRef() types.Ref {
return self.ref
}
func (self *SubCommitsViewModel) SetShowBranchHeads(value bool) {
self.showBranchHeads = value
}
func (self *SubCommitsViewModel) GetShowBranchHeads() bool {
return self.showBranchHeads
}
func (self *SubCommitsContext) GetSelectedItemId() string {
item := self.GetSelected()
if item == nil {

View File

@ -69,3 +69,7 @@ func (self *TagsContext) GetDiffTerminals() []string {
return []string{itemId}
}
func (self *TagsContext) ShowBranchHeadsInSubCommits() bool {
return true
}

View File

@ -272,6 +272,32 @@ func (self *RefreshHelper) refreshCommitsAndCommitFiles() {
}
}
func (self *RefreshHelper) determineCheckedOutBranchName() string {
if rebasedBranch := self.c.Git().Status.BranchBeingRebased(); rebasedBranch != "" {
// During a rebase we're on a detached head, so cannot determine the
// branch name in the usual way. We need to read it from the
// ".git/rebase-merge/head-name" file instead.
return strings.TrimPrefix(rebasedBranch, "refs/heads/")
}
if bisectInfo := self.c.Git().Bisect.GetInfo(); bisectInfo.Bisecting() && bisectInfo.GetStartSha() != "" {
// Likewise, when we're bisecting we're on a detached head as well. In
// this case we read the branch name from the ".git/BISECT_START" file.
return bisectInfo.GetStartSha()
}
// In all other cases, get the branch name by asking git what branch is
// checked out. Note that if we're on a detached head (for reasons other
// than rebasing or bisecting, i.e. it was explicitly checked out), then
// this will return its sha.
if branchName, err := self.c.Git().Branch.CurrentBranchName(); err == nil {
return branchName
}
// Should never get here unless the working copy is corrupt
return ""
}
func (self *RefreshHelper) refreshCommitsWithLimit() error {
self.c.Mutexes().LocalCommitsMutex.Lock()
defer self.c.Mutexes().LocalCommitsMutex.Unlock()
@ -291,6 +317,7 @@ func (self *RefreshHelper) refreshCommitsWithLimit() error {
self.c.Model().Commits = commits
self.RefreshAuthors(commits)
self.c.Model().WorkingTreeStateAtLastCommitRefresh = self.c.Git().Status.WorkingTreeState()
self.c.Model().CheckedOutBranch = self.determineCheckedOutBranchName()
return self.c.PostRefreshUpdate(self.c.Contexts().LocalCommits)
}
@ -412,6 +439,12 @@ func (self *RefreshHelper) refreshBranches() {
self.c.Log.Error(err)
}
// Need to re-render the commits view because the visualization of local
// branch heads might have changed
if err := self.c.Contexts().LocalCommits.HandleRender(); err != nil {
self.c.Log.Error(err)
}
self.refreshStatus()
}

View File

@ -11,6 +11,7 @@ var _ types.IController = &SwitchToSubCommitsController{}
type CanSwitchToSubCommits interface {
types.Context
GetSelectedRef() types.Ref
ShowBranchHeadsInSubCommits() bool
}
type SwitchToSubCommitsController struct {
@ -79,6 +80,7 @@ func (self *SwitchToSubCommitsController) viewCommits() error {
subCommitsContext.SetTitleRef(ref.Description())
subCommitsContext.SetRef(ref)
subCommitsContext.SetLimitCommits(true)
subCommitsContext.SetShowBranchHeads(self.context.ShowBranchHeadsInSubCommits())
subCommitsContext.ClearSearchString()
subCommitsContext.GetView().ClearSearch()

View File

@ -71,7 +71,7 @@ func getBranchDisplayStrings(
}
if fullDescription || userConfig.Gui.ShowBranchCommitHash {
res = append(res, b.CommitHash)
res = append(res, utils.ShortSha(b.CommitHash))
}
res = append(res, coloredName)

View File

@ -39,6 +39,9 @@ type bisectBounds struct {
func GetCommitListDisplayStrings(
common *common.Common,
commits []*models.Commit,
branches []*models.Branch,
currentBranchName string,
showBranchMarkerForHeadCommit bool,
fullDescription bool,
cherryPickedCommitShaSet *set.Set[string],
diffName string,
@ -99,6 +102,30 @@ func GetCommitListDisplayStrings(
getGraphLine = func(idx int) string { return "" }
}
// Determine the hashes of the local branches for which we want to show a
// branch marker in the commits list. We only want to do this for branches
// that are not the current branch, and not any of the main branches. The
// goal is to visualize stacks of local branches, so anything that doesn't
// contribute to a branch stack shouldn't show a marker.
//
// If there are other branches pointing to the current head commit, we only
// want to show the marker if the rebase.updateRefs config is on.
branchHeadsToVisualize := set.NewFromSlice(lo.FilterMap(branches,
func(b *models.Branch, index int) (string, bool) {
return b.CommitHash,
// Don't consider branches that don't have a commit hash. As far
// as I can see, this happens for a detached head, so filter
// these out
b.CommitHash != "" &&
// Don't show a marker for the current branch
b.Name != currentBranchName &&
// Don't show a marker for main branches
!lo.Contains(common.UserConfig.Git.MainBranches, b.Name) &&
// Don't show a marker for the head commit unless the
// rebase.updateRefs config is on
(showBranchMarkerForHeadCommit || b.CommitHash != commits[0].Sha)
}))
lines := make([][]string, 0, len(filteredCommits))
var bisectStatus BisectStatus
for i, commit := range filteredCommits {
@ -112,6 +139,7 @@ func GetCommitListDisplayStrings(
lines = append(lines, displayCommit(
common,
commit,
branchHeadsToVisualize,
cherryPickedCommitShaSet,
diffName,
timeFormat,
@ -260,6 +288,7 @@ func getBisectStatusText(bisectStatus BisectStatus, bisectInfo *git_commands.Bis
func displayCommit(
common *common.Common,
commit *models.Commit,
branchHeadsToVisualize *set.Set[string],
cherryPickedCommitShaSet *set.Set[string],
diffName string,
timeFormat string,
@ -289,8 +318,11 @@ func displayCommit(
} else {
if len(commit.Tags) > 0 {
tagString = theme.DiffTerminalColor.SetBold().Sprint(strings.Join(commit.Tags, " ")) + " "
} else if common.UserConfig.Gui.ExperimentalShowBranchHeads && commit.ExtraInfo != "" {
tagString = style.FgMagenta.SetBold().Sprint("(*)") + " "
}
if branchHeadsToVisualize.Includes(commit.Sha) && commit.Status != models.StatusMerged {
tagString = style.FgCyan.SetBold().Sprint(
lo.Ternary(icons.IsIconEnabled(), icons.BRANCH_ICON, "*") + " " + tagString)
}
}

View File

@ -28,6 +28,9 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
scenarios := []struct {
testName string
commits []*models.Commit
branches []*models.Branch
currentBranchName string
hasUpdateRefConfig bool
fullDescription bool
cherryPickedCommitShaSet *set.Set[string]
diffName string
@ -72,6 +75,120 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
sha2 commit2
`),
},
{
testName: "commit with tags",
commits: []*models.Commit{
{Name: "commit1", Sha: "sha1", Tags: []string{"tag1", "tag2"}},
{Name: "commit2", Sha: "sha2"},
},
startIdx: 0,
length: 2,
showGraph: false,
bisectInfo: git_commands.NewNullBisectInfo(),
cherryPickedCommitShaSet: set.New[string](),
now: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
expected: formatExpected(`
sha1 tag1 tag2 commit1
sha2 commit2
`),
},
{
testName: "show local branch head, except the current branch, main branches, or merged branches",
commits: []*models.Commit{
{Name: "commit1", Sha: "sha1"},
{Name: "commit2", Sha: "sha2"},
{Name: "commit3", Sha: "sha3"},
{Name: "commit4", Sha: "sha4", Status: models.StatusMerged},
},
branches: []*models.Branch{
{Name: "current-branch", CommitHash: "sha1", Head: true},
{Name: "other-branch", CommitHash: "sha2", Head: false},
{Name: "master", CommitHash: "sha3", Head: false},
{Name: "old-branch", CommitHash: "sha4", Head: false},
},
currentBranchName: "current-branch",
hasUpdateRefConfig: true,
startIdx: 0,
length: 4,
showGraph: false,
bisectInfo: git_commands.NewNullBisectInfo(),
cherryPickedCommitShaSet: set.New[string](),
now: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
expected: formatExpected(`
sha1 commit1
sha2 * commit2
sha3 commit3
sha4 commit4
`),
},
{
testName: "show local branch head for head commit if updateRefs is on",
commits: []*models.Commit{
{Name: "commit1", Sha: "sha1"},
{Name: "commit2", Sha: "sha2"},
},
branches: []*models.Branch{
{Name: "current-branch", CommitHash: "sha1", Head: true},
{Name: "other-branch", CommitHash: "sha1", Head: false},
},
currentBranchName: "current-branch",
hasUpdateRefConfig: true,
startIdx: 0,
length: 2,
showGraph: false,
bisectInfo: git_commands.NewNullBisectInfo(),
cherryPickedCommitShaSet: set.New[string](),
now: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
expected: formatExpected(`
sha1 * commit1
sha2 commit2
`),
},
{
testName: "don't show local branch head for head commit if updateRefs is off",
commits: []*models.Commit{
{Name: "commit1", Sha: "sha1"},
{Name: "commit2", Sha: "sha2"},
},
branches: []*models.Branch{
{Name: "current-branch", CommitHash: "sha1", Head: true},
{Name: "other-branch", CommitHash: "sha1", Head: false},
},
currentBranchName: "current-branch",
hasUpdateRefConfig: false,
startIdx: 0,
length: 2,
showGraph: false,
bisectInfo: git_commands.NewNullBisectInfo(),
cherryPickedCommitShaSet: set.New[string](),
now: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
expected: formatExpected(`
sha1 commit1
sha2 commit2
`),
},
{
testName: "show local branch head and tag if both exist",
commits: []*models.Commit{
{Name: "commit1", Sha: "sha1"},
{Name: "commit2", Sha: "sha2", Tags: []string{"some-tag"}},
{Name: "commit3", Sha: "sha3"},
},
branches: []*models.Branch{
{Name: "some-branch", CommitHash: "sha2"},
},
startIdx: 0,
length: 3,
showGraph: false,
bisectInfo: git_commands.NewNullBisectInfo(),
cherryPickedCommitShaSet: set.New[string](),
now: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
expected: formatExpected(`
sha1 commit1
sha2 * some-tag commit2
sha3 commit3
`),
},
{
testName: "showing graph",
commits: []*models.Commit{
@ -285,6 +402,9 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
result := GetCommitListDisplayStrings(
common,
s.commits,
s.branches,
s.currentBranchName,
s.hasUpdateRefConfig,
s.fullDescription,
s.cherryPickedCommitShaSet,
s.diffName,

View File

@ -217,6 +217,10 @@ type Model struct {
RemoteBranches []*models.RemoteBranch
Tags []*models.Tag
// Name of the currently checked out branch. This will be set even when
// we're on a detached head because we're rebasing or bisecting.
CheckedOutBranch string
// for displaying suggestions while typing in a file name
FilesTrie *patricia.Trie

View File

@ -11,6 +11,7 @@ var Basic = NewIntegrationTest(NewIntegrationTestArgs{
Skip: false,
SetupRepo: func(shell *Shell) {
shell.
NewBranch("mybranch").
CreateNCommits(10)
},
SetupConfig: func(cfg *config.AppConfig) {},
@ -31,20 +32,21 @@ var Basic = NewIntegrationTest(NewIntegrationTestArgs{
t.Views().Commits().
Focus().
SelectedLine(Contains("commit 10")).
NavigateToLine(Contains("commit 09")).
SelectedLine(Contains("CI commit 10")).
NavigateToLine(Contains("CI commit 09")).
Tap(func() {
markCommitAsBad()
t.Views().Information().Content(Contains("Bisecting"))
}).
SelectedLine(Contains("<-- bad")).
NavigateToLine(Contains("commit 02")).
NavigateToLine(Contains("CI commit 02")).
Tap(markCommitAsGood).
TopLines(Contains("CI commit 10")).
// lazygit will land us in the commit between our good and bad commits.
SelectedLine(Contains("commit 05").Contains("<-- current")).
SelectedLine(Contains("CI commit 05").Contains("<-- current")).
Tap(markCommitAsBad).
SelectedLine(Contains("commit 04").Contains("<-- current")).
SelectedLine(Contains("CI commit 04").Contains("<-- current")).
Tap(func() {
markCommitAsGood()
@ -52,7 +54,7 @@ var Basic = NewIntegrationTest(NewIntegrationTestArgs{
t.ExpectPopup().Alert().Title(Equals("Bisect complete")).Content(MatchesRegexp("(?s)commit 05.*Do you want to reset")).Confirm()
}).
IsFocused().
Content(Contains("commit 04"))
Content(Contains("CI commit 04"))
t.Views().Information().Content(DoesNotContain("Bisecting"))
},

View File

@ -10,12 +10,16 @@ var DropTodoCommitWithUpdateRef = NewIntegrationTest(NewIntegrationTestArgs{
ExtraCmdArgs: []string{},
Skip: false,
GitVersion: AtLeast("2.38.0"),
SetupConfig: func(config *config.AppConfig) {},
SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Git.MainBranches = []string{"master"}
},
SetupRepo: func(shell *Shell) {
shell.
CreateNCommits(3).
NewBranch("mybranch").
CreateNCommitsStartingAt(3, 4)
CreateNCommits(1).
NewBranch("branch1").
CreateNCommitsStartingAt(3, 2).
NewBranch("branch2").
CreateNCommitsStartingAt(3, 5)
shell.SetConfig("rebase.updateRefs", "true")
},
@ -23,26 +27,28 @@ var DropTodoCommitWithUpdateRef = NewIntegrationTest(NewIntegrationTestArgs{
t.Views().Commits().
Focus().
Lines(
Contains("commit 06").IsSelected(),
Contains("commit 05"),
Contains("commit 04"),
Contains("commit 03"),
Contains("commit 02"),
Contains("commit 01"),
Contains("CI commit 07").IsSelected(),
Contains("CI commit 06"),
Contains("CI commit 05"),
Contains("CI * commit 04"),
Contains("CI commit 03"),
Contains("CI commit 02"),
Contains("CI commit 01"),
).
NavigateToLine(Contains("commit 01")).
NavigateToLine(Contains("commit 02")).
Press(keys.Universal.Edit).
Focus().
Lines(
Contains("pick").Contains("commit 06"),
Contains("pick").Contains("commit 05"),
Contains("pick").Contains("commit 04"),
Contains("update-ref").Contains("master"),
Contains("pick").Contains("commit 03"),
Contains("pick").Contains("commit 02"),
Contains("<-- YOU ARE HERE --- commit 01"),
Contains("pick").Contains("CI commit 07"),
Contains("pick").Contains("CI commit 06"),
Contains("pick").Contains("CI commit 05"),
Contains("update-ref").Contains("branch1").DoesNotContain("*"),
Contains("pick").Contains("CI * commit 04"),
Contains("pick").Contains("CI commit 03"),
Contains("<-- YOU ARE HERE --- commit 02"),
Contains("CI commit 01"),
).
NavigateToLine(Contains("commit 05")).
NavigateToLine(Contains("commit 06")).
Press(keys.Universal.Remove)
t.Common().ContinueRebase()
@ -50,11 +56,12 @@ var DropTodoCommitWithUpdateRef = NewIntegrationTest(NewIntegrationTestArgs{
t.Views().Commits().
IsFocused().
Lines(
Contains("commit 06"),
Contains("commit 04"),
Contains("commit 03"),
Contains("commit 02"),
Contains("commit 01"),
Contains("CI commit 07"),
Contains("CI commit 05"),
Contains("CI * commit 04"),
Contains("CI commit 03"),
Contains("CI commit 02"),
Contains("CI commit 01"),
)
},
})

View File

@ -1,62 +0,0 @@
package interactive_rebase
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var DropTodoCommitWithUpdateRefShowBranchHeads = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Drops a commit during interactive rebase when there is an update-ref in the git-rebase-todo file (with experimentalShowBranchHeads on)",
ExtraCmdArgs: []string{},
Skip: false,
GitVersion: AtLeast("2.38.0"),
SetupConfig: func(config *config.AppConfig) {
config.UserConfig.Gui.ExperimentalShowBranchHeads = true
},
SetupRepo: func(shell *Shell) {
shell.
CreateNCommits(3).
NewBranch("mybranch").
CreateNCommitsStartingAt(3, 4)
shell.SetConfig("rebase.updateRefs", "true")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Commits().
Focus().
Lines(
Contains("(*) commit 06").IsSelected(),
Contains("commit 05"),
Contains("commit 04"),
Contains("(*) commit 03"),
Contains("commit 02"),
Contains("commit 01"),
).
NavigateToLine(Contains("commit 01")).
Press(keys.Universal.Edit).
Focus().
Lines(
Contains("pick").Contains("(*) commit 06"),
Contains("pick").Contains("commit 05"),
Contains("pick").Contains("commit 04"),
Contains("update-ref").Contains("master"),
Contains("pick").Contains("(*) commit 03"),
Contains("pick").Contains("commit 02"),
Contains("<-- YOU ARE HERE --- commit 01"),
).
NavigateToLine(Contains("commit 05")).
Press(keys.Universal.Remove)
t.Common().ContinueRebase()
t.Views().Commits().
IsFocused().
Lines(
Contains("(*) commit 06"),
Contains("commit 04"),
Contains("(*) commit 03"),
Contains("commit 02"),
Contains("commit 01"),
)
},
})

View File

@ -0,0 +1,71 @@
package reflog
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var DoNotShowBranchMarkersInReflogSubcommits = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Verify that no branch heads are shown in the subcommits view of a reflog entry",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) {
shell.NewBranch("branch1")
shell.EmptyCommit("one")
shell.EmptyCommit("two")
shell.NewBranch("branch2")
shell.EmptyCommit("three")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
// Check that the local commits view does show a branch marker for branch1
t.Views().Commits().
Lines(
Contains("CI three"),
Contains("CI * two"),
Contains("CI one"),
)
t.Views().Branches().
Focus().
// Check out branch1
NavigateToLine(Contains("branch1")).
PressPrimaryAction().
// Look at the subcommits of branch2
NavigateToLine(Contains("branch2")).
PressEnter().
// Check that we see a marker for branch1 here (but not for
// branch2), even though branch1 is checked out
Tap(func() {
t.Views().SubCommits().
IsFocused().
Lines(
Contains("CI three"),
Contains("CI * two"),
Contains("CI one"),
).
PressEscape()
}).
// Check out branch2 again
NavigateToLine(Contains("branch2")).
PressPrimaryAction()
t.Views().ReflogCommits().
Focus().
TopLines(
Contains("checkout: moving from branch1 to branch2").IsSelected(),
).
PressEnter().
// Check that the subcommits view for a reflog entry doesn't show
// any branch markers
Tap(func() {
t.Views().SubCommits().
IsFocused().
Lines(
Contains("CI three"),
Contains("CI two"),
Contains("CI one"),
)
})
},
})

View File

@ -117,7 +117,6 @@ var tests = []*components.IntegrationTest{
interactive_rebase.AmendMerge,
interactive_rebase.AmendNonHeadCommitDuringRebase,
interactive_rebase.DropTodoCommitWithUpdateRef,
interactive_rebase.DropTodoCommitWithUpdateRefShowBranchHeads,
interactive_rebase.DropWithCustomCommentChar,
interactive_rebase.EditFirstCommit,
interactive_rebase.EditNonTodoCommitDuringRebase,
@ -164,6 +163,7 @@ var tests = []*components.IntegrationTest{
patch_building.StartNewPatch,
reflog.Checkout,
reflog.CherryPick,
reflog.DoNotShowBranchMarkersInReflogSubcommits,
reflog.Patch,
reflog.Reset,
staging.DiffContextChange,