Use more widely-supported Unicode symbols for the commit graph (#5573)

The commit graph used '⏣' (U+23E3 BENZENE RING WITH CIRCLE) for merge
commits and '◯' (U+25EF LARGE CIRCLE) for regular commits. Both have
very poor coverage in popular monospace fonts:

- '⏣' lives in the Misc Technical block and is essentially absent from
every common monospace font (Source Code Pro, JetBrains Mono, Fira Code,
Cascadia Code, Hack, Iosevka, Menlo, Consolas, Monaco, IBM Plex Mono,
Ubuntu Mono, Noto Sans Mono, Inconsolata). It is always drawn from a
system fallback font.
- '◯' is the late-addition LARGE CIRCLE codepoint. It is present in some
fonts (Cascadia, Fira Code, Hack, Iosevka, Menlo, Noto Sans Mono) but
missing from many others, including Source Code Pro and most Nerd Font
derivatives based on it.

This is why the graph renders inconsistently across platforms even when
the same monospace font is configured: each OS picks a different
fallback font (Apple Symbols on macOS, Segoe UI Symbol on Windows,
Noto/DejaVu/Symbola on Linux), and the substituted glyphs differ in
shape, weight, and advance width. '◯' is also East Asian Ambiguous
width, so some terminals render it wider than one cell, exaggerating the
misalignment.

Replace the symbols with codepoints from the foundational 1991 Geometric
Shapes block, which has far broader font coverage:

- Merge: '◎' U+25CE BULLSEYE -- concentric circles, the visually closest
cousin to the previous benzene-ring glyph.
- Commit: '○' U+25CB WHITE CIRCLE -- the same hollow-circle silhouette
as before, just a more universally available codepoint.

The new symbols are present in the font directly in significantly more
cases; and when fallback is still required, they are universally
well-drawn (unlike '⏣', which many fallback fonts also lack).

I also considered choosing suitable nerd font symbols for those who are
using nerd fonts, on the assumption that these must work better because
they are guaranteed to be in the font and no fallback font substitution
is necessary; several suitable icons could be considered, e.g.
`nf-cod-circle_large` or `nf-md-circle_double`. Surprisingly, these
didn't work well, and the reason is that (at least in the font I am
using) these are defined with a glyph width that is wider than their
advance width, which means they draw in different sizes depending on
whether they are followed by a space or not. The glyphs we picked above
don't have this problem.

And finally, I considered adding config options so that users with weird
fonts can pick symbols that work well for them. I would like to avoid
having to do this though; ideally we should be able to make a choice
that works well for everybody.
This commit is contained in:
Stefan Haller 2026-05-04 13:09:28 +02:00 committed by GitHub
commit 59b9b5959d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 288 additions and 288 deletions

View file

