summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2022-03-24 17:49:25 +1100
committerJesse Duffield <jessedduffield@gmail.com>2022-03-24 17:50:25 +1100
commitdde30fa104347ab9c01f82b7886864b473e6f51c (patch)
tree560b545c54e7051d16cef4056f8485557dccee91
parent13a9bbb984601d19f1aabe7abfbf58fbe91cf621 (diff)
add gone branches status
-rw-r--r--pkg/commands/loaders/branches.go78
-rw-r--r--pkg/commands/loaders/branches_test.go52
-rw-r--r--pkg/commands/models/branch.go11
-rw-r--r--pkg/gui/list_context_config.go2
-rw-r--r--pkg/gui/presentation/branches.go24
-rw-r--r--pkg/gui/refresh.go2
-rw-r--r--pkg/gui/status_panel.go2
-rw-r--r--pkg/i18n/english.go2
8 files changed, 121 insertions, 52 deletions
diff --git a/pkg/commands/loaders/branches.go b/pkg/commands/loaders/branches.go
index c54e65ee9..1f78908a8 100644
--- a/pkg/commands/loaders/branches.go
+++ b/pkg/commands/loaders/branches.go
@@ -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)
}
diff --git a/pkg/commands/loaders/branches_test.go b/pkg/commands/loaders/branches_test.go
new file mode 100644
index 000000000..70f02dcf7
--- /dev/null
+++ b/pkg/commands/loaders/branches_test.go
@@ -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)
+ })
+ }
+}
diff --git a/pkg/commands/models/branch.go b/pkg/commands/models/branch.go
index 3cdf5ad6d..dae934fdf 100644
--- a/pkg/commands/models/branch.go
+++ b/pkg/commands/models/branch.go
@@ -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'
diff --git a/pkg/gui/list_context_config.go b/pkg/gui/list_context_config.go
index 89e1461b8..010a2f0b1 100644
--- a/pkg/gui/list_context_config.go
+++ b/pkg/gui/list_context_config.go
@@ -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)),
diff --git a/pkg/gui/presentation/branches.go b/pkg/gui/presentation/branches.go
index e31c823ce..9062eface 100644
--- a/pkg/gui/presentation/branches.go
+++ b/pkg/gui/presentation/branches.go
@@ -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)
}
diff --git a/pkg/gui/refresh.go b/pkg/gui/refresh.go
index d9d661cff..2a47efc7a 100644
--- a/pkg/gui/refresh.go
+++ b/pkg/gui/refresh.go
@@ -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()
diff --git a/pkg/gui/status_panel.go b/pkg/gui/status_panel.go
index 072f41da9..6ca6e6996 100644
--- a/pkg/gui/status_panel.go
+++ b/pkg/gui/status_panel.go
@@ -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 {
diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go
index e72fe7d06..4724abcab 100644
--- a/pkg/i18n/english.go
+++ b/pkg/i18n/english.go
@@ -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",