mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-05-11 12:25:47 +02:00
Mark commits which changed a file among the last X commits
See https://github.com/jesseduffield/lazygit/issues/2653
This commit is contained in:
parent
6f535d71c9
commit
7efe433f1c
9 changed files with 145 additions and 62 deletions
|
@ -65,6 +65,8 @@ gui:
|
|||
splitDiff: 'auto' # one of 'auto' | 'always'
|
||||
skipRewordInEditorWarning: false # for skipping the confirmation before launching the reword editor
|
||||
border: 'single' # one of 'single' | 'double' | 'rounded' | 'hidden'
|
||||
# For marking recent commits which changed the selected file
|
||||
experimentalMarkCommitsWhichChangedFile: false
|
||||
git:
|
||||
paging:
|
||||
colorArg: always
|
||||
|
|
|
@ -3,6 +3,7 @@ package git_commands
|
|||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||
|
@ -250,3 +251,19 @@ func (self *CommitCommands) GetCommitMessageFromHistory(value int) (string, erro
|
|||
}
|
||||
return self.GetCommitMessage(formattedHash)
|
||||
}
|
||||
|
||||
// Returns hashes of recent commits which changed the given file
|
||||
// Note: This does not look for the last X commits to change a file, instead
|
||||
// it looks among the last X commits and see which of them happened to have changed the file.
|
||||
// This is more efficient.
|
||||
func (self *CommitCommands) GetRecentCommitsWhichChangedFile(path string) []string {
|
||||
t := time.Now()
|
||||
// Checking last X commits. Funnily this seems to actually consider more than the last
|
||||
// X, perhaps because of topological sorting.
|
||||
cmdStr := NewGitCmd("log").Arg("HEAD~50..HEAD", "--pretty=%H", "--", self.cmd.Quote(path)).
|
||||
ToString()
|
||||
|
||||
hashes, _ := self.cmd.New(cmdStr).DontLog().RunWithOutput()
|
||||
self.Log.Warn(fmt.Sprintf("GetRecentCommitsWhichChangedFile took %s", time.Since(t)))
|
||||
return strings.Split(strings.TrimSpace(hashes), "\n")
|
||||
}
|
||||
|
|
|
@ -27,33 +27,34 @@ type RefresherConfig struct {
|
|||
}
|
||||
|
||||
type GuiConfig struct {
|
||||
AuthorColors map[string]string `yaml:"authorColors"`
|
||||
BranchColors map[string]string `yaml:"branchColors"`
|
||||
ScrollHeight int `yaml:"scrollHeight"`
|
||||
ScrollPastBottom bool `yaml:"scrollPastBottom"`
|
||||
MouseEvents bool `yaml:"mouseEvents"`
|
||||
SkipUnstageLineWarning bool `yaml:"skipUnstageLineWarning"`
|
||||
SkipStashWarning bool `yaml:"skipStashWarning"`
|
||||
SidePanelWidth float64 `yaml:"sidePanelWidth"`
|
||||
ExpandFocusedSidePanel bool `yaml:"expandFocusedSidePanel"`
|
||||
MainPanelSplitMode string `yaml:"mainPanelSplitMode"`
|
||||
Language string `yaml:"language"`
|
||||
TimeFormat string `yaml:"timeFormat"`
|
||||
Theme ThemeConfig `yaml:"theme"`
|
||||
CommitLength CommitLengthConfig `yaml:"commitLength"`
|
||||
SkipNoStagedFilesWarning bool `yaml:"skipNoStagedFilesWarning"`
|
||||
ShowListFooter bool `yaml:"showListFooter"`
|
||||
ShowFileTree bool `yaml:"showFileTree"`
|
||||
ShowRandomTip bool `yaml:"showRandomTip"`
|
||||
ShowCommandLog bool `yaml:"showCommandLog"`
|
||||
ShowBottomLine bool `yaml:"showBottomLine"`
|
||||
ShowIcons bool `yaml:"showIcons"`
|
||||
ExperimentalShowBranchHeads bool `yaml:"experimentalShowBranchHeads"`
|
||||
CommandLogSize int `yaml:"commandLogSize"`
|
||||
SplitDiff string `yaml:"splitDiff"`
|
||||
SkipRewordInEditorWarning bool `yaml:"skipRewordInEditorWarning"`
|
||||
WindowSize string `yaml:"windowSize"`
|
||||
Border string `yaml:"border"`
|
||||
AuthorColors map[string]string `yaml:"authorColors"`
|
||||
BranchColors map[string]string `yaml:"branchColors"`
|
||||
ScrollHeight int `yaml:"scrollHeight"`
|
||||
ScrollPastBottom bool `yaml:"scrollPastBottom"`
|
||||
MouseEvents bool `yaml:"mouseEvents"`
|
||||
SkipUnstageLineWarning bool `yaml:"skipUnstageLineWarning"`
|
||||
SkipStashWarning bool `yaml:"skipStashWarning"`
|
||||
SidePanelWidth float64 `yaml:"sidePanelWidth"`
|
||||
ExpandFocusedSidePanel bool `yaml:"expandFocusedSidePanel"`
|
||||
MainPanelSplitMode string `yaml:"mainPanelSplitMode"`
|
||||
Language string `yaml:"language"`
|
||||
TimeFormat string `yaml:"timeFormat"`
|
||||
Theme ThemeConfig `yaml:"theme"`
|
||||
CommitLength CommitLengthConfig `yaml:"commitLength"`
|
||||
SkipNoStagedFilesWarning bool `yaml:"skipNoStagedFilesWarning"`
|
||||
ShowListFooter bool `yaml:"showListFooter"`
|
||||
ShowFileTree bool `yaml:"showFileTree"`
|
||||
ShowRandomTip bool `yaml:"showRandomTip"`
|
||||
ShowCommandLog bool `yaml:"showCommandLog"`
|
||||
ShowBottomLine bool `yaml:"showBottomLine"`
|
||||
ShowIcons bool `yaml:"showIcons"`
|
||||
ExperimentalShowBranchHeads bool `yaml:"experimentalShowBranchHeads"`
|
||||
CommandLogSize int `yaml:"commandLogSize"`
|
||||
SplitDiff string `yaml:"splitDiff"`
|
||||
SkipRewordInEditorWarning bool `yaml:"skipRewordInEditorWarning"`
|
||||
WindowSize string `yaml:"windowSize"`
|
||||
Border string `yaml:"border"`
|
||||
ExperimentalMarkCommitsWhichChangedFile bool `yaml:"experimentalMarkCommitsWhichChangedFile"`
|
||||
}
|
||||
|
||||
type ThemeConfig struct {
|
||||
|
@ -410,19 +411,20 @@ func GetDefaultConfig() *UserConfig {
|
|||
UnstagedChangesColor: []string{"red"},
|
||||
DefaultFgColor: []string{"default"},
|
||||
},
|
||||
CommitLength: CommitLengthConfig{Show: true},
|
||||
SkipNoStagedFilesWarning: false,
|
||||
ShowListFooter: true,
|
||||
ShowCommandLog: true,
|
||||
ShowBottomLine: true,
|
||||
ShowFileTree: true,
|
||||
ShowRandomTip: true,
|
||||
ShowIcons: false,
|
||||
ExperimentalShowBranchHeads: false,
|
||||
CommandLogSize: 8,
|
||||
SplitDiff: "auto",
|
||||
SkipRewordInEditorWarning: false,
|
||||
Border: "single",
|
||||
CommitLength: CommitLengthConfig{Show: true},
|
||||
SkipNoStagedFilesWarning: false,
|
||||
ShowListFooter: true,
|
||||
ShowCommandLog: true,
|
||||
ShowBottomLine: true,
|
||||
ShowFileTree: true,
|
||||
ShowRandomTip: true,
|
||||
ShowIcons: false,
|
||||
ExperimentalShowBranchHeads: false,
|
||||
CommandLogSize: 8,
|
||||
SplitDiff: "auto",
|
||||
SkipRewordInEditorWarning: false,
|
||||
Border: "single",
|
||||
ExperimentalMarkCommitsWhichChangedFile: false,
|
||||
},
|
||||
Git: GitConfig{
|
||||
Paging: PagingConfig{
|
||||
|
|
|
@ -3,6 +3,7 @@ package context
|
|||
import (
|
||||
"log"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
|
||||
|
@ -37,20 +38,14 @@ func NewLocalCommitsContext(c *ContextCommon) *LocalCommitsContext {
|
|||
|
||||
showYouAreHereLabel := c.Model().WorkingTreeStateAtLastCommitRefresh == enums.REBASE_MODE_REBASING
|
||||
|
||||
return presentation.GetCommitListDisplayStrings(
|
||||
c.Common,
|
||||
return getCommitsDisplayStrings(
|
||||
c,
|
||||
c.Model().Commits,
|
||||
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
|
||||
c.Modes().CherryPicking.SelectedShaSet(),
|
||||
c.Modes().Diffing.Ref,
|
||||
c.UserConfig.Gui.TimeFormat,
|
||||
c.UserConfig.Git.ParseEmoji,
|
||||
selectedCommitSha,
|
||||
startIdx,
|
||||
length,
|
||||
shouldShowGraph(c),
|
||||
c.Model().BisectInfo,
|
||||
selectedCommitSha,
|
||||
showYouAreHereLabel,
|
||||
c.Model().BisectInfo,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -159,3 +154,31 @@ func shouldShowGraph(c *ContextCommon) bool {
|
|||
log.Fatalf("Unknown value for git.log.showGraph: %s. Expected one of: 'always', 'never', 'when-maximised'", value)
|
||||
return false
|
||||
}
|
||||
|
||||
func getCommitsDisplayStrings(
|
||||
c *ContextCommon,
|
||||
commits []*models.Commit,
|
||||
startIdx int,
|
||||
length int,
|
||||
selectedCommitSha string,
|
||||
showYouAreHereLabel bool,
|
||||
bisectInfo *git_commands.BisectInfo,
|
||||
) [][]string {
|
||||
return presentation.GetCommitListDisplayStrings(
|
||||
c.Common,
|
||||
commits,
|
||||
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
|
||||
c.Modes().CherryPicking.SelectedShaSet(),
|
||||
c.Modes().Diffing.Ref,
|
||||
c.UserConfig.Gui.TimeFormat,
|
||||
c.UserConfig.Git.ParseEmoji,
|
||||
selectedCommitSha,
|
||||
startIdx,
|
||||
length,
|
||||
shouldShowGraph(c),
|
||||
bisectInfo,
|
||||
showYouAreHereLabel,
|
||||
c.State().GetRepoState().GetRecentCommitsWhichChangedFile(),
|
||||
c.UserConfig.Gui.ExperimentalMarkCommitsWhichChangedFile,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
|
@ -40,20 +39,14 @@ func NewSubCommitsContext(
|
|||
selectedCommitSha = selectedCommit.Sha
|
||||
}
|
||||
}
|
||||
return presentation.GetCommitListDisplayStrings(
|
||||
c.Common,
|
||||
return getCommitsDisplayStrings(
|
||||
c,
|
||||
c.Model().SubCommits,
|
||||
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
|
||||
c.Modes().CherryPicking.SelectedShaSet(),
|
||||
c.Modes().Diffing.Ref,
|
||||
c.UserConfig.Gui.TimeFormat,
|
||||
c.UserConfig.Git.ParseEmoji,
|
||||
selectedCommitSha,
|
||||
startIdx,
|
||||
length,
|
||||
shouldShowGraph(c),
|
||||
git_commands.NewNullBisectInfo(),
|
||||
selectedCommitSha,
|
||||
false,
|
||||
git_commands.NewNullBisectInfo(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
|
||||
type FilesController struct {
|
||||
|
@ -192,6 +193,16 @@ func (self *FilesController) GetOnRenderToMain() func() error {
|
|||
}
|
||||
}
|
||||
|
||||
if self.c.UserConfig.Gui.ExperimentalMarkCommitsWhichChangedFile {
|
||||
go utils.Safe(func() {
|
||||
recentCommitsWhichChangedFile := self.c.Git().Commit.GetRecentCommitsWhichChangedFile(node.GetPath())
|
||||
self.c.OnUIThread(func() error {
|
||||
self.c.State().GetRepoState().SetRecentCommitsWhichChangedFile(recentCommitsWhichChangedFile)
|
||||
return self.c.PostRefreshUpdate(self.c.Contexts().LocalCommits)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
self.c.Helpers().MergeConflicts.ResetMergeState()
|
||||
|
||||
pair := self.c.MainViewPairs().Normal
|
||||
|
|
|
@ -220,6 +220,8 @@ type GuiRepoState struct {
|
|||
ScreenMode types.WindowMaximisation
|
||||
|
||||
CurrentPopupOpts *types.CreatePopupPanelOpts
|
||||
|
||||
RecentCommitsWhichChangedFile []string
|
||||
}
|
||||
|
||||
var _ types.IRepoStateAccessor = new(GuiRepoState)
|
||||
|
@ -268,6 +270,14 @@ func (self *GuiRepoState) GetSplitMainPanel() bool {
|
|||
return self.SplitMainPanel
|
||||
}
|
||||
|
||||
func (self *GuiRepoState) SetRecentCommitsWhichChangedFile(value []string) {
|
||||
self.RecentCommitsWhichChangedFile = value
|
||||
}
|
||||
|
||||
func (self *GuiRepoState) GetRecentCommitsWhichChangedFile() []string {
|
||||
return self.RecentCommitsWhichChangedFile
|
||||
}
|
||||
|
||||
type searchingState struct {
|
||||
view *gocui.View
|
||||
isSearching bool
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/kyokomi/emoji/v2"
|
||||
"github.com/samber/lo"
|
||||
"github.com/sasha-s/go-deadlock"
|
||||
)
|
||||
|
||||
|
@ -48,6 +49,8 @@ func GetCommitListDisplayStrings(
|
|||
showGraph bool,
|
||||
bisectInfo *git_commands.BisectInfo,
|
||||
showYouAreHereLabel bool,
|
||||
recentCommitsWhichChangedFile []string,
|
||||
markRecentFileChanges bool,
|
||||
) [][]string {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
@ -113,6 +116,8 @@ func GetCommitListDisplayStrings(
|
|||
bisectStatus,
|
||||
bisectInfo,
|
||||
isYouAreHereCommit,
|
||||
recentCommitsWhichChangedFile,
|
||||
markRecentFileChanges,
|
||||
))
|
||||
}
|
||||
return lines
|
||||
|
@ -259,6 +264,8 @@ func displayCommit(
|
|||
bisectStatus BisectStatus,
|
||||
bisectInfo *git_commands.BisectInfo,
|
||||
isYouAreHereCommit bool,
|
||||
recentCommitsWhichChangedFile []string,
|
||||
markRecentFileChanges bool,
|
||||
) []string {
|
||||
shaColor := getShaColor(commit, diffName, cherryPickedCommitShaSet, bisectStatus, bisectInfo)
|
||||
bisectString := getBisectStatusText(bisectStatus, bisectInfo)
|
||||
|
@ -299,7 +306,23 @@ func displayCommit(
|
|||
|
||||
cols := make([]string, 0, 7)
|
||||
if icons.IsIconEnabled() {
|
||||
cols = append(cols, shaColor.Sprint(icons.IconForCommit(commit)))
|
||||
if markRecentFileChanges && lo.SomeBy(recentCommitsWhichChangedFile, func(sha string) bool {
|
||||
return utils.ShortSha(sha) == utils.ShortSha(commit.Sha)
|
||||
}) {
|
||||
cols = append(cols, style.FgDefault.Sprint(">"))
|
||||
} else {
|
||||
cols = append(cols, shaColor.Sprint(icons.IconForCommit(commit)))
|
||||
}
|
||||
} else {
|
||||
if markRecentFileChanges {
|
||||
if lo.SomeBy(recentCommitsWhichChangedFile, func(sha string) bool {
|
||||
return utils.ShortSha(sha) == utils.ShortSha(commit.Sha)
|
||||
}) {
|
||||
cols = append(cols, style.FgDefault.Sprint(">"))
|
||||
} else {
|
||||
cols = append(cols, " ")
|
||||
}
|
||||
}
|
||||
}
|
||||
cols = append(cols, shaColor.Sprint(commit.ShortSha()))
|
||||
cols = append(cols, bisectString)
|
||||
|
|
|
@ -254,6 +254,8 @@ type IRepoStateAccessor interface {
|
|||
IsSearching() bool
|
||||
SetSplitMainPanel(bool)
|
||||
GetSplitMainPanel() bool
|
||||
SetRecentCommitsWhichChangedFile([]string)
|
||||
GetRecentCommitsWhichChangedFile() []string
|
||||
}
|
||||
|
||||
// startup stages so we don't need to load everything at once
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue