summaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2022-11-07 16:35:36 +1100
committerJesse Duffield <jessedduffield@gmail.com>2023-06-01 19:21:24 +1000
commita4db44bc3dab55c203c5f4d40c131c9c4adaf793 (patch)
tree6de159b0fcd225e8c96eebea5e852dc4bbefc6cd /pkg
parent4b3f8055d0746c44787c6ba026630f29e7f049b5 (diff)
show commits against branches
Diffstat (limited to 'pkg')
-rw-r--r--pkg/commands/git.go2
-rw-r--r--pkg/commands/git_commands/branch.go10
-rw-r--r--pkg/commands/git_commands/branch_loader.go103
-rw-r--r--pkg/commands/git_commands/branch_loader_test.go68
-rw-r--r--pkg/commands/models/branch.go17
-rw-r--r--pkg/config/user_config.go2
-rw-r--r--pkg/gui/context/branches_context.go1
-rw-r--r--pkg/gui/presentation/branches.go28
-rw-r--r--pkg/utils/formatting.go6
9 files changed, 167 insertions, 70 deletions
diff --git a/pkg/commands/git.go b/pkg/commands/git.go
index 2ae8694e7..d09ff88b0 100644
--- a/pkg/commands/git.go
+++ b/pkg/commands/git.go
@@ -128,7 +128,7 @@ func NewGitCommandAux(
patchCommands := git_commands.NewPatchCommands(gitCommon, rebaseCommands, commitCommands, statusCommands, stashCommands, patchBuilder)
bisectCommands := git_commands.NewBisectCommands(gitCommon)
- branchLoader := git_commands.NewBranchLoader(cmn, branchCommands.GetRawBranches, branchCommands.CurrentBranchInfo, configCommands)
+ branchLoader := git_commands.NewBranchLoader(cmn, cmd, branchCommands.CurrentBranchInfo, configCommands)
commitFileLoader := git_commands.NewCommitFileLoader(cmn, cmd)
commitLoader := git_commands.NewCommitLoader(cmn, cmd, dotGitDir, statusCommands.RebaseMode)
reflogCommitLoader := git_commands.NewReflogCommitLoader(cmn, cmd)
diff --git a/pkg/commands/git_commands/branch.go b/pkg/commands/git_commands/branch.go
index 3c4d97c82..caa876f3f 100644
--- a/pkg/commands/git_commands/branch.go
+++ b/pkg/commands/git_commands/branch.go
@@ -188,16 +188,6 @@ func (self *BranchCommands) Rename(oldName string, newName string) error {
return self.cmd.New(cmdArgs).Run()
}
-func (self *BranchCommands) GetRawBranches() (string, error) {
- cmdArgs := NewGitCmd("for-each-ref").
- Arg("--sort=-committerdate").
- Arg(`--format=%(HEAD)%00%(refname:short)%00%(upstream:short)%00%(upstream:track)`).
- Arg("refs/heads").
- ToArgv()
-
- return self.cmd.New(cmdArgs).DontLog().RunWithOutput()
-}
-
type MergeOpts struct {
FastForwardOnly bool
}
diff --git a/pkg/commands/git_commands/branch_loader.go b/pkg/commands/git_commands/branch_loader.go
index 58e7bb940..cb284f67f 100644
--- a/pkg/commands/git_commands/branch_loader.go
+++ b/pkg/commands/git_commands/branch_loader.go
@@ -1,6 +1,7 @@
package git_commands
import (
+ "fmt"
"regexp"
"strings"
@@ -8,8 +9,10 @@ import (
"github.com/jesseduffield/generics/slices"
"github.com/jesseduffield/go-git/v5/config"
"github.com/jesseduffield/lazygit/pkg/commands/models"
+ "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/utils"
+ "github.com/samber/lo"
)
// context:
@@ -36,20 +39,20 @@ type BranchInfo struct {
// BranchLoader returns a list of Branch objects for the current repo
type BranchLoader struct {
*common.Common
- getRawBranches func() (string, error)
+ cmd oscommands.ICmdObjBuilder
getCurrentBranchInfo func() (BranchInfo, error)
config BranchLoaderConfigCommands
}
func NewBranchLoader(
cmn *common.Common,
- getRawBranches func() (string, error),
+ cmd oscommands.ICmdObjBuilder,
getCurrentBranchInfo func() (BranchInfo, error),
config BranchLoaderConfigCommands,
) *BranchLoader {
return &BranchLoader{
Common: cmn,
- getRawBranches: getRawBranches,
+ cmd: cmd,
getCurrentBranchInfo: getCurrentBranchInfo,
config: config,
}
@@ -128,8 +131,8 @@ func (self *BranchLoader) obtainBranches() []*models.Branch {
}
split := strings.Split(line, "\x00")
- if len(split) != 4 {
- // Ignore line if it isn't separated into 4 parts
+ if len(split) != len(branchFields) {
+ // Ignore line if it isn't separated into the expected number of parts
// This is probably a warning message, for more info see:
// https://github.com/jesseduffield/lazygit/issues/1385#issuecomment-885580439
return nil, false
@@ -139,47 +142,81 @@ func (self *BranchLoader) obtainBranches() []*models.Branch {
})
}
+func (self *BranchLoader) getRawBranches() (string, error) {
+ format := strings.Join(
+ lo.Map(branchFields, func(thing string, _ int) string {
+ return "%(" + thing + ")"
+ }),
+ "%00",
+ )
+
+ cmdArgs := NewGitCmd("for-each-ref").
+ Arg("--sort=-committerdate").
+ Arg(fmt.Sprintf("--format=%s", format)).
+ Arg("refs/heads").
+ ToArgv()
+
+ return self.cmd.New(cmdArgs).DontLog().RunWithOutput()
+}
+
+var branchFields = []string{
+ "HEAD",
+ "refname:short",
+ "upstream:short",
+ "upstream:track",
+ "subject",
+ fmt.Sprintf("objectname:short=%d", utils.COMMIT_HASH_SHORT_SIZE),
+}
+
// 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] == "*",
+ headMarker := split[0]
+ fullName := split[1]
+ upstreamName := split[2]
+ track := split[3]
+ subject := split[4]
+ commitHash := split[5]
+
+ name := strings.TrimPrefix(fullName, "heads/")
+ pushables, pullables, gone := parseUpstreamInfo(upstreamName, track)
+
+ return &models.Branch{
+ Name: name,
+ Pushables: pushables,
+ Pullables: pullables,
+ UpstreamGone: gone,
+ Head: headMarker == "*",
+ Subject: subject,
+ CommitHash: commitHash,
}
+}
- upstreamName := split[2]
+func parseUpstreamInfo(upstreamName string, track string) (string, string, bool) {
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
+ return "?", "?", false
}
- 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 "?", "?", true
}
- return branch
+ pushables := parseDifference(track, `ahead (\d+)`)
+ pullables := parseDifference(track, `behind (\d+)`)
+
+ return pushables, pullables, false
+}
+
+func parseDifference(track string, regexStr string) string {
+ re := regexp.MustCompile(regexStr)
+ match := re.FindStringSubmatch(track)
+ if len(match) > 1 {
+ return match[1]
+ } else {
+ return "0"
+ }
}
// TODO: only look at the new reflog commits, and otherwise store the recencies in
diff --git a/pkg/commands/git_commands/branch_loader_test.go b/pkg/commands/git_commands/branch_loader_test.go
index c147c1484..f16dcf5f4 100644
--- a/pkg/commands/git_commands/branch_loader_test.go
+++ b/pkg/commands/git_commands/branch_loader_test.go
@@ -8,7 +8,7 @@ import (
"github.com/stretchr/testify/assert"
)
-func TestObtainBanch(t *testing.T) {
+func TestObtainBranch(t *testing.T) {
type scenario struct {
testName string
input []string
@@ -17,29 +17,65 @@ func TestObtainBanch(t *testing.T) {
scenarios := []scenario{
{
- testName: "TrimHeads",
- input: []string{"", "heads/a_branch", "", ""},
- expectedBranch: &models.Branch{Name: "a_branch", Pushables: "?", Pullables: "?", Head: false},
+ testName: "TrimHeads",
+ input: []string{"", "heads/a_branch", "", "", "subject", "123"},
+ expectedBranch: &models.Branch{
+ Name: "a_branch",
+ Pushables: "?",
+ Pullables: "?",
+ Head: false,
+ Subject: "subject",
+ CommitHash: "123",
+ },
},
{
- testName: "NoUpstream",
- input: []string{"", "a_branch", "", ""},
- expectedBranch: &models.Branch{Name: "a_branch", Pushables: "?", Pullables: "?", Head: false},
+ testName: "NoUpstream",
+ input: []string{"", "a_branch", "", "", "subject", "123"},
+ expectedBranch: &models.Branch{
+ Name: "a_branch",
+ Pushables: "?",
+ Pullables: "?",
+ Head: false,
+ Subject: "subject",
+ CommitHash: "123",
+ },
},
{
- testName: "IsHead",
- input: []string{"*", "a_branch", "", ""},
- expectedBranch: &models.Branch{Name: "a_branch", Pushables: "?", Pullables: "?", Head: true},
+ testName: "IsHead",
+ input: []string{"*", "a_branch", "", "", "subject", "123"},
+ expectedBranch: &models.Branch{
+ Name: "a_branch",
+ Pushables: "?",
+ Pullables: "?",
+ Head: true,
+ Subject: "subject",
+ CommitHash: "123",
+ },
},
{
- 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: "IsBehindAndAhead",
+ input: []string{"", "a_branch", "a_remote/a_branch", "[behind 2, ahead 3]", "subject", "123"},
+ expectedBranch: &models.Branch{
+ Name: "a_branch",
+ Pushables: "3",
+ Pullables: "2",
+ Head: false,
+ Subject: "subject",
+ CommitHash: "123",
+ },
},
{
- testName: "RemoteBranchIsGone",
- input: []string{"", "a_branch", "a_remote/a_branch", "[gone]"},
- expectedBranch: &models.Branch{Name: "a_branch", UpstreamGone: true, Pushables: "?", Pullables: "?", Head: false},
+ testName: "RemoteBranchIsGone",
+ input: []string{"", "a_branch", "a_remote/a_branch", "[gone]", "subject", "123"},
+ expectedBranch: &models.Branch{
+ Name: "a_branch",
+ UpstreamGone: true,
+ Pushables: "?",
+ Pullables: "?",
+ Head: false,
+ Subject: "subject",
+ CommitHash: "123",
+ },
},
}
diff --git a/pkg/commands/models/branch.go b/pkg/commands/models/branch.go
index 895b0442a..b4dcc0a79 100644
--- a/pkg/commands/models/branch.go
+++ b/pkg/commands/models/branch.go
@@ -5,11 +5,16 @@ 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
+ DisplayName string
+ // indicator of when the branch was last checked out e.g. '2d', '3m'
+ Recency string
+ // how many commits ahead we are from the remote branch (how many commits we can push)
+ Pushables string
+ // how many commits behind we are from the remote branch (how many commits we can pull)
+ Pullables string
+ // whether the remote branch is 'gone' i.e. we're tracking a remote branch that has been deleted
UpstreamGone bool
+ // whether this is the current branch. Exactly one branch should have this be true
Head bool
DetachedHead bool
// if we have a named remote locally this will be the name of that remote e.g.
@@ -17,6 +22,10 @@ type Branch struct {
// 'git@github.com:tiwood/lazygit.git'
UpstreamRemote string
UpstreamBranch string
+ // subject line in commit message
+ Subject string
+ // commit hash
+ CommitHash string
}
func (b *Branch) FullRefName() string {
diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go
index 295c8178d..597253e3d 100644
--- a/pkg/config/user_config.go
+++ b/pkg/config/user_config.go
@@ -49,6 +49,7 @@ type GuiConfig struct {
ShowCommandLog bool `yaml:"showCommandLog"`
ShowBottomLine bool `yaml:"showBottomLine"`
ShowIcons bool `yaml:"showIcons"`
+ ShowBranchCommitHash bool `yaml:"showBranchCommitHash"`
ExperimentalShowBranchHeads bool `yaml:"experimentalShowBranchHeads"`
CommandLogSize int `yaml:"commandLogSize"`
SplitDiff string `yaml:"splitDiff"`
@@ -426,6 +427,7 @@ func GetDefaultConfig() *UserConfig {
ShowRandomTip: true,
ShowIcons: false,
ExperimentalShowBranchHeads: false,
+ ShowBranchCommitHash: false,
CommandLogSize: 8,
SplitDiff: "auto",
SkipRewordInEditorWarning: false,
diff --git a/pkg/gui/context/branches_context.go b/pkg/gui/context/branches_context.go
index 1d6453c13..c2463ad20 100644
--- a/pkg/gui/context/branches_context.go
+++ b/pkg/gui/context/branches_context.go
@@ -25,6 +25,7 @@ func NewBranchesContext(c *ContextCommon) *BranchesContext {
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
c.Modes().Diffing.Ref,
c.Tr,
+ c.UserConfig,
)
}
diff --git a/pkg/gui/presentation/branches.go b/pkg/gui/presentation/branches.go
index bb4570654..cf0802d6f 100644
--- a/pkg/gui/presentation/branches.go
+++ b/pkg/gui/presentation/branches.go
@@ -6,6 +6,7 @@ import (
"github.com/jesseduffield/generics/slices"
"github.com/jesseduffield/lazygit/pkg/commands/models"
+ "github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/presentation/icons"
"github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/i18n"
@@ -15,15 +16,27 @@ import (
var branchPrefixColorCache = make(map[string]style.TextStyle)
-func GetBranchListDisplayStrings(branches []*models.Branch, fullDescription bool, diffName string, tr *i18n.TranslationSet) [][]string {
+func GetBranchListDisplayStrings(
+ branches []*models.Branch,
+ fullDescription bool,
+ diffName string,
+ tr *i18n.TranslationSet,
+ userConfig *config.UserConfig,
+) [][]string {
return slices.Map(branches, func(branch *models.Branch) []string {
diffed := branch.Name == diffName
- return getBranchDisplayStrings(branch, fullDescription, diffed, tr)
+ return getBranchDisplayStrings(branch, fullDescription, diffed, tr, userConfig)
})
}
// getBranchDisplayStrings returns the display string of branch
-func getBranchDisplayStrings(b *models.Branch, fullDescription bool, diffed bool, tr *i18n.TranslationSet) []string {
+func getBranchDisplayStrings(
+ b *models.Branch,
+ fullDescription bool,
+ diffed bool,
+ tr *i18n.TranslationSet,
+ userConfig *config.UserConfig,
+) []string {
displayName := b.Name
if b.DisplayName != "" {
displayName = b.DisplayName
@@ -43,12 +56,18 @@ func getBranchDisplayStrings(b *models.Branch, fullDescription bool, diffed bool
recencyColor = style.FgGreen
}
- res := make([]string, 0, 4)
+ res := make([]string, 0, 6)
res = append(res, recencyColor.Sprint(b.Recency))
if icons.IsIconEnabled() {
res = append(res, nameTextStyle.Sprint(icons.IconForBranch(b)))
}
+
+ if fullDescription || userConfig.Gui.ShowBranchCommitHash {
+ res = append(res, b.CommitHash)
+ }
+
res = append(res, coloredName)
+
if fullDescription {
res = append(
res,
@@ -56,6 +75,7 @@ func getBranchDisplayStrings(b *models.Branch, fullDescription bool, diffed bool
style.FgYellow.Sprint(b.UpstreamRemote),
style.FgYellow.Sprint(b.UpstreamBranch),
),
+ utils.TruncateWithEllipsis(b.Subject, 60),
)
}
return res
diff --git a/pkg/utils/formatting.go b/pkg/utils/formatting.go
index 2a900d207..5d04a16a8 100644
--- a/pkg/utils/formatting.go
+++ b/pkg/utils/formatting.go
@@ -149,9 +149,11 @@ func SafeTruncate(str string, limit int) string {
}
}
+const COMMIT_HASH_SHORT_SIZE = 8
+
func ShortSha(sha string) string {
- if len(sha) < 8 {
+ if len(sha) < COMMIT_HASH_SHORT_SIZE {
return sha
}
- return sha[:8]
+ return sha[:COMMIT_HASH_SHORT_SIZE]
}