1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-01-04 03:48:07 +02:00

add gone branches status

This commit is contained in:
Jesse Duffield 2022-03-24 17:49:25 +11:00
parent 13a9bbb984
commit dde30fa104
8 changed files with 121 additions and 52 deletions

View File

@ -106,6 +106,49 @@ outer:
return branches, nil
}
// Obtain branch information from parsed line output of getRawBranches()
// split contains the '|' separated tokens in the line of output
func obtainBranch(split []string) *models.Branch {
name := strings.TrimPrefix(split[1], "heads/")
branch := &models.Branch{
Name: name,
Pullables: "?",
Pushables: "?",
Head: split[0] == "*",
}
upstreamName := split[2]
if upstreamName == "" {
// if we're here then it means we do not have a local version of the remote.
// The branch might still be tracking a remote though, we just don't know
// how many commits ahead/behind it is
return branch
}
track := split[3]
if track == "[gone]" {
branch.UpstreamGone = true
} else {
re := regexp.MustCompile(`ahead (\d+)`)
match := re.FindStringSubmatch(track)
if len(match) > 1 {
branch.Pushables = match[1]
} else {
branch.Pushables = "0"
}
re = regexp.MustCompile(`behind (\d+)`)
match = re.FindStringSubmatch(track)
if len(match) > 1 {
branch.Pullables = match[1]
} else {
branch.Pullables = "0"
}
}
return branch
}
func (self *BranchLoader) obtainBranches() []*models.Branch {
output, err := self.getRawBranches()
if err != nil {
@ -128,40 +171,7 @@ func (self *BranchLoader) obtainBranches() []*models.Branch {
continue
}
name := strings.TrimPrefix(split[1], "heads/")
branch := &models.Branch{
Name: name,
Pullables: "?",
Pushables: "?",
Head: split[0] == "*",
}
upstreamName := split[2]
if upstreamName == "" {
// if we're here then it means we do not have a local version of the remote.
// The branch might still be tracking a remote though, we just don't know
// how many commits ahead/behind it is
branches = append(branches, branch)
continue
}
track := split[3]
re := regexp.MustCompile(`ahead (\d+)`)
match := re.FindStringSubmatch(track)
if len(match) > 1 {
branch.Pushables = match[1]
} else {
branch.Pushables = "0"
}
re = regexp.MustCompile(`behind (\d+)`)
match = re.FindStringSubmatch(track)
if len(match) > 1 {
branch.Pullables = match[1]
} else {
branch.Pullables = "0"
}
branch := obtainBranch(split)
branches = append(branches, branch)
}

View File

@ -0,0 +1,52 @@
package loaders
// "*|feat/detect-purge|origin/feat/detect-purge|[ahead 1]"
import (
"testing"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/stretchr/testify/assert"
)
func TestObtainBanch(t *testing.T) {
type scenario struct {
testName string
input []string
expectedBranch *models.Branch
}
scenarios := []scenario{
{
testName: "TrimHeads",
input: []string{"", "heads/a_branch", "", ""},
expectedBranch: &models.Branch{Name: "a_branch", Pushables: "?", Pullables: "?", Head: false},
},
{
testName: "NoUpstream",
input: []string{"", "a_branch", "", ""},
expectedBranch: &models.Branch{Name: "a_branch", Pushables: "?", Pullables: "?", Head: false},
},
{
testName: "IsHead",
input: []string{"*", "a_branch", "", ""},
expectedBranch: &models.Branch{Name: "a_branch", Pushables: "?", Pullables: "?", Head: true},
},
{
testName: "IsBehindAndAhead",
input: []string{"", "a_branch", "a_remote/a_branch", "[behind 2, ahead 3]"},
expectedBranch: &models.Branch{Name: "a_branch", Pushables: "3", Pullables: "2", Head: false},
},
{
testName: "RemoteBranchIsGone",
input: []string{"", "a_branch", "a_remote/a_branch", "[gone]"},
expectedBranch: &models.Branch{Name: "a_branch", UpstreamGone: true, Pushables: "?", Pullables: "?", Head: false},
},
}
for _, s := range scenarios {
t.Run(s.testName, func(t *testing.T) {
branch := obtainBranch(s.input)
assert.EqualValues(t, s.expectedBranch, branch)
})
}
}

View File

@ -5,11 +5,12 @@ package models
type Branch struct {
Name string
// the displayname is something like '(HEAD detached at 123asdf)', whereas in that case the name would be '123asdf'
DisplayName string
Recency string
Pushables string
Pullables string
Head bool
DisplayName string
Recency string
Pushables string
Pullables string
UpstreamGone bool
Head bool
// if we have a named remote locally this will be the name of that remote e.g.
// 'origin' or 'tiwood'. If we don't have the remote locally it'll look like
// 'git@github.com:tiwood/lazygit.git'

View File

@ -47,7 +47,7 @@ func (gui *Gui) branchesListContext() *context.BranchesContext {
func() []*models.Branch { return gui.State.Model.Branches },
gui.Views.Branches,
func(startIdx int, length int) [][]string {
return presentation.GetBranchListDisplayStrings(gui.State.Model.Branches, gui.State.ScreenMode != SCREEN_NORMAL, gui.State.Modes.Diffing.Ref)
return presentation.GetBranchListDisplayStrings(gui.State.Model.Branches, gui.State.ScreenMode != SCREEN_NORMAL, gui.State.Modes.Diffing.Ref, gui.Tr)
},
nil,
OnFocusWrapper(gui.withDiffModeCheck(gui.branchesRenderToMain)),

View File

@ -6,25 +6,26 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/i18n"
"github.com/jesseduffield/lazygit/pkg/theme"
"github.com/jesseduffield/lazygit/pkg/utils"
)
var branchPrefixColorCache = make(map[string]style.TextStyle)
func GetBranchListDisplayStrings(branches []*models.Branch, fullDescription bool, diffName string) [][]string {
func GetBranchListDisplayStrings(branches []*models.Branch, fullDescription bool, diffName string, tr *i18n.TranslationSet) [][]string {
lines := make([][]string, len(branches))
for i := range branches {
diffed := branches[i].Name == diffName
lines[i] = getBranchDisplayStrings(branches[i], fullDescription, diffed)
lines[i] = getBranchDisplayStrings(branches[i], fullDescription, diffed, tr)
}
return lines
}
// getBranchDisplayStrings returns the display string of branch
func getBranchDisplayStrings(b *models.Branch, fullDescription bool, diffed bool) []string {
func getBranchDisplayStrings(b *models.Branch, fullDescription bool, diffed bool, tr *i18n.TranslationSet) []string {
displayName := b.Name
if b.DisplayName != "" {
displayName = b.DisplayName
@ -36,7 +37,7 @@ func getBranchDisplayStrings(b *models.Branch, fullDescription bool, diffed bool
}
coloredName := nameTextStyle.Sprint(displayName)
if b.IsTrackingRemote() {
coloredName = fmt.Sprintf("%s %s", coloredName, ColoredBranchStatus(b))
coloredName = fmt.Sprintf("%s %s", coloredName, ColoredBranchStatus(b, tr))
}
recencyColor := style.FgCyan
@ -77,18 +78,21 @@ func GetBranchTextStyle(name string) style.TextStyle {
}
}
func ColoredBranchStatus(branch *models.Branch) string {
func ColoredBranchStatus(branch *models.Branch, tr *i18n.TranslationSet) string {
colour := style.FgYellow
if branch.MatchesUpstream() {
colour = style.FgGreen
} else if !branch.IsTrackingRemote() {
if !branch.IsTrackingRemote() || branch.UpstreamGone {
colour = style.FgRed
} else if branch.MatchesUpstream() {
colour = style.FgGreen
}
return colour.Sprint(BranchStatus(branch))
return colour.Sprint(BranchStatus(branch, tr))
}
func BranchStatus(branch *models.Branch) string {
func BranchStatus(branch *models.Branch, tr *i18n.TranslationSet) string {
if branch.UpstreamGone {
return tr.UpstreamGone
}
return fmt.Sprintf("↑%s↓%s", branch.Pushables, branch.Pullables)
}

View File

@ -534,7 +534,7 @@ func (gui *Gui) refreshStatus() {
status := ""
if currentBranch.IsRealBranch() {
status += presentation.ColoredBranchStatus(currentBranch) + " "
status += presentation.ColoredBranchStatus(currentBranch, gui.Tr) + " "
}
workingTreeState := gui.git.Status.WorkingTreeState()

View File

@ -41,7 +41,7 @@ func (gui *Gui) handleStatusClick() error {
}
cx, _ := gui.Views.Status.Cursor()
upstreamStatus := presentation.BranchStatus(currentBranch)
upstreamStatus := presentation.BranchStatus(currentBranch, gui.Tr)
repoName := utils.GetCurrentRepoName()
workingTreeState := gui.git.Status.WorkingTreeState()
switch workingTreeState {

View File

@ -458,6 +458,7 @@ type TranslationSet struct {
RewordInEditorPrompt string
CheckoutPrompt string
HardResetAutostashPrompt string
UpstreamGone string
Actions Actions
Bisect Bisect
}
@ -1035,6 +1036,7 @@ func EnglishTranslationSet() TranslationSet {
RewordInEditorPrompt: "Are you sure you want to reword this commit in your editor?",
HardResetAutostashPrompt: "Are you sure you want to hard reset to '%s'? An auto-stash will be performed if necessary.",
CheckoutPrompt: "Are you sure you want to checkout '%s'?",
UpstreamGone: "↑gone",
Actions: Actions{
// TODO: combine this with the original keybinding descriptions (those are all in lowercase atm)
CheckoutCommit: "Checkout commit",