@ -202,11 +202,11 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
cherryPickedCommitHashSet: set.New[string](),
now: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
expected: formatExpected(`
hash1 commit1
hash2 commit2
hash3 commit3
hash4 commit4
hash5 commit5
hash1 commit1
hash2 commit2
hash3 commit3
hash4 commit4
hash5 commit5
`),
},
{
@ -227,9 +227,9 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
expected: formatExpected(`
hash1 pick commit1
hash2 pick commit2
hash3 commit3
hash4 commit4
hash5 commit5
hash3 commit3
hash4 commit4
hash5 commit5
`),
},
{
@ -249,9 +249,9 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
now: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
expected: formatExpected(`
hash2 pick commit2
hash3 commit3
hash4 commit4
hash5 commit5
hash3 commit3
hash4 commit4
hash5 commit5
`),
},
{
@ -270,8 +270,8 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
cherryPickedCommitHashSet: set.New[string](),
now: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
expected: formatExpected(`
hash4 commit4
hash5 commit5
hash4 commit4
hash5 commit5
`),
},
{
@ -310,7 +310,7 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
cherryPickedCommitHashSet: set.New[string](),
now: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
expected: formatExpected(`
hash5 commit5
hash5 commit5
`),
},
{
@ -352,14 +352,14 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
cherryPickedCommitHashSet: set.New[string](),
now: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
expected: formatExpected(`
hash1r commit1
hash2r commit2
hash3r commit3
hash1l commit1
hash2l commit2
hash3l commit3
hash4l commit4
hash5l commit5
hash1r commit1
hash2r commit2
hash3r commit3
hash1l commit1
hash2l commit2
hash3l commit3
hash4l commit4
hash5l commit5
`),
},
{
@ -381,12 +381,12 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
cherryPickedCommitHashSet: set.New[string](),
now: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
expected: formatExpected(`
hash3r commit3
hash1l commit1
hash2l commit2
hash3l commit3
hash4l commit4
hash5l commit5
hash3r commit3
hash1l commit1
hash2l commit2
hash3l commit3
hash4l commit4
hash5l commit5
`),
},
{
@ -408,11 +408,11 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
cherryPickedCommitHashSet: set.New[string](),
now: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
expected: formatExpected(`
hash1r commit1
hash2r commit2
hash3r commit3
hash1l commit1
hash2l commit2
hash1r commit1
hash2r commit2
hash3r commit3
hash1l commit1
hash2l commit2
`),
},
{
@ -434,10 +434,10 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
cherryPickedCommitHashSet: set.New[string](),
now: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
expected: formatExpected(`
hash2l commit2
hash3l commit3
hash4l commit4
hash5l commit5
hash2l commit2
hash3l commit3
hash4l commit4
hash5l commit5
`),
},
{
@ -459,8 +459,8 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
cherryPickedCommitHashSet: set.New[string](),
now: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
expected: formatExpected(`
hash1r commit1
hash2r commit2
hash1r commit1
hash2r commit2
`),
},
{
@ -479,11 +479,11 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
cherryPickedCommitHashSet: set.New[string](),
now: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
expected: formatExpected(`
hash1l commit1
hash2l commit2
hash3l commit3
hash4l commit4
hash5l commit5
hash1l commit1
hash2l commit2
hash3l commit3
hash4l commit4
hash5l commit5
`),
},
{
@ -500,9 +500,9 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
cherryPickedCommitHashSet: set.New[string](),
now: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
expected: formatExpected(`
hash1r commit1
hash2r commit2
hash3r commit3
hash1r commit1
hash2r commit2
hash3r commit3
`),
},
{

View file

@ -9,8 +9,8 @@ import (
)
const (
MergeSymbol = ''
CommitSymbol = ''
MergeSymbol = ''
CommitSymbol = ''
)
type cellType int

View file

@ -41,20 +41,20 @@ func TestRenderCommitGraph(t *testing.T) {
{Hash: "D", Parents: []string{"G"}},
},
expectedOutput: `
1
2
3
4
7
5
8
9
B
D
A
E
F
D `,
1
2
3
4
7
5
8
9
B
D
A
E
F
D `,
},
{
name: "with a path that has room to move to the left",
@ -67,12 +67,12 @@ func TestRenderCommitGraph(t *testing.T) {
{Hash: "6", Parents: []string{"7"}},
},
expectedOutput: `
1
2
4
3
5
6 `,
1
2
4
3
5
6 `,
},
{
name: "with a new commit",
@ -86,13 +86,13 @@ func TestRenderCommitGraph(t *testing.T) {
{Hash: "6", Parents: []string{"7"}},
},
expectedOutput: `
1
2
4
Z
3
5
6 `,
1
2
4
Z
3
5
6 `,
},
{
name: "with a path that has room to move to the left and continues",
@ -105,12 +105,12 @@ func TestRenderCommitGraph(t *testing.T) {
{Hash: "7", Parents: []string{"11"}},
},
expectedOutput: `
1
2
3
5
4
7 `,
1
2
3
5
4
7 `,
},
{
name: "with a path that has room to move to the left and continues",
@ -124,13 +124,13 @@ func TestRenderCommitGraph(t *testing.T) {
{Hash: "B", Parents: []string{"C"}},
},
expectedOutput: `
1
2
3
5
7
4
B `,
1
2
3
5
7
4
B `,
},
{
name: "with a path that has room to move to the left and continues",
@ -142,11 +142,11 @@ func TestRenderCommitGraph(t *testing.T) {
{Hash: "6", Parents: []string{"8"}},
},
expectedOutput: `
1
3
2
4
6 `,
1
3
2
4
6 `,
},
{
name: "new merge path fills gap before continuing path on right",
@ -158,11 +158,11 @@ func TestRenderCommitGraph(t *testing.T) {
{Hash: "B", Parents: []string{"C"}},
},
expectedOutput: `
1
4
2
A
B `,
1
4
2
A
B `,
},
{
name: "with a path that has room to move to the left and continues",
@ -177,14 +177,14 @@ func TestRenderCommitGraph(t *testing.T) {
{Hash: "C", Parents: []string{"D"}},
},
expectedOutput: `
1
2
3
5
7
4
B
C `,
1
2
3
5
7
4
B
C `,
},
{
name: "with a path that has room to move to the left and continues",
@ -201,16 +201,16 @@ func TestRenderCommitGraph(t *testing.T) {
{Hash: "D", Parents: []string{"F"}},
},
expectedOutput: `
1
2
3
5
7
8
4
B
C
D `,
1
2
3
5
7
8
4
B
C
D `,
},
}
@ -274,7 +274,7 @@ func TestRenderPipeSet(t *testing.T) {
{fromPos: 0, toPos: 0, fromHash: pool("b"), toHash: pool("c"), kind: STARTS, style: &green},
},
prevCommit: models.NewCommit(hashPool, models.NewCommitOpts{Hash: "a"}),
expectedStr: "",
expectedStr: "",
expectedStyles: []style.TextStyle{green},
},
{
@ -284,7 +284,7 @@ func TestRenderPipeSet(t *testing.T) {
{fromPos: 0, toPos: 0, fromHash: pool("selected"), toHash: pool("c"), kind: STARTS, style: &green},
},
prevCommit: models.NewCommit(hashPool, models.NewCommitOpts{Hash: "a"}),
expectedStr: "",
expectedStr: "",
expectedStyles: []style.TextStyle{highlightStyle},
},
{
@ -296,7 +296,7 @@ func TestRenderPipeSet(t *testing.T) {
{fromPos: 0, toPos: 1, fromHash: pool("selected"), toHash: pool("e"), kind: STARTS, style: &green},
},
prevCommit: models.NewCommit(hashPool, models.NewCommitOpts{Hash: "a"}),
expectedStr: "─╮",
expectedStr: "─╮",
expectedStyles: []style.TextStyle{
highlightStyle, highlightStyle, highlightStyle,
},
@ -310,7 +310,7 @@ func TestRenderPipeSet(t *testing.T) {
{fromPos: 0, toPos: 1, fromHash: pool("b"), toHash: pool("e"), kind: STARTS, style: &green},
},
prevCommit: models.NewCommit(hashPool, models.NewCommitOpts{Hash: "a"}),
expectedStr: "─│",
expectedStr: "─│",
expectedStyles: []style.TextStyle{
green, green, magenta,
},
@ -325,7 +325,7 @@ func TestRenderPipeSet(t *testing.T) {
{fromPos: 0, toPos: 2, fromHash: pool("a2"), toHash: pool("c3"), kind: STARTS, style: &yellow},
},
prevCommit: models.NewCommit(hashPool, models.NewCommitOpts{Hash: "a1"}),
expectedStr: "─│─┬─╯",
expectedStr: "─│─┬─╯",
expectedStyles: []style.TextStyle{
yellow, yellow, magenta, yellow, yellow, green, green,
},
@ -340,7 +340,7 @@ func TestRenderPipeSet(t *testing.T) {
{fromPos: 0, toPos: 2, fromHash: pool("selected"), toHash: pool("c3"), kind: STARTS, style: &yellow},
},
prevCommit: models.NewCommit(hashPool, models.NewCommitOpts{Hash: "a1"}),
expectedStr: "───╮ ╯",
expectedStr: "───╮ ╯",
expectedStyles: []style.TextStyle{
highlightStyle, highlightStyle, highlightStyle, highlightStyle, highlightStyle, nothing, green,
},
@ -354,7 +354,7 @@ func TestRenderPipeSet(t *testing.T) {
{fromPos: 2, toPos: 0, fromHash: pool("c1"), toHash: pool("a2"), kind: TERMINATES, style: &green},
},
prevCommit: models.NewCommit(hashPool, models.NewCommitOpts{Hash: "a1"}),
expectedStr: "─┴─╯",
expectedStr: "─┴─╯",
expectedStyles: []style.TextStyle{
yellow, magenta, magenta, green, green,
},
@ -369,7 +369,7 @@ func TestRenderPipeSet(t *testing.T) {
{fromPos: 2, toPos: 2, fromHash: pool("c1"), toHash: pool("c3"), kind: CONTINUES, style: &green},
},
prevCommit: models.NewCommit(hashPool, models.NewCommitOpts{Hash: "a1"}),
expectedStr: "─│─│─╮",
expectedStr: "─│─│─╮",
expectedStyles: []style.TextStyle{
yellow, yellow, magenta, yellow, green, yellow, yellow,
},
@ -384,7 +384,7 @@ func TestRenderPipeSet(t *testing.T) {
{fromPos: 2, toPos: 0, fromHash: pool("c1"), toHash: pool("a2"), kind: TERMINATES, style: &magenta},
},
prevCommit: models.NewCommit(hashPool, models.NewCommitOpts{Hash: "a1"}),
expectedStr: "─│─╯",
expectedStr: "─│─╯",
expectedStyles: []style.TextStyle{
yellow, yellow, green, magenta, magenta,
},
@ -399,7 +399,7 @@ func TestRenderPipeSet(t *testing.T) {
{fromPos: 3, toPos: 0, fromHash: pool("d1"), toHash: pool("a2"), kind: TERMINATES, style: &magenta},
},
prevCommit: models.NewCommit(hashPool, models.NewCommitOpts{Hash: "a1"}),
expectedStr: "─┬─│─╯",
expectedStr: "─┬─│─╯",
expectedStyles: []style.TextStyle{
yellow, yellow, yellow, magenta, green, magenta, magenta,
},
@ -411,7 +411,7 @@ func TestRenderPipeSet(t *testing.T) {
{fromPos: 0, toPos: 0, fromHash: pool("a2"), toHash: pool("a3"), kind: STARTS, style: &yellow},
},
prevCommit: models.NewCommit(hashPool, models.NewCommitOpts{Hash: "selected"}),
expectedStr: "",
expectedStr: "",
expectedStyles: []style.TextStyle{
yellow,
},
@ -423,7 +423,7 @@ func TestRenderPipeSet(t *testing.T) {
{fromPos: 1, toPos: 1, fromHash: pool("selected"), toHash: pool("b3"), kind: CONTINUES, style: &red},
},
prevCommit: models.NewCommit(hashPool, models.NewCommitOpts{Hash: "selected"}),
expectedStr: " │",
expectedStr: " │",
expectedStyles: []style.TextStyle{
highlightStyle, nothing, highlightStyle,
},
@ -436,7 +436,7 @@ func TestRenderPipeSet(t *testing.T) {
{fromPos: 2, toPos: 2, fromHash: pool("selected"), toHash: pool("b3"), kind: CONTINUES, style: &red},
},
prevCommit: models.NewCommit(hashPool, models.NewCommitOpts{Hash: "selected"}),
expectedStr: " │ │",
expectedStr: " │ │",
expectedStyles: []style.TextStyle{
highlightStyle, nothing, green, nothing, highlightStyle,
},
@ -450,7 +450,7 @@ func TestRenderPipeSet(t *testing.T) {
{fromPos: 1, toPos: 0, fromHash: pool("selected"), toHash: pool("a2"), kind: TERMINATES, style: &yellow},
},
prevCommit: models.NewCommit(hashPool, models.NewCommitOpts{Hash: "selected"}),
expectedStr: "─╯",
expectedStr: "─╯",
expectedStyles: []style.TextStyle{
highlightStyle, highlightStyle, highlightStyle,
},

View file

@ -44,9 +44,9 @@ var MergeNonFastForward = NewIntegrationTest(NewIntegrationTestArgs{
t.Views().Commits().
Lines(
Contains("─╮ Merge branch 'branch1' into original-branch").IsSelected(),
Contains("│ * branch1"),
Contains("─╯ one"),
Contains("─╮ Merge branch 'branch1' into original-branch").IsSelected(),
Contains("│ * branch1"),
Contains("─╯ one"),
)
// Check that branch2 shows the non-fast-forward option first
@ -66,11 +66,11 @@ var MergeNonFastForward = NewIntegrationTest(NewIntegrationTestArgs{
t.Views().Commits().
Lines(
Contains("─╮ Merge branch 'branch2' into original-branch").IsSelected(),
Contains("│ * branch2"),
Contains("─│─╮ Merge branch 'branch1' into original-branch"),
Contains("│ │ * branch1"),
Contains("─┴─╯ one"),
Contains("─╮ Merge branch 'branch2' into original-branch").IsSelected(),
Contains("│ * branch2"),
Contains("─│─╮ Merge branch 'branch1' into original-branch"),
Contains("│ │ * branch1"),
Contains("─┴─╯ one"),
)
},
})

View file

@ -39,10 +39,10 @@ var CherryPickMerge = NewIntegrationTest(NewIntegrationTestArgs{
t.Views().SubCommits().
IsFocused().
Lines(
Contains("─╮ Merge branch 'second-branch'").IsSelected(),
Contains("│ two"),
Contains("│ one"),
Contains(" ╯ base"),
Contains("─╮ Merge branch 'second-branch'").IsSelected(),
Contains("│ two"),
Contains("│ one"),
Contains(" ╯ base"),
).
// copy the merge commit
Press(keys.Commits.CherryPickCopy)

View file

@ -27,11 +27,11 @@ var CreateFixupCommitInBranchStack = NewIntegrationTest(NewIntegrationTestArgs{
t.Views().Commits().
Focus().
Lines(
Contains("CI branch2 commit 2"),
Contains("CI branch2 commit 1"),
Contains("CI * branch1 commit 3"),
Contains("CI branch1 commit 2"),
Contains("CI branch1 commit 1"),
Contains("CI branch2 commit 2"),
Contains("CI branch2 commit 1"),
Contains("CI * branch1 commit 3"),
Contains("CI branch1 commit 2"),
Contains("CI branch1 commit 1"),
).
NavigateToLine(Contains("branch1 commit 2")).
Press(keys.Commits.CreateFixupCommit).
@ -42,12 +42,12 @@ var CreateFixupCommitInBranchStack = NewIntegrationTest(NewIntegrationTestArgs{
Confirm()
}).
Lines(
Contains("CI branch2 commit 2"),
Contains("CI branch2 commit 1"),
Contains("CI * fixup! branch1 commit 2"),
Contains("CI branch1 commit 3"),
Contains("CI branch1 commit 2"),
Contains("CI branch1 commit 1"),
Contains("CI branch2 commit 2"),
Contains("CI branch2 commit 1"),
Contains("CI * fixup! branch1 commit 2"),
Contains("CI branch1 commit 3"),
Contains("CI branch1 commit 2"),
Contains("CI branch1 commit 1"),
)
},
})

View file

@ -24,14 +24,14 @@ var Highlight = NewIntegrationTest(NewIntegrationTestArgs{
highlightedColor := "#ffffff"
t.Views().Commits().
DoesNotContainColoredText(highlightedColor, "").
DoesNotContainColoredText(highlightedColor, "").
Focus().
ContainsColoredText(highlightedColor, "")
ContainsColoredText(highlightedColor, "")
t.Views().Files().
Focus()
t.Views().Commits().
DoesNotContainColoredText(highlightedColor, "")
DoesNotContainColoredText(highlightedColor, "")
},
})

View file

@ -24,10 +24,10 @@ var RevertWithConflictMultipleCommits = NewIntegrationTest(NewIntegrationTestArg
t.Views().Commits().
Focus().
Lines(
Contains("CI add second line").IsSelected(),
Contains("CI add first line"),
Contains("CI unrelated change"),
Contains("CI add empty file"),
Contains("CI add second line").IsSelected(),
Contains("CI add first line"),
Contains("CI unrelated change"),
Contains("CI add empty file"),
).
SelectNextItem().
Press(keys.Universal.RangeSelectDown).
@ -48,10 +48,10 @@ var RevertWithConflictMultipleCommits = NewIntegrationTest(NewIntegrationTestArg
Contains("revert").Contains("CI unrelated change"),
Contains("revert").Contains("CI <-- CONFLICT --- add first line"),
Contains("--- Commits ---"),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI unrelated change"),
Contains("CI add empty file"),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI unrelated change"),
Contains("CI add empty file"),
)
t.Views().Options().Content(Contains("View revert options: m"))
@ -74,12 +74,12 @@ var RevertWithConflictMultipleCommits = NewIntegrationTest(NewIntegrationTestArg
t.Views().Commits().
Lines(
Contains(`CI Revert "unrelated change"`),
Contains(`CI Revert "add first line"`),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI unrelated change"),
Contains("CI add empty file"),
Contains(`CI Revert "unrelated change"`),
Contains(`CI Revert "add first line"`),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI unrelated change"),
Contains("CI add empty file"),
)
},
})

View file

@ -22,9 +22,9 @@ var RevertWithConflictSingleCommit = NewIntegrationTest(NewIntegrationTestArgs{
t.Views().Commits().
Focus().
Lines(
Contains("CI add second line").IsSelected(),
Contains("CI add first line"),
Contains("CI add empty file"),
Contains("CI add second line").IsSelected(),
Contains("CI add first line"),
Contains("CI add empty file"),
).
SelectNextItem().
Press(keys.Commits.RevertCommit).
@ -42,9 +42,9 @@ var RevertWithConflictSingleCommit = NewIntegrationTest(NewIntegrationTestArgs{
Contains("--- Pending reverts ---"),
Contains("revert").Contains("CI <-- CONFLICT --- add first line"),
Contains("--- Commits ---"),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI add empty file"),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI add empty file"),
)
t.Views().Options().Content(Contains("View revert options: m"))
@ -67,10 +67,10 @@ var RevertWithConflictSingleCommit = NewIntegrationTest(NewIntegrationTestArgs{
t.Views().Commits().
Lines(
Contains(`CI Revert "add first line"`),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI add empty file"),
Contains(`CI Revert "add first line"`),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI add empty file"),
)
},
})

View file

@ -34,7 +34,7 @@ var DeleteUpdateRefTodo = NewIntegrationTest(NewIntegrationTestArgs{
Contains("pick").Contains("CI commit 03"),
Contains("pick").Contains("CI commit 02"),
Contains("--- Commits ---"),
Contains("CI commit 01"),
Contains("CI commit 01"),
).
NavigateToLine(Contains("update-ref")).
Press(keys.Universal.Remove).
@ -52,7 +52,7 @@ var DeleteUpdateRefTodo = NewIntegrationTest(NewIntegrationTestArgs{
Contains("pick").Contains("CI commit 03").IsSelected(),
Contains("pick").Contains("CI commit 02"),
Contains("--- Commits ---"),
Contains("CI commit 01"),
Contains("CI commit 01"),
).
NavigateToLine(Contains("commit 02")).
Press(keys.Universal.Remove).
@ -60,11 +60,11 @@ var DeleteUpdateRefTodo = NewIntegrationTest(NewIntegrationTestArgs{
t.Common().ContinueRebase()
}).
Lines(
Contains("CI commit 06"),
Contains("CI commit 05"),
Contains("CI commit 04"),
Contains("CI commit 03"), // No star on this commit, so there's no branch head here
Contains("CI commit 01"),
Contains("CI commit 06"),
Contains("CI commit 05"),
Contains("CI commit 04"),
Contains("CI commit 03"), // No star on this commit, so there's no branch head here
Contains("CI commit 01"),
)
t.Views().Branches().

View file

@ -18,14 +18,14 @@ var DropMergeCommit = NewIntegrationTest(NewIntegrationTestArgs{
t.Views().Commits().
Focus().
Lines(
Contains("CI ─╮ Merge branch 'second-change-branch' into first-change-branch").IsSelected(),
Contains("CI │ * second-change-branch unrelated change"),
Contains("CI │ second change"),
Contains("CI │ first change"),
Contains("CI ─╯ * original"),
Contains("CI three"),
Contains("CI two"),
Contains("CI one"),
Contains("CI ─╮ Merge branch 'second-change-branch' into first-change-branch").IsSelected(),
Contains("CI │ * second-change-branch unrelated change"),
Contains("CI │ second change"),
Contains("CI │ first change"),
Contains("CI ─╯ * original"),
Contains("CI three"),
Contains("CI two"),
Contains("CI one"),
).
Press(keys.Universal.Remove).
Tap(func() {
@ -35,11 +35,11 @@ var DropMergeCommit = NewIntegrationTest(NewIntegrationTestArgs{
Confirm()
}).
Lines(
Contains("CI first change").IsSelected(),
Contains("CI * original"),
Contains("CI three"),
Contains("CI two"),
Contains("CI one"),
Contains("CI first change").IsSelected(),
Contains("CI * original"),
Contains("CI three"),
Contains("CI two"),
Contains("CI one"),
)
},
})

View file

@ -19,8 +19,8 @@ var EditRangeSelectDownToMergeOutsideRebase = NewIntegrationTest(NewIntegrationT
t.Views().Commits().
Focus().
TopLines(
Contains("CI commit 02").IsSelected(),
Contains("CI commit 01"),
Contains("CI commit 02").IsSelected(),
Contains("CI commit 01"),
Contains("Merge branch 'second-change-branch' into first-change-branch"),
).
Press(keys.Universal.RangeSelectDown).
@ -31,14 +31,14 @@ var EditRangeSelectDownToMergeOutsideRebase = NewIntegrationTest(NewIntegrationT
Contains("edit CI commit 02").IsSelected(),
Contains("edit CI commit 01").IsSelected(),
Contains("--- Commits ---").IsSelected(),
Contains(" CI ─╮ Merge branch 'second-change-branch' into first-change-branch").IsSelected(),
Contains(" CI │ * second-change-branch unrelated change"),
Contains(" CI │ second change"),
Contains(" CI │ first change"),
Contains(" CI ─╯ * original"),
Contains(" CI three"),
Contains(" CI two"),
Contains(" CI one"),
Contains(" CI ─╮ Merge branch 'second-change-branch' into first-change-branch").IsSelected(),
Contains(" CI │ * second-change-branch unrelated change"),
Contains(" CI │ second change"),
Contains(" CI │ first change"),
Contains(" CI ─╯ * original"),
Contains(" CI three"),
Contains(" CI two"),
Contains(" CI one"),
)
},
})

View file

@ -26,14 +26,14 @@ var EditRangeSelectOutsideRebase = NewIntegrationTest(NewIntegrationTestArgs{
Press(keys.Universal.RangeSelectDown).
Press(keys.Universal.RangeSelectDown).
Lines(
Contains("CI ─╮ Merge branch 'second-change-branch' into first-change-branch").IsSelected(),
Contains("CI │ * second-change-branch unrelated change").IsSelected(),
Contains("CI │ second change").IsSelected(),
Contains("CI │ first change").IsSelected(),
Contains("CI ─╯ * original").IsSelected(),
Contains("CI three").IsSelected(),
Contains("CI two"),
Contains("CI one"),
Contains("CI ─╮ Merge branch 'second-change-branch' into first-change-branch").IsSelected(),
Contains("CI │ * second-change-branch unrelated change").IsSelected(),
Contains("CI │ second change").IsSelected(),
Contains("CI │ first change").IsSelected(),
Contains("CI ─╯ * original").IsSelected(),
Contains("CI three").IsSelected(),
Contains("CI two"),
Contains("CI one"),
).
Press(keys.Universal.Edit).
Lines(
@ -44,9 +44,9 @@ var EditRangeSelectOutsideRebase = NewIntegrationTest(NewIntegrationTestArgs{
Contains("edit CI second change").IsSelected(),
Contains("edit CI * original").IsSelected(),
Contains("--- Commits ---").IsSelected(),
Contains(" CI three").IsSelected(),
Contains(" CI two"),
Contains(" CI one"),
Contains(" CI three").IsSelected(),
Contains(" CI two"),
Contains(" CI one"),
)
},
})

View file

@ -34,7 +34,7 @@ var MoveUpdateRefTodo = NewIntegrationTest(NewIntegrationTestArgs{
Contains("pick").Contains("CI commit 03"),
Contains("pick").Contains("CI commit 02"),
Contains("--- Commits ---"),
Contains("CI commit 01"),
Contains("CI commit 01"),
).
NavigateToLine(Contains("update-ref")).
Press(keys.Commits.MoveUpCommit).
@ -48,18 +48,18 @@ var MoveUpdateRefTodo = NewIntegrationTest(NewIntegrationTestArgs{
Contains("pick").Contains("CI commit 03"),
Contains("pick").Contains("CI commit 02"),
Contains("--- Commits ---"),
Contains("CI commit 01"),
Contains("CI commit 01"),
).
Tap(func() {
t.Common().ContinueRebase()
}).
Lines(
Contains("CI commit 06"),
Contains("CI * commit 05"),
Contains("CI commit 04"),
Contains("CI commit 03"),
Contains("CI commit 02"),
Contains("CI commit 01"),
Contains("CI commit 06"),
Contains("CI * commit 05"),
Contains("CI commit 04"),
Contains("CI commit 03"),
Contains("CI commit 02"),
Contains("CI commit 01"),
)
},
})

View file

@ -26,12 +26,12 @@ var RevertMultipleCommitsInInteractiveRebase = NewIntegrationTest(NewIntegration
t.Views().Commits().
Focus().
Lines(
Contains("CI unrelated change 3").IsSelected(),
Contains("CI unrelated change 2"),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI unrelated change 1"),
Contains("CI add empty file"),
Contains("CI unrelated change 3").IsSelected(),
Contains("CI unrelated change 2"),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI unrelated change 1"),
Contains("CI add empty file"),
).
NavigateToLine(Contains("add second line")).
Press(keys.Universal.Edit).
@ -57,10 +57,10 @@ var RevertMultipleCommitsInInteractiveRebase = NewIntegrationTest(NewIntegration
Contains("revert").Contains("CI unrelated change 1"),
Contains("revert").Contains("CI <-- CONFLICT --- add first line"),
Contains("--- Commits ---"),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI unrelated change 1"),
Contains("CI add empty file"),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI unrelated change 1"),
Contains("CI add empty file"),
)
t.Views().Options().Content(Contains("View revert options: m"))
@ -87,12 +87,12 @@ var RevertMultipleCommitsInInteractiveRebase = NewIntegrationTest(NewIntegration
Contains("pick").Contains("CI unrelated change 3"),
Contains("pick").Contains("CI unrelated change 2"),
Contains("--- Commits ---"),
Contains(`CI Revert "unrelated change 1"`),
Contains(`CI Revert "add first line"`),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI unrelated change 1"),
Contains("CI add empty file"),
Contains(`CI Revert "unrelated change 1"`),
Contains(`CI Revert "add first line"`),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI unrelated change 1"),
Contains("CI add empty file"),
)
t.Views().Options().Content(Contains("View rebase options: m"))
@ -102,14 +102,14 @@ var RevertMultipleCommitsInInteractiveRebase = NewIntegrationTest(NewIntegration
t.Views().Commits().
Lines(
Contains("CI unrelated change 3"),
Contains("CI unrelated change 2"),
Contains(`CI Revert "unrelated change 1"`),
Contains(`CI Revert "add first line"`),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI unrelated change 1"),
Contains("CI add empty file"),
Contains("CI unrelated change 3"),
Contains("CI unrelated change 2"),
Contains(`CI Revert "unrelated change 1"`),
Contains(`CI Revert "add first line"`),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI unrelated change 1"),
Contains("CI add empty file"),
)
},
})

View file

@ -24,11 +24,11 @@ var RevertSingleCommitInInteractiveRebase = NewIntegrationTest(NewIntegrationTes
t.Views().Commits().
Focus().
Lines(
Contains("CI unrelated change 2").IsSelected(),
Contains("CI unrelated change 1"),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI add empty file"),
Contains("CI unrelated change 2").IsSelected(),
Contains("CI unrelated change 1"),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI add empty file"),
).
NavigateToLine(Contains("add second line")).
Press(keys.Universal.Edit).
@ -51,9 +51,9 @@ var RevertSingleCommitInInteractiveRebase = NewIntegrationTest(NewIntegrationTes
Contains("--- Pending reverts ---"),
Contains("revert").Contains("CI <-- CONFLICT --- add first line"),
Contains("--- Commits ---"),
Contains("CI add second line"),
Contains("CI add first line").IsSelected(),
Contains("CI add empty file"),
Contains("CI add second line"),
Contains("CI add first line").IsSelected(),
Contains("CI add empty file"),
).
Press(keys.Commits.MoveDownCommit).
Tap(func() {
@ -88,10 +88,10 @@ var RevertSingleCommitInInteractiveRebase = NewIntegrationTest(NewIntegrationTes
Contains("pick").Contains("CI unrelated change 2"),
Contains("pick").Contains("CI unrelated change 1"),
Contains("--- Commits ---"),
Contains(`CI Revert "add first line"`),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI add empty file"),
Contains(`CI Revert "add first line"`),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI add empty file"),
)
t.Views().Options().Content(Contains("View rebase options: m"))
@ -101,12 +101,12 @@ var RevertSingleCommitInInteractiveRebase = NewIntegrationTest(NewIntegrationTes
t.Views().Commits().
Lines(
Contains("CI unrelated change 2"),
Contains("CI unrelated change 1"),
Contains(`CI Revert "add first line"`),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI add empty file"),
Contains("CI unrelated change 2"),
Contains("CI unrelated change 1"),
Contains(`CI Revert "add first line"`),
Contains("CI add second line"),
Contains("CI add first line"),
Contains("CI add empty file"),
)
},
})

View file

@ -25,10 +25,10 @@ var RewordMergeCommit = NewIntegrationTest(NewIntegrationTestArgs{
t.Views().Commits().
Focus().
Lines(
Contains("CI two").IsSelected(),
Contains("CI ─╮ Merge branch 'first-branch'"),
Contains("CI │ one"),
Contains("CI ─╯ base"),
Contains("CI two").IsSelected(),
Contains("CI ─╮ Merge branch 'first-branch'"),
Contains("CI │ one"),
Contains("CI ─╯ base"),
).
SelectNextItem().
Press(keys.Commits.RenameCommit).
@ -41,10 +41,10 @@ var RewordMergeCommit = NewIntegrationTest(NewIntegrationTestArgs{
Confirm()
}).
Lines(
Contains("CI two"),
Contains("CI ─╮ renamed merge").IsSelected(),
Contains("CI │ one"),
Contains("CI ╯ base"),
Contains("CI two"),
Contains("CI ─╮ renamed merge").IsSelected(),
Contains("CI │ one"),
Contains("CI ╯ base"),
)
},
})

View file

@ -35,8 +35,8 @@ var ShowExecTodos = NewIntegrationTest(NewIntegrationTestArgs{
Contains("exec").Contains("false"),
Contains("pick").Contains("CI commit 03"),
Contains("--- Commits ---"),
Contains("CI commit 02"),
Contains("CI commit 01"),
Contains("CI commit 02"),
Contains("CI commit 01"),
).
Tap(func() {
t.Common().ContinueRebase()
@ -45,17 +45,17 @@ var ShowExecTodos = NewIntegrationTest(NewIntegrationTestArgs{
Lines(
Contains("--- Pending rebase todos ---"),
Contains("--- Commits ---"),
Contains("CI commit 03"),
Contains("CI commit 02"),
Contains("CI commit 01"),
Contains("CI commit 03"),
Contains("CI commit 02"),
Contains("CI commit 01"),
).
Tap(func() {
t.Common().ContinueRebase()
}).
Lines(
Contains("CI commit 03"),
Contains("CI commit 02"),
Contains("CI commit 01"),
Contains("CI commit 03"),
Contains("CI commit 02"),
Contains("CI commit 01"),
)
},
})