mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-04-17 12:06:38 +02:00
use reflogs from state to work out branch recencies
This commit is contained in:
parent
bd2c1eef53
commit
fbbd16bd82
@ -2,10 +2,10 @@ package commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -24,13 +24,15 @@ import (
|
|||||||
type BranchListBuilder struct {
|
type BranchListBuilder struct {
|
||||||
Log *logrus.Entry
|
Log *logrus.Entry
|
||||||
GitCommand *GitCommand
|
GitCommand *GitCommand
|
||||||
|
ReflogCommits []*Commit
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBranchListBuilder builds a new branch list builder
|
// NewBranchListBuilder builds a new branch list builder
|
||||||
func NewBranchListBuilder(log *logrus.Entry, gitCommand *GitCommand) (*BranchListBuilder, error) {
|
func NewBranchListBuilder(log *logrus.Entry, gitCommand *GitCommand, reflogCommits []*Commit) (*BranchListBuilder, error) {
|
||||||
return &BranchListBuilder{
|
return &BranchListBuilder{
|
||||||
Log: log,
|
Log: log,
|
||||||
GitCommand: gitCommand,
|
GitCommand: gitCommand,
|
||||||
|
ReflogCommits: reflogCommits,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,63 +134,34 @@ outer:
|
|||||||
}
|
}
|
||||||
branches = append([]*Branch{{Name: currentBranchName, DisplayName: currentBranchDisplayName, Head: true, Recency: " *"}}, branches...)
|
branches = append([]*Branch{{Name: currentBranchName, DisplayName: currentBranchDisplayName, Head: true, Recency: " *"}}, branches...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return branches
|
return branches
|
||||||
}
|
}
|
||||||
|
|
||||||
// A line will have the form '10 days ago master' so we need to strip out the
|
// TODO: only look at the new reflog commits, and otherwise store the recencies in
|
||||||
// useful information from that into timeNumber, timeUnit, and branchName
|
// int form against the branch to recalculate the time ago
|
||||||
func branchInfoFromLine(line string) (string, string) {
|
|
||||||
// example line: HEAD@{12 minutes ago}|checkout: moving from pulling-from-forks to tim77-patch-1
|
|
||||||
r := regexp.MustCompile(`HEAD\@\{([^\s]+) ([^\s]+) ago\}\|.*?([^\s]*)$`)
|
|
||||||
matches := r.FindStringSubmatch(strings.TrimSpace(line))
|
|
||||||
if len(matches) == 0 {
|
|
||||||
return "", ""
|
|
||||||
}
|
|
||||||
since := matches[1]
|
|
||||||
unit := matches[2]
|
|
||||||
branchName := matches[3]
|
|
||||||
return since + abbreviatedTimeUnit(unit), branchName
|
|
||||||
}
|
|
||||||
|
|
||||||
func abbreviatedTimeUnit(timeUnit string) string {
|
|
||||||
r := regexp.MustCompile("s$")
|
|
||||||
timeUnit = r.ReplaceAllString(timeUnit, "")
|
|
||||||
timeUnitMap := map[string]string{
|
|
||||||
"hour": "h",
|
|
||||||
"minute": "m",
|
|
||||||
"second": "s",
|
|
||||||
"week": "w",
|
|
||||||
"year": "y",
|
|
||||||
"day": "d",
|
|
||||||
"month": "m",
|
|
||||||
}
|
|
||||||
return timeUnitMap[timeUnit]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BranchListBuilder) obtainReflogBranches() []*Branch {
|
func (b *BranchListBuilder) obtainReflogBranches() []*Branch {
|
||||||
branches := make([]*Branch, 0)
|
foundBranchesMap := map[string]bool{}
|
||||||
// if we directly put this string in RunCommandWithOutput the compiler complains because it thinks it's a format string
|
re := regexp.MustCompile(`checkout: moving from ([\S]+) to ([\S]+)`)
|
||||||
unescaped := "git reflog --date=relative --pretty='%gd|%gs' --grep-reflog='checkout: moving' HEAD"
|
reflogBranches := make([]*Branch, 0, len(b.ReflogCommits))
|
||||||
rawString, err := b.GitCommand.OSCommand.RunCommandWithOutput(unescaped)
|
for _, commit := range b.ReflogCommits {
|
||||||
|
if match := re.FindStringSubmatch(commit.Name); len(match) == 3 {
|
||||||
|
timestamp, err := strconv.Atoi(commit.Date)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return branches
|
b.Log.Errorf("couldn't parse reflog date: %s", commit.Date)
|
||||||
}
|
|
||||||
|
|
||||||
branchNameMap := map[string]bool{}
|
|
||||||
|
|
||||||
branchLines := utils.SplitLines(rawString)
|
|
||||||
for _, line := range branchLines {
|
|
||||||
recency, branchName := branchInfoFromLine(line)
|
|
||||||
if branchName == "" {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, ok := branchNameMap[branchName]; ok {
|
|
||||||
continue
|
recency := utils.UnixToTimeAgo(timestamp)
|
||||||
|
for _, branchName := range match[1:] {
|
||||||
|
if !foundBranchesMap[branchName] {
|
||||||
|
foundBranchesMap[branchName] = true
|
||||||
|
reflogBranches = append(reflogBranches, &Branch{
|
||||||
|
Recency: recency,
|
||||||
|
Name: branchName,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
branchNameMap[branchName] = true
|
|
||||||
branch := &Branch{Name: branchName, Recency: recency}
|
|
||||||
branches = append(branches, branch)
|
|
||||||
}
|
}
|
||||||
return branches
|
}
|
||||||
|
}
|
||||||
|
return reflogBranches
|
||||||
}
|
}
|
||||||
|
@ -1126,7 +1126,7 @@ func (c *GitCommand) FetchRemote(remoteName string) error {
|
|||||||
func (c *GitCommand) GetNewReflogCommits(lastReflogCommit *Commit) ([]*Commit, error) {
|
func (c *GitCommand) GetNewReflogCommits(lastReflogCommit *Commit) ([]*Commit, error) {
|
||||||
commits := make([]*Commit, 0)
|
commits := make([]*Commit, 0)
|
||||||
re := regexp.MustCompile(`(\w+).*HEAD@\{([^\}]+)\}: (.*)`)
|
re := regexp.MustCompile(`(\w+).*HEAD@\{([^\}]+)\}: (.*)`)
|
||||||
cmd := c.OSCommand.ExecutableFromString("git reflog --abbrev=20 --date=iso")
|
cmd := c.OSCommand.ExecutableFromString("git reflog --abbrev=20 --date=unix")
|
||||||
err := RunLineOutputCmd(cmd, func(line string) (bool, error) {
|
err := RunLineOutputCmd(cmd, func(line string) (bool, error) {
|
||||||
match := re.FindStringSubmatch(line)
|
match := re.FindStringSubmatch(line)
|
||||||
if len(match) <= 1 {
|
if len(match) <= 1 {
|
||||||
|
@ -63,7 +63,7 @@ func (gui *Gui) refreshBranches(g *gocui.Gui) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
g.Update(func(g *gocui.Gui) error {
|
g.Update(func(g *gocui.Gui) error {
|
||||||
builder, err := commands.NewBranchListBuilder(gui.Log, gui.GitCommand)
|
builder, err := commands.NewBranchListBuilder(gui.Log, gui.GitCommand, gui.State.ReflogCommits)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -374,7 +374,7 @@ func (gui *Gui) handleFastForward(g *gocui.Gui, v *gocui.View) error {
|
|||||||
if err := gui.GitCommand.FastForward(branch.Name, remoteName, remoteBranchName); err != nil {
|
if err := gui.GitCommand.FastForward(branch.Name, remoteName, remoteBranchName); err != nil {
|
||||||
_ = gui.createErrorPanel(gui.g, err.Error())
|
_ = gui.createErrorPanel(gui.g, err.Error())
|
||||||
}
|
}
|
||||||
_ = gui.refreshBranches(gui.g)
|
_ = gui.refreshCommits(gui.g)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = gui.closeConfirmationPrompt(gui.g, true)
|
_ = gui.closeConfirmationPrompt(gui.g, true)
|
||||||
@ -481,7 +481,7 @@ func (gui *Gui) handleRenameBranch(g *gocui.Gui, v *gocui.View) error {
|
|||||||
return gui.createErrorPanel(gui.g, err.Error())
|
return gui.createErrorPanel(gui.g, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return gui.refreshBranches(gui.g)
|
return gui.refreshCommits(gui.g)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,12 +79,13 @@ func (gui *Gui) refreshCommits(g *gocui.Gui) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// doing this async because it shouldn't hold anything up
|
|
||||||
go func() {
|
|
||||||
if err := gui.refreshReflogCommits(); err != nil {
|
if err := gui.refreshReflogCommits(); err != nil {
|
||||||
_ = gui.createErrorPanel(gui.g, err.Error())
|
return gui.createErrorPanel(gui.g, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := gui.refreshBranches(gui.g); err != nil {
|
||||||
|
return gui.createErrorPanel(gui.g, err.Error())
|
||||||
}
|
}
|
||||||
}()
|
|
||||||
|
|
||||||
if g.CurrentView() == gui.getCommitFilesView() || (g.CurrentView() == gui.getMainView() || gui.State.MainContext == "patch-building") {
|
if g.CurrentView() == gui.getCommitFilesView() || (g.CurrentView() == gui.getMainView() || gui.State.MainContext == "patch-building") {
|
||||||
return gui.refreshCommitFilesView()
|
return gui.refreshCommitFilesView()
|
||||||
|
@ -27,9 +27,6 @@ func (gui *Gui) resetToRef(ref string, strength string, options commands.RunComm
|
|||||||
if err := gui.refreshFiles(); err != nil {
|
if err := gui.refreshFiles(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := gui.refreshBranches(gui.g); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := gui.resetOrigin(gui.getCommitsView()); err != nil {
|
if err := gui.resetOrigin(gui.getCommitsView()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -14,15 +14,12 @@ import (
|
|||||||
var cyclableViews = []string{"status", "files", "branches", "commits", "stash"}
|
var cyclableViews = []string{"status", "files", "branches", "commits", "stash"}
|
||||||
|
|
||||||
func (gui *Gui) refreshSidePanels(g *gocui.Gui) error {
|
func (gui *Gui) refreshSidePanels(g *gocui.Gui) error {
|
||||||
if err := gui.refreshBranches(g); err != nil {
|
if err := gui.refreshCommits(g); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := gui.refreshFiles(); err != nil {
|
if err := gui.refreshFiles(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := gui.refreshCommits(g); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return gui.refreshStashEntries(g)
|
return gui.refreshStashEntries(g)
|
||||||
}
|
}
|
||||||
|
21
pkg/utils/date.go
Normal file
21
pkg/utils/date.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func UnixToTimeAgo(timestamp int) string {
|
||||||
|
now := time.Now().Unix()
|
||||||
|
delta := float64(now - int64(timestamp))
|
||||||
|
// we go seconds, minutes, hours, days, weeks, months, years
|
||||||
|
conversions := []float64{60, 60, 24, 7, 4.34524, 12}
|
||||||
|
labels := []string{"s", "m", "h", "d", "w", "m", "y"}
|
||||||
|
for i, conversion := range conversions {
|
||||||
|
if delta < conversion {
|
||||||
|
return fmt.Sprintf("%d%s", int(delta), labels[i])
|
||||||
|
}
|
||||||
|
delta /= conversion
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%dy", int(delta))
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user