1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-06-15 00:15:32 +02:00
This commit is contained in:
Jesse Duffield
2021-12-30 17:19:01 +11:00
parent 96c2887fd0
commit 9b2b0fc122
22 changed files with 453 additions and 471 deletions

View File

@ -127,9 +127,12 @@ type MergeOpts struct {
// Merge merge // Merge merge
func (c *GitCommand) Merge(branchName string, opts MergeOpts) error { func (c *GitCommand) Merge(branchName string, opts MergeOpts) error {
mergeArgs := c.UserConfig.Git.Merging.Args mergeArg := ""
if c.UserConfig.Git.Merging.Args != "" {
mergeArg = " " + c.UserConfig.Git.Merging.Args
}
command := fmt.Sprintf("git merge --no-edit %s %s", mergeArgs, c.OSCommand.Quote(branchName)) command := fmt.Sprintf("git merge --no-edit%s %s", mergeArg, c.OSCommand.Quote(branchName))
if opts.FastForwardOnly { if opts.FastForwardOnly {
command = fmt.Sprintf("%s --ff-only", command) command = fmt.Sprintf("%s --ff-only", command)
} }

View File

@ -1,120 +1,85 @@
package commands package commands
import ( import (
"os/exec"
"testing" "testing"
"github.com/jesseduffield/lazygit/pkg/secureexec" "github.com/go-errors/errors"
"github.com/jesseduffield/lazygit/pkg/test" "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
// TestGitCommandGetCommitDifferences is a function.
func TestGitCommandGetCommitDifferences(t *testing.T) { func TestGitCommandGetCommitDifferences(t *testing.T) {
type scenario struct { type scenario struct {
testName string testName string
command func(string, ...string) *exec.Cmd runner *oscommands.FakeCmdObjRunner
test func(string, string) expectedPushables string
expectedPullables string
} }
scenarios := []scenario{ scenarios := []scenario{
{ {
"Can't retrieve pushable count", "Can't retrieve pushable count",
func(string, ...string) *exec.Cmd { oscommands.NewFakeRunner(t).
return secureexec.Command("test") Expect("git rev-list @{u}..HEAD --count", "", errors.New("error")),
}, "?", "?",
func(pushableCount string, pullableCount string) {
assert.EqualValues(t, "?", pushableCount)
assert.EqualValues(t, "?", pullableCount)
},
}, },
{ {
"Can't retrieve pullable count", "Can't retrieve pullable count",
func(cmd string, args ...string) *exec.Cmd { oscommands.NewFakeRunner(t).
if args[1] == "HEAD..@{u}" { Expect("git rev-list @{u}..HEAD --count", "1\n", nil).
return secureexec.Command("test") Expect("git rev-list HEAD..@{u} --count", "", errors.New("error")),
} "?", "?",
return secureexec.Command("echo")
},
func(pushableCount string, pullableCount string) {
assert.EqualValues(t, "?", pushableCount)
assert.EqualValues(t, "?", pullableCount)
},
}, },
{ {
"Retrieve pullable and pushable count", "Retrieve pullable and pushable count",
func(cmd string, args ...string) *exec.Cmd { oscommands.NewFakeRunner(t).
if args[1] == "HEAD..@{u}" { Expect("git rev-list @{u}..HEAD --count", "1\n", nil).
return secureexec.Command("echo", "10") Expect("git rev-list HEAD..@{u} --count", "2\n", nil),
} "1", "2",
return secureexec.Command("echo", "11")
},
func(pushableCount string, pullableCount string) {
assert.EqualValues(t, "11", pushableCount)
assert.EqualValues(t, "10", pullableCount)
},
}, },
} }
for _, s := range scenarios { for _, s := range scenarios {
t.Run(s.testName, func(t *testing.T) { t.Run(s.testName, func(t *testing.T) {
gitCmd := NewDummyGitCommand() gitCmd := NewDummyGitCommandWithRunner(s.runner)
gitCmd.OSCommand.Command = s.command pushables, pullables := gitCmd.GetCommitDifferences("HEAD", "@{u}")
s.test(gitCmd.GetCommitDifferences("HEAD", "@{u}")) assert.EqualValues(t, s.expectedPushables, pushables)
assert.EqualValues(t, s.expectedPullables, pullables)
s.runner.CheckForMissingCalls()
}) })
} }
} }
// TestGitCommandNewBranch is a function.
func TestGitCommandNewBranch(t *testing.T) { func TestGitCommandNewBranch(t *testing.T) {
gitCmd := NewDummyGitCommand() runner := oscommands.NewFakeRunner(t).
gitCmd.OSCommand.Command = func(cmd string, args ...string) *exec.Cmd { Expect(`git checkout -b "test" "master"`, "", nil)
assert.EqualValues(t, "git", cmd) gitCmd := NewDummyGitCommandWithRunner(runner)
assert.EqualValues(t, []string{"checkout", "-b", "test", "master"}, args)
return secureexec.Command("echo")
}
assert.NoError(t, gitCmd.NewBranch("test", "master")) assert.NoError(t, gitCmd.NewBranch("test", "master"))
runner.CheckForMissingCalls()
} }
// TestGitCommandDeleteBranch is a function.
func TestGitCommandDeleteBranch(t *testing.T) { func TestGitCommandDeleteBranch(t *testing.T) {
type scenario struct { type scenario struct {
testName string testName string
branch string
force bool force bool
command func(string, ...string) *exec.Cmd runner *oscommands.FakeCmdObjRunner
test func(error) test func(error)
} }
scenarios := []scenario{ scenarios := []scenario{
{ {
"Delete a branch", "Delete a branch",
"test",
false, false,
func(cmd string, args ...string) *exec.Cmd { oscommands.NewFakeRunner(t).Expect(`git branch -d "test"`, "", nil),
assert.EqualValues(t, "git", cmd)
assert.EqualValues(t, []string{"branch", "-d", "test"}, args)
return secureexec.Command("echo")
},
func(err error) { func(err error) {
assert.NoError(t, err) assert.NoError(t, err)
}, },
}, },
{ {
"Force delete a branch", "Force delete a branch",
"test",
true, true,
func(cmd string, args ...string) *exec.Cmd { oscommands.NewFakeRunner(t).Expect(`git branch -D "test"`, "", nil),
assert.EqualValues(t, "git", cmd)
assert.EqualValues(t, []string{"branch", "-D", "test"}, args)
return secureexec.Command("echo")
},
func(err error) { func(err error) {
assert.NoError(t, err) assert.NoError(t, err)
}, },
@ -123,31 +88,27 @@ func TestGitCommandDeleteBranch(t *testing.T) {
for _, s := range scenarios { for _, s := range scenarios {
t.Run(s.testName, func(t *testing.T) { t.Run(s.testName, func(t *testing.T) {
gitCmd := NewDummyGitCommand() gitCmd := NewDummyGitCommandWithRunner(s.runner)
gitCmd.OSCommand.Command = s.command
s.test(gitCmd.DeleteBranch(s.branch, s.force)) s.test(gitCmd.DeleteBranch("test", s.force))
s.runner.CheckForMissingCalls()
}) })
} }
} }
// TestGitCommandMerge is a function.
func TestGitCommandMerge(t *testing.T) { func TestGitCommandMerge(t *testing.T) {
gitCmd := NewDummyGitCommand() runner := oscommands.NewFakeRunner(t).
gitCmd.OSCommand.Command = func(cmd string, args ...string) *exec.Cmd { Expect(`git merge --no-edit "test"`, "", nil)
assert.EqualValues(t, "git", cmd) gitCmd := NewDummyGitCommandWithRunner(runner)
assert.EqualValues(t, []string{"merge", "--no-edit", "test"}, args)
return secureexec.Command("echo")
}
assert.NoError(t, gitCmd.Merge("test", MergeOpts{})) assert.NoError(t, gitCmd.Merge("test", MergeOpts{}))
runner.CheckForMissingCalls()
} }
// TestGitCommandCheckout is a function.
func TestGitCommandCheckout(t *testing.T) { func TestGitCommandCheckout(t *testing.T) {
type scenario struct { type scenario struct {
testName string testName string
command func(string, ...string) *exec.Cmd runner *oscommands.FakeCmdObjRunner
test func(error) test func(error)
force bool force bool
} }
@ -155,12 +116,7 @@ func TestGitCommandCheckout(t *testing.T) {
scenarios := []scenario{ scenarios := []scenario{
{ {
"Checkout", "Checkout",
func(cmd string, args ...string) *exec.Cmd { oscommands.NewFakeRunner(t).Expect(`git checkout "test"`, "", nil),
assert.EqualValues(t, "git", cmd)
assert.EqualValues(t, []string{"checkout", "test"}, args)
return secureexec.Command("echo")
},
func(err error) { func(err error) {
assert.NoError(t, err) assert.NoError(t, err)
}, },
@ -168,12 +124,7 @@ func TestGitCommandCheckout(t *testing.T) {
}, },
{ {
"Checkout forced", "Checkout forced",
func(cmd string, args ...string) *exec.Cmd { oscommands.NewFakeRunner(t).Expect(`git checkout --force "test"`, "", nil),
assert.EqualValues(t, "git", cmd)
assert.EqualValues(t, []string{"checkout", "--force", "test"}, args)
return secureexec.Command("echo")
},
func(err error) { func(err error) {
assert.NoError(t, err) assert.NoError(t, err)
}, },
@ -183,52 +134,43 @@ func TestGitCommandCheckout(t *testing.T) {
for _, s := range scenarios { for _, s := range scenarios {
t.Run(s.testName, func(t *testing.T) { t.Run(s.testName, func(t *testing.T) {
gitCmd := NewDummyGitCommand() gitCmd := NewDummyGitCommandWithRunner(s.runner)
gitCmd.OSCommand.Command = s.command
s.test(gitCmd.Checkout("test", CheckoutOptions{Force: s.force})) s.test(gitCmd.Checkout("test", CheckoutOptions{Force: s.force}))
s.runner.CheckForMissingCalls()
}) })
} }
} }
// TestGitCommandGetBranchGraph is a function.
func TestGitCommandGetBranchGraph(t *testing.T) { func TestGitCommandGetBranchGraph(t *testing.T) {
gitCmd := NewDummyGitCommand() runner := oscommands.NewFakeRunner(t).ExpectArgs([]string{
gitCmd.OSCommand.Command = func(cmd string, args ...string) *exec.Cmd { "git", "log", "--graph", "--color=always", "--abbrev-commit", "--decorate", "--date=relative", "--pretty=medium", "test", "--",
assert.EqualValues(t, "git", cmd) }, "", nil)
assert.EqualValues(t, []string{"log", "--graph", "--color=always", "--abbrev-commit", "--decorate", "--date=relative", "--pretty=medium", "test", "--"}, args) gitCmd := NewDummyGitCommandWithRunner(runner)
return secureexec.Command("echo")
}
_, err := gitCmd.GetBranchGraph("test") _, err := gitCmd.GetBranchGraph("test")
assert.NoError(t, err) assert.NoError(t, err)
} }
func TestGitCommandGetAllBranchGraph(t *testing.T) { func TestGitCommandGetAllBranchGraph(t *testing.T) {
gitCmd := NewDummyGitCommand() runner := oscommands.NewFakeRunner(t).ExpectArgs([]string{
gitCmd.OSCommand.Command = func(cmd string, args ...string) *exec.Cmd { "git", "log", "--graph", "--all", "--color=always", "--abbrev-commit", "--decorate", "--date=relative", "--pretty=medium",
assert.EqualValues(t, "git", cmd) }, "", nil)
assert.EqualValues(t, []string{"log", "--graph", "--all", "--color=always", "--abbrev-commit", "--decorate", "--date=relative", "--pretty=medium"}, args) gitCmd := NewDummyGitCommandWithRunner(runner)
return secureexec.Command("echo")
}
cmdStr := gitCmd.UserConfig.Git.AllBranchesLogCmd cmdStr := gitCmd.UserConfig.Git.AllBranchesLogCmd
_, err := gitCmd.Cmd.New(cmdStr).RunWithOutput() _, err := gitCmd.Cmd.New(cmdStr).RunWithOutput()
assert.NoError(t, err) assert.NoError(t, err)
} }
// TestGitCommandCurrentBranchName is a function.
func TestGitCommandCurrentBranchName(t *testing.T) { func TestGitCommandCurrentBranchName(t *testing.T) {
type scenario struct { type scenario struct {
testName string testName string
command func(string, ...string) *exec.Cmd runner *oscommands.FakeCmdObjRunner
test func(string, string, error) test func(string, string, error)
} }
scenarios := []scenario{ scenarios := []scenario{
{ {
"says we are on the master branch if we are", "says we are on the master branch if we are",
func(cmd string, args ...string) *exec.Cmd { oscommands.NewFakeRunner(t).Expect(`git symbolic-ref --short HEAD`, "master", nil),
assert.Equal(t, "git", cmd)
return secureexec.Command("echo", "master")
},
func(name string, displayname string, err error) { func(name string, displayname string, err error) {
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, "master", name) assert.EqualValues(t, "master", name)
@ -237,20 +179,9 @@ func TestGitCommandCurrentBranchName(t *testing.T) {
}, },
{ {
"falls back to git `git branch --contains` if symbolic-ref fails", "falls back to git `git branch --contains` if symbolic-ref fails",
func(cmd string, args ...string) *exec.Cmd { oscommands.NewFakeRunner(t).
assert.EqualValues(t, "git", cmd) Expect(`git symbolic-ref --short HEAD`, "", errors.New("error")).
Expect(`git branch --contains`, "* master", nil),
switch args[0] {
case "symbolic-ref":
assert.EqualValues(t, []string{"symbolic-ref", "--short", "HEAD"}, args)
return secureexec.Command("test")
case "branch":
assert.EqualValues(t, []string{"branch", "--contains"}, args)
return secureexec.Command("echo", "* master")
}
return nil
},
func(name string, displayname string, err error) { func(name string, displayname string, err error) {
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, "master", name) assert.EqualValues(t, "master", name)
@ -259,20 +190,9 @@ func TestGitCommandCurrentBranchName(t *testing.T) {
}, },
{ {
"handles a detached head", "handles a detached head",
func(cmd string, args ...string) *exec.Cmd { oscommands.NewFakeRunner(t).
assert.EqualValues(t, "git", cmd) Expect(`git symbolic-ref --short HEAD`, "", errors.New("error")).
Expect(`git branch --contains`, "* (HEAD detached at 123abcd)", nil),
switch args[0] {
case "symbolic-ref":
assert.EqualValues(t, []string{"symbolic-ref", "--short", "HEAD"}, args)
return secureexec.Command("test")
case "branch":
assert.EqualValues(t, []string{"branch", "--contains"}, args)
return secureexec.Command("echo", "* (HEAD detached at 123abcd)")
}
return nil
},
func(name string, displayname string, err error) { func(name string, displayname string, err error) {
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, "123abcd", name) assert.EqualValues(t, "123abcd", name)
@ -281,10 +201,9 @@ func TestGitCommandCurrentBranchName(t *testing.T) {
}, },
{ {
"bubbles up error if there is one", "bubbles up error if there is one",
func(cmd string, args ...string) *exec.Cmd { oscommands.NewFakeRunner(t).
assert.Equal(t, "git", cmd) Expect(`git symbolic-ref --short HEAD`, "", errors.New("error")).
return secureexec.Command("test") Expect(`git branch --contains`, "", errors.New("error")),
},
func(name string, displayname string, err error) { func(name string, displayname string, err error) {
assert.Error(t, err) assert.Error(t, err)
assert.EqualValues(t, "", name) assert.EqualValues(t, "", name)
@ -295,19 +214,18 @@ func TestGitCommandCurrentBranchName(t *testing.T) {
for _, s := range scenarios { for _, s := range scenarios {
t.Run(s.testName, func(t *testing.T) { t.Run(s.testName, func(t *testing.T) {
gitCmd := NewDummyGitCommand() gitCmd := NewDummyGitCommandWithRunner(s.runner)
gitCmd.OSCommand.Command = s.command
s.test(gitCmd.CurrentBranchName()) s.test(gitCmd.CurrentBranchName())
s.runner.CheckForMissingCalls()
}) })
} }
} }
// TestGitCommandResetHard is a function.
func TestGitCommandResetHard(t *testing.T) { func TestGitCommandResetHard(t *testing.T) {
type scenario struct { type scenario struct {
testName string testName string
ref string ref string
command func(string, ...string) *exec.Cmd runner *oscommands.FakeCmdObjRunner
test func(error) test func(error)
} }
@ -315,23 +233,17 @@ func TestGitCommandResetHard(t *testing.T) {
{ {
"valid case", "valid case",
"HEAD", "HEAD",
test.CreateMockCommand(t, []*test.CommandSwapper{ oscommands.NewFakeRunner(t).
{ Expect(`git reset --hard "HEAD"`, "", nil),
Expect: `git reset --hard HEAD`,
Replace: "echo",
},
}),
func(err error) { func(err error) {
assert.NoError(t, err) assert.NoError(t, err)
}, },
}, },
} }
gitCmd := NewDummyGitCommand()
for _, s := range scenarios { for _, s := range scenarios {
t.Run(s.testName, func(t *testing.T) { t.Run(s.testName, func(t *testing.T) {
gitCmd.OSCommand.Command = s.command gitCmd := NewDummyGitCommandWithRunner(s.runner)
s.test(gitCmd.ResetHard(s.ref)) s.test(gitCmd.ResetHard(s.ref))
}) })
} }

View File

@ -23,3 +23,12 @@ func NewDummyGitCommandWithOSCommand(osCommand *oscommands.OSCommand) *GitComman
GetCmdWriter: func() io.Writer { return ioutil.Discard }, GetCmdWriter: func() io.Writer { return ioutil.Discard },
} }
} }
func NewDummyGitCommandWithRunner(runner oscommands.ICmdObjRunner) *GitCommand {
builder := oscommands.NewDummyCmdObjBuilder(runner)
gitCommand := NewDummyGitCommand()
gitCommand.Cmd = builder
gitCommand.OSCommand.Cmd = builder
return gitCommand
}

View File

@ -9,6 +9,7 @@ import (
"time" "time"
"github.com/go-errors/errors" "github.com/go-errors/errors"
"github.com/jesseduffield/lazygit/pkg/commands/loaders"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/gui/filetree" "github.com/jesseduffield/lazygit/pkg/gui/filetree"
@ -75,7 +76,10 @@ func (c *GitCommand) BeforeAndAfterFileForRename(file *models.File) (*models.Fil
// all files, passing the --no-renames flag and then recursively call the function // all files, passing the --no-renames flag and then recursively call the function
// again for the before file and after file. // again for the before file and after file.
filesWithoutRenames := c.GetStatusFiles(GetStatusFileOptions{NoRenames: true}) filesWithoutRenames := loaders.
NewFileLoader(c.Common, c.Cmd, c.GitConfig).
GetStatusFiles(loaders.GetStatusFileOptions{NoRenames: true})
var beforeFile *models.File var beforeFile *models.File
var afterFile *models.File var afterFile *models.File
for _, f := range filesWithoutRenames { for _, f := range filesWithoutRenames {

View File

@ -223,3 +223,11 @@ func findDotGitDir(stat func(string) (os.FileInfo, error), readFile func(filenam
func VerifyInGitRepo(osCommand *oscommands.OSCommand) error { func VerifyInGitRepo(osCommand *oscommands.OSCommand) error {
return osCommand.Cmd.New("git rev-parse --git-dir").Run() return osCommand.Cmd.New("git rev-parse --git-dir").Run()
} }
func (c *GitCommand) GetDotGitDir() string {
return c.DotGitDir
}
func (c *GitCommand) GetCmd() oscommands.ICmdObjBuilder {
return c.Cmd
}

View File

@ -4,7 +4,6 @@ import (
"regexp" "regexp"
"strings" "strings"
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/common" "github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
@ -29,9 +28,14 @@ type BranchLoader struct {
reflogCommits []*models.Commit reflogCommits []*models.Commit
} }
type BranchLoaderGitCommand interface {
GetRawBranches() (string, error)
CurrentBranchName() (string, string, error)
}
func NewBranchLoader( func NewBranchLoader(
cmn *common.Common, cmn *common.Common,
gitCommand *commands.GitCommand, gitCommand BranchLoaderGitCommand,
reflogCommits []*models.Commit, reflogCommits []*models.Commit,
) *BranchLoader { ) *BranchLoader {
return &BranchLoader{ return &BranchLoader{
@ -43,10 +47,10 @@ func NewBranchLoader(
} }
// Load the list of branches for the current repo // Load the list of branches for the current repo
func (b *BranchLoader) Load() []*models.Branch { func (self *BranchLoader) Load() []*models.Branch {
branches := b.obtainBranches() branches := self.obtainBranches()
reflogBranches := b.obtainReflogBranches() reflogBranches := self.obtainReflogBranches()
// loop through reflog branches. If there is a match, merge them, then remove it from the branches and keep it in the reflog branches // loop through reflog branches. If there is a match, merge them, then remove it from the branches and keep it in the reflog branches
branchesWithRecency := make([]*models.Branch, 0) branchesWithRecency := make([]*models.Branch, 0)
@ -78,7 +82,7 @@ outer:
} }
} }
if !foundHead { if !foundHead {
currentBranchName, currentBranchDisplayName, err := b.getCurrentBranchName() currentBranchName, currentBranchDisplayName, err := self.getCurrentBranchName()
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -87,8 +91,8 @@ outer:
return branches return branches
} }
func (b *BranchLoader) obtainBranches() []*models.Branch { func (self *BranchLoader) obtainBranches() []*models.Branch {
output, err := b.getRawBranches() output, err := self.getRawBranches()
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -150,11 +154,11 @@ func (b *BranchLoader) obtainBranches() []*models.Branch {
// TODO: only look at the new reflog commits, and otherwise store the recencies in // TODO: only look at the new reflog commits, and otherwise store the recencies in
// int form against the branch to recalculate the time ago // int form against the branch to recalculate the time ago
func (b *BranchLoader) obtainReflogBranches() []*models.Branch { func (self *BranchLoader) obtainReflogBranches() []*models.Branch {
foundBranchesMap := map[string]bool{} foundBranchesMap := map[string]bool{}
re := regexp.MustCompile(`checkout: moving from ([\S]+) to ([\S]+)`) re := regexp.MustCompile(`checkout: moving from ([\S]+) to ([\S]+)`)
reflogBranches := make([]*models.Branch, 0, len(b.reflogCommits)) reflogBranches := make([]*models.Branch, 0, len(self.reflogCommits))
for _, commit := range b.reflogCommits { for _, commit := range self.reflogCommits {
if match := re.FindStringSubmatch(commit.Name); len(match) == 3 { if match := re.FindStringSubmatch(commit.Name); len(match) == 3 {
recency := utils.UnixToTimeAgo(commit.UnixTimestamp) recency := utils.UnixToTimeAgo(commit.UnixTimestamp)
for _, branchName := range match[1:] { for _, branchName := range match[1:] {

View File

@ -0,0 +1,57 @@
package loaders
import (
"fmt"
"strings"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/common"
)
type CommitFileLoader struct {
*common.Common
cmd oscommands.ICmdObjBuilder
}
func NewCommitFileLoader(common *common.Common, cmd oscommands.ICmdObjBuilder) *CommitFileLoader {
return &CommitFileLoader{
Common: common,
cmd: cmd,
}
}
// GetFilesInDiff get the specified commit files
func (self *CommitFileLoader) GetFilesInDiff(from string, to string, reverse bool) ([]*models.CommitFile, error) {
reverseFlag := ""
if reverse {
reverseFlag = " -R "
}
filenames, err := self.cmd.New(fmt.Sprintf("git diff --submodule --no-ext-diff --name-status -z --no-renames %s %s %s", reverseFlag, from, to)).RunWithOutput()
if err != nil {
return nil, err
}
return self.getCommitFilesFromFilenames(filenames), nil
}
// filenames string is something like "file1\nfile2\nfile3"
func (self *CommitFileLoader) getCommitFilesFromFilenames(filenames string) []*models.CommitFile {
commitFiles := make([]*models.CommitFile, 0)
lines := strings.Split(strings.TrimRight(filenames, "\x00"), "\x00")
n := len(lines)
for i := 0; i < n-1; i += 2 {
// typical result looks like 'A my_file' meaning my_file was added
changeStatus := lines[i]
name := lines[i+1]
commitFiles = append(commitFiles, &models.CommitFile{
Name: name,
ChangeStatus: changeStatus,
})
}
return commitFiles
}

View File

@ -9,7 +9,6 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/commands/types/enums" "github.com/jesseduffield/lazygit/pkg/commands/types/enums"
@ -37,20 +36,26 @@ type CommitLoader struct {
dotGitDir string dotGitDir string
} }
type CommitLoaderGitCommand interface {
CurrentBranchName() (string, string, error)
RebaseMode() (enums.RebaseMode, error)
GetCmd() oscommands.ICmdObjBuilder
GetDotGitDir() string
}
// making our dependencies explicit for the sake of easier testing // making our dependencies explicit for the sake of easier testing
func NewCommitLoader( func NewCommitLoader(
cmn *common.Common, cmn *common.Common,
gitCommand *commands.GitCommand, gitCommand CommitLoaderGitCommand,
osCommand *oscommands.OSCommand,
) *CommitLoader { ) *CommitLoader {
return &CommitLoader{ return &CommitLoader{
Common: cmn, Common: cmn,
cmd: gitCommand.Cmd, cmd: gitCommand.GetCmd(),
getCurrentBranchName: gitCommand.CurrentBranchName, getCurrentBranchName: gitCommand.CurrentBranchName,
getRebaseMode: gitCommand.RebaseMode, getRebaseMode: gitCommand.RebaseMode,
readFile: ioutil.ReadFile, readFile: ioutil.ReadFile,
walkFiles: filepath.Walk, walkFiles: filepath.Walk,
dotGitDir: gitCommand.DotGitDir, dotGitDir: gitCommand.GetDotGitDir(),
} }
} }

View File

@ -189,7 +189,7 @@ func TestGetCommits(t *testing.T) {
t.Run(scenario.testName, func(t *testing.T) { t.Run(scenario.testName, func(t *testing.T) {
builder := &CommitLoader{ builder := &CommitLoader{
Common: utils.NewDummyCommon(), Common: utils.NewDummyCommon(),
cmd: oscommands.NewCmdObjBuilderDummy(scenario.runner), cmd: oscommands.NewDummyCmdObjBuilder(scenario.runner),
getCurrentBranchName: func() (string, string, error) { getCurrentBranchName: func() (string, string, error) {
return scenario.currentBranchName, scenario.currentBranchName, nil return scenario.currentBranchName, scenario.currentBranchName, nil
}, },

View File

@ -1,36 +1,54 @@
package commands package loaders
import ( import (
"fmt" "fmt"
"strings" "strings"
"github.com/jesseduffield/lazygit/pkg/commands/git_config"
"github.com/jesseduffield/lazygit/pkg/commands/models" "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/jesseduffield/lazygit/pkg/utils"
) )
// GetStatusFiles git status files type FileLoader struct {
*common.Common
cmd oscommands.ICmdObjBuilder
gitConfig git_config.IGitConfig
getFileType func(string) string
}
func NewFileLoader(cmn *common.Common, cmd oscommands.ICmdObjBuilder, gitConfig git_config.IGitConfig) *FileLoader {
return &FileLoader{
Common: cmn,
cmd: cmd,
gitConfig: gitConfig,
getFileType: oscommands.FileType,
}
}
type GetStatusFileOptions struct { type GetStatusFileOptions struct {
NoRenames bool NoRenames bool
} }
func (c *GitCommand) GetStatusFiles(opts GetStatusFileOptions) []*models.File { func (self *FileLoader) GetStatusFiles(opts GetStatusFileOptions) []*models.File {
// check if config wants us ignoring untracked files // check if config wants us ignoring untracked files
untrackedFilesSetting := c.GitConfig.Get("status.showUntrackedFiles") untrackedFilesSetting := self.gitConfig.Get("status.showUntrackedFiles")
if untrackedFilesSetting == "" { if untrackedFilesSetting == "" {
untrackedFilesSetting = "all" untrackedFilesSetting = "all"
} }
untrackedFilesArg := fmt.Sprintf("--untracked-files=%s", untrackedFilesSetting) untrackedFilesArg := fmt.Sprintf("--untracked-files=%s", untrackedFilesSetting)
statuses, err := c.GitStatus(GitStatusOptions{NoRenames: opts.NoRenames, UntrackedFilesArg: untrackedFilesArg}) statuses, err := self.GitStatus(GitStatusOptions{NoRenames: opts.NoRenames, UntrackedFilesArg: untrackedFilesArg})
if err != nil { if err != nil {
c.Log.Error(err) self.Log.Error(err)
} }
files := []*models.File{} files := []*models.File{}
for _, status := range statuses { for _, status := range statuses {
if strings.HasPrefix(status.StatusString, "warning") { if strings.HasPrefix(status.StatusString, "warning") {
c.Log.Warningf("warning when calling git status: %s", status.StatusString) self.Log.Warningf("warning when calling git status: %s", status.StatusString)
continue continue
} }
change := status.Change change := status.Change
@ -52,7 +70,7 @@ func (c *GitCommand) GetStatusFiles(opts GetStatusFileOptions) []*models.File {
Added: unstagedChange == "A" || untracked, Added: unstagedChange == "A" || untracked,
HasMergeConflicts: hasMergeConflicts, HasMergeConflicts: hasMergeConflicts,
HasInlineMergeConflicts: hasInlineMergeConflicts, HasInlineMergeConflicts: hasInlineMergeConflicts,
Type: c.OSCommand.FileType(status.Name), Type: self.getFileType(status.Name),
ShortStatus: change, ShortStatus: change,
} }
files = append(files, file) files = append(files, file)
@ -74,13 +92,13 @@ type FileStatus struct {
PreviousName string PreviousName string
} }
func (c *GitCommand) GitStatus(opts GitStatusOptions) ([]FileStatus, error) { func (c *FileLoader) GitStatus(opts GitStatusOptions) ([]FileStatus, error) {
noRenamesFlag := "" noRenamesFlag := ""
if opts.NoRenames { if opts.NoRenames {
noRenamesFlag = " --no-renames" noRenamesFlag = " --no-renames"
} }
statusLines, err := c.Cmd.New(fmt.Sprintf("git status %s --porcelain -z %s", opts.UntrackedFilesArg, noRenamesFlag)).RunWithOutput() statusLines, err := c.cmd.New(fmt.Sprintf("git status %s --porcelain -z%s", opts.UntrackedFilesArg, noRenamesFlag)).RunWithOutput()
if err != nil { if err != nil {
return []FileStatus{}, err return []FileStatus{}, err
} }

View File

@ -0,0 +1,203 @@
package loaders
import (
"testing"
"github.com/jesseduffield/lazygit/pkg/commands/git_config"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/stretchr/testify/assert"
)
func TestGitCommandGetStatusFiles(t *testing.T) {
type scenario struct {
testName string
runner oscommands.ICmdObjRunner
expectedFiles []*models.File
}
scenarios := []scenario{
{
"No files found",
oscommands.NewFakeRunner(t).
Expect(`git status --untracked-files=yes --porcelain -z`, "", nil),
[]*models.File{},
},
{
"Several files found",
oscommands.NewFakeRunner(t).
Expect(
`git status --untracked-files=yes --porcelain -z`,
"MM file1.txt\x00A file3.txt\x00AM file2.txt\x00?? file4.txt\x00UU file5.txt",
nil,
),
[]*models.File{
{
Name: "file1.txt",
HasStagedChanges: true,
HasUnstagedChanges: true,
Tracked: true,
Added: false,
Deleted: false,
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "MM file1.txt",
Type: "file",
ShortStatus: "MM",
},
{
Name: "file3.txt",
HasStagedChanges: true,
HasUnstagedChanges: false,
Tracked: false,
Added: true,
Deleted: false,
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "A file3.txt",
Type: "file",
ShortStatus: "A ",
},
{
Name: "file2.txt",
HasStagedChanges: true,
HasUnstagedChanges: true,
Tracked: false,
Added: true,
Deleted: false,
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "AM file2.txt",
Type: "file",
ShortStatus: "AM",
},
{
Name: "file4.txt",
HasStagedChanges: false,
HasUnstagedChanges: true,
Tracked: false,
Added: true,
Deleted: false,
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "?? file4.txt",
Type: "file",
ShortStatus: "??",
},
{
Name: "file5.txt",
HasStagedChanges: false,
HasUnstagedChanges: true,
Tracked: true,
Added: false,
Deleted: false,
HasMergeConflicts: true,
HasInlineMergeConflicts: true,
DisplayString: "UU file5.txt",
Type: "file",
ShortStatus: "UU",
},
},
},
{
"File with new line char",
oscommands.NewFakeRunner(t).
Expect(`git status --untracked-files=yes --porcelain -z`, "MM a\nb.txt", nil),
[]*models.File{
{
Name: "a\nb.txt",
HasStagedChanges: true,
HasUnstagedChanges: true,
Tracked: true,
Added: false,
Deleted: false,
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "MM a\nb.txt",
Type: "file",
ShortStatus: "MM",
},
},
},
{
"Renamed files",
oscommands.NewFakeRunner(t).
Expect(
`git status --untracked-files=yes --porcelain -z`,
"R after1.txt\x00before1.txt\x00RM after2.txt\x00before2.txt",
nil,
),
[]*models.File{
{
Name: "after1.txt",
PreviousName: "before1.txt",
HasStagedChanges: true,
HasUnstagedChanges: false,
Tracked: true,
Added: false,
Deleted: false,
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "R before1.txt -> after1.txt",
Type: "file",
ShortStatus: "R ",
},
{
Name: "after2.txt",
PreviousName: "before2.txt",
HasStagedChanges: true,
HasUnstagedChanges: true,
Tracked: true,
Added: false,
Deleted: false,
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "RM before2.txt -> after2.txt",
Type: "file",
ShortStatus: "RM",
},
},
},
{
"File with arrow in name",
oscommands.NewFakeRunner(t).
Expect(
`git status --untracked-files=yes --porcelain -z`,
`?? a -> b.txt`,
nil,
),
[]*models.File{
{
Name: "a -> b.txt",
HasStagedChanges: false,
HasUnstagedChanges: true,
Tracked: false,
Added: true,
Deleted: false,
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "?? a -> b.txt",
Type: "file",
ShortStatus: "??",
},
},
},
}
for _, s := range scenarios {
t.Run(s.testName, func(t *testing.T) {
cmd := oscommands.NewDummyCmdObjBuilder(s.runner)
gitConfig := git_config.NewFakeGitConfig(map[string]string{"status.showUntrackedFiles": "yes"})
loader := &FileLoader{
Common: utils.NewDummyCommon(),
cmd: cmd,
gitConfig: gitConfig,
getFileType: func(string) string { return "file" },
}
assert.EqualValues(t, s.expectedFiles, loader.GetStatusFiles(GetStatusFileOptions{}))
})
}
}

View File

@ -1,43 +0,0 @@
package commands
import (
"fmt"
"strings"
"github.com/jesseduffield/lazygit/pkg/commands/models"
)
// GetFilesInDiff get the specified commit files
func (c *GitCommand) GetFilesInDiff(from string, to string, reverse bool) ([]*models.CommitFile, error) {
reverseFlag := ""
if reverse {
reverseFlag = " -R "
}
filenames, err := c.Cmd.New(fmt.Sprintf("git diff --submodule --no-ext-diff --name-status -z --no-renames %s %s %s", reverseFlag, from, to)).RunWithOutput()
if err != nil {
return nil, err
}
return c.getCommitFilesFromFilenames(filenames), nil
}
// filenames string is something like "file1\nfile2\nfile3"
func (c *GitCommand) getCommitFilesFromFilenames(filenames string) []*models.CommitFile {
commitFiles := make([]*models.CommitFile, 0)
lines := strings.Split(strings.TrimRight(filenames, "\x00"), "\x00")
n := len(lines)
for i := 0; i < n-1; i += 2 {
// typical result looks like 'A my_file' meaning my_file was added
changeStatus := lines[i]
name := lines[i+1]
commitFiles = append(commitFiles, &models.CommitFile{
Name: name,
ChangeStatus: changeStatus,
})
}
return commitFiles
}

View File

@ -1,227 +0,0 @@
package commands
import (
"os/exec"
"testing"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/secureexec"
"github.com/stretchr/testify/assert"
)
// TestGitCommandGetStatusFiles is a function.
func TestGitCommandGetStatusFiles(t *testing.T) {
type scenario struct {
testName string
command func(string, ...string) *exec.Cmd
test func([]*models.File)
}
scenarios := []scenario{
{
"No files found",
func(cmd string, args ...string) *exec.Cmd {
return secureexec.Command("echo")
},
func(files []*models.File) {
assert.Len(t, files, 0)
},
},
{
"Several files found",
func(cmd string, args ...string) *exec.Cmd {
return secureexec.Command(
"printf",
`MM file1.txt\0A file3.txt\0AM file2.txt\0?? file4.txt\0UU file5.txt`,
)
},
func(files []*models.File) {
assert.Len(t, files, 5)
expected := []*models.File{
{
Name: "file1.txt",
HasStagedChanges: true,
HasUnstagedChanges: true,
Tracked: true,
Added: false,
Deleted: false,
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "MM file1.txt",
Type: "other",
ShortStatus: "MM",
},
{
Name: "file3.txt",
HasStagedChanges: true,
HasUnstagedChanges: false,
Tracked: false,
Added: true,
Deleted: false,
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "A file3.txt",
Type: "other",
ShortStatus: "A ",
},
{
Name: "file2.txt",
HasStagedChanges: true,
HasUnstagedChanges: true,
Tracked: false,
Added: true,
Deleted: false,
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "AM file2.txt",
Type: "other",
ShortStatus: "AM",
},
{
Name: "file4.txt",
HasStagedChanges: false,
HasUnstagedChanges: true,
Tracked: false,
Added: true,
Deleted: false,
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "?? file4.txt",
Type: "other",
ShortStatus: "??",
},
{
Name: "file5.txt",
HasStagedChanges: false,
HasUnstagedChanges: true,
Tracked: true,
Added: false,
Deleted: false,
HasMergeConflicts: true,
HasInlineMergeConflicts: true,
DisplayString: "UU file5.txt",
Type: "other",
ShortStatus: "UU",
},
}
assert.EqualValues(t, expected, files)
},
},
{
"File with new line char",
func(cmd string, args ...string) *exec.Cmd {
return secureexec.Command(
"printf",
`MM a\nb.txt`,
)
},
func(files []*models.File) {
assert.Len(t, files, 1)
expected := []*models.File{
{
Name: "a\nb.txt",
HasStagedChanges: true,
HasUnstagedChanges: true,
Tracked: true,
Added: false,
Deleted: false,
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "MM a\nb.txt",
Type: "other",
ShortStatus: "MM",
},
}
assert.EqualValues(t, expected, files)
},
},
{
"Renamed files",
func(cmd string, args ...string) *exec.Cmd {
return secureexec.Command(
"printf",
`R after1.txt\0before1.txt\0RM after2.txt\0before2.txt`,
)
},
func(files []*models.File) {
assert.Len(t, files, 2)
expected := []*models.File{
{
Name: "after1.txt",
PreviousName: "before1.txt",
HasStagedChanges: true,
HasUnstagedChanges: false,
Tracked: true,
Added: false,
Deleted: false,
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "R before1.txt -> after1.txt",
Type: "other",
ShortStatus: "R ",
},
{
Name: "after2.txt",
PreviousName: "before2.txt",
HasStagedChanges: true,
HasUnstagedChanges: true,
Tracked: true,
Added: false,
Deleted: false,
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "RM before2.txt -> after2.txt",
Type: "other",
ShortStatus: "RM",
},
}
assert.EqualValues(t, expected, files)
},
},
{
"File with arrow in name",
func(cmd string, args ...string) *exec.Cmd {
return secureexec.Command(
"printf",
`?? a -> b.txt`,
)
},
func(files []*models.File) {
assert.Len(t, files, 1)
expected := []*models.File{
{
Name: "a -> b.txt",
HasStagedChanges: false,
HasUnstagedChanges: true,
Tracked: false,
Added: true,
Deleted: false,
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "?? a -> b.txt",
Type: "other",
ShortStatus: "??",
},
}
assert.EqualValues(t, expected, files)
},
},
}
for _, s := range scenarios {
t.Run(s.testName, func(t *testing.T) {
gitCmd := NewDummyGitCommand()
gitCmd.OSCommand.Command = s.command
s.test(gitCmd.GetStatusFiles(GetStatusFileOptions{}))
})
}
}

View File

@ -10,7 +10,7 @@ func NewDummyOSCommand() *OSCommand {
return NewOSCommand(utils.NewDummyCommon()) return NewOSCommand(utils.NewDummyCommon())
} }
func NewCmdObjBuilderDummy(runner ICmdObjRunner) ICmdObjBuilder { func NewDummyCmdObjBuilder(runner ICmdObjRunner) *CmdObjBuilder {
return &CmdObjBuilder{ return &CmdObjBuilder{
runner: runner, runner: runner,
logCmdObj: func(ICmdObj) {}, logCmdObj: func(ICmdObj) {},

View File

@ -36,9 +36,11 @@ func (self *FakeCmdObjRunner) RunWithOutput(cmdObj ICmdObj) (string, error) {
} }
expectedCmd := self.expectedCmds[self.expectedCmdIndex] expectedCmd := self.expectedCmds[self.expectedCmdIndex]
output, err := expectedCmd(cmdObj)
self.expectedCmdIndex++ self.expectedCmdIndex++
return expectedCmd(cmdObj) return output, err
} }
func (self *FakeCmdObjRunner) RunAndProcessLines(cmdObj ICmdObj, onLine func(line string) (bool, error)) error { func (self *FakeCmdObjRunner) RunAndProcessLines(cmdObj ICmdObj, onLine func(line string) (bool, error)) error {
@ -72,13 +74,29 @@ func (self *FakeCmdObjRunner) ExpectFunc(fn func(cmdObj ICmdObj) (string, error)
func (self *FakeCmdObjRunner) Expect(expectedCmdStr string, output string, err error) *FakeCmdObjRunner { func (self *FakeCmdObjRunner) Expect(expectedCmdStr string, output string, err error) *FakeCmdObjRunner {
self.ExpectFunc(func(cmdObj ICmdObj) (string, error) { self.ExpectFunc(func(cmdObj ICmdObj) (string, error) {
cmdStr := cmdObj.ToString() cmdStr := cmdObj.ToString()
if cmdStr != expectedCmdStr {
assert.Equal(self.t, expectedCmdStr, cmdStr, fmt.Sprintf("expected command %d to be %s, but was %s", self.expectedCmdIndex+1, expectedCmdStr, cmdStr)) assert.Equal(self.t, expectedCmdStr, cmdStr, fmt.Sprintf("expected command %d to be %s, but was %s", self.expectedCmdIndex+1, expectedCmdStr, cmdStr))
return "", errors.New("expected cmd")
}
return output, err return output, err
}) })
return self return self
} }
func (self *FakeCmdObjRunner) ExpectArgs(expectedArgs []string, output string, err error) *FakeCmdObjRunner {
self.ExpectFunc(func(cmdObj ICmdObj) (string, error) {
args := cmdObj.GetCmd().Args
assert.EqualValues(self.t, expectedArgs, args, fmt.Sprintf("command %d did not match expectation", self.expectedCmdIndex+1))
return output, err
})
return self
}
func (self *FakeCmdObjRunner) CheckForMissingCalls() {
if self.expectedCmdIndex < len(self.expectedCmds) {
self.t.Errorf("expected command %d to be called, but was not", self.expectedCmdIndex+1)
}
return
}

View File

@ -137,7 +137,7 @@ func (c *OSCommand) SetRemoveFile(f func(string) error) {
} }
// FileType tells us if the file is a file, directory or other // FileType tells us if the file is a file, directory or other
func (c *OSCommand) FileType(path string) string { func FileType(path string) string {
fileInfo, err := os.Stat(path) fileInfo, err := os.Stat(path)
if err != nil { if err != nil {
return "other" return "other"

View File

@ -164,7 +164,7 @@ func TestOSCommandFileType(t *testing.T) {
for _, s := range scenarios { for _, s := range scenarios {
s.setup() s.setup()
s.test(NewDummyOSCommand().FileType(s.path)) s.test(FileType(s.path))
_ = os.RemoveAll(s.path) _ = os.RemoveAll(s.path)
} }
} }

View File

@ -1,6 +1,10 @@
package commands package commands
import "fmt" import (
"fmt"
"github.com/jesseduffield/lazygit/pkg/commands/loaders"
)
// StashDo modify stash // StashDo modify stash
func (c *GitCommand) StashDo(index int, method string) error { func (c *GitCommand) StashDo(index int, method string) error {
@ -45,7 +49,10 @@ func (c *GitCommand) StashSaveStagedChanges(message string) error {
// if you had staged an untracked file, that will now appear as 'AD' in git status // if you had staged an untracked file, that will now appear as 'AD' in git status
// meaning it's deleted in your working tree but added in your index. Given that it's // meaning it's deleted in your working tree but added in your index. Given that it's
// now safely stashed, we need to remove it. // now safely stashed, we need to remove it.
files := c.GetStatusFiles(GetStatusFileOptions{}) files := loaders.
NewFileLoader(c.Common, c.Cmd, c.GitConfig).
GetStatusFiles(loaders.GetStatusFileOptions{})
for _, file := range files { for _, file := range files {
if file.ShortStatus == "AD" { if file.ShortStatus == "AD" {
if err := c.UnStageFile(file.Names(), false); err != nil { if err := c.UnStageFile(file.Names(), false); err != nil {

View File

@ -1,6 +1,7 @@
package gui package gui
import ( import (
"github.com/jesseduffield/lazygit/pkg/commands/loaders"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/patch" "github.com/jesseduffield/lazygit/pkg/commands/patch"
"github.com/jesseduffield/lazygit/pkg/gui/filetree" "github.com/jesseduffield/lazygit/pkg/gui/filetree"
@ -105,7 +106,7 @@ func (gui *Gui) refreshCommitFilesView() error {
to := gui.State.Panels.CommitFiles.refName to := gui.State.Panels.CommitFiles.refName
from, reverse := gui.getFromAndReverseArgsForDiff(to) from, reverse := gui.getFromAndReverseArgsForDiff(to)
files, err := gui.GitCommand.GetFilesInDiff(from, to, reverse) files, err := loaders.NewCommitFileLoader(gui.Common, gui.GitCommand.Cmd).GetFilesInDiff(from, to, reverse)
if err != nil { if err != nil {
return gui.surfaceError(err) return gui.surfaceError(err)
} }

View File

@ -119,7 +119,7 @@ func (gui *Gui) refreshCommitsWithLimit() error {
gui.Mutexes.BranchCommitsMutex.Lock() gui.Mutexes.BranchCommitsMutex.Lock()
defer gui.Mutexes.BranchCommitsMutex.Unlock() defer gui.Mutexes.BranchCommitsMutex.Unlock()
loader := loaders.NewCommitLoader(gui.Common, gui.GitCommand, gui.OSCommand) loader := loaders.NewCommitLoader(gui.Common, gui.GitCommand)
commits, err := loader.GetCommits( commits, err := loader.GetCommits(
loaders.GetCommitsOptions{ loaders.GetCommitsOptions{
@ -142,7 +142,7 @@ func (gui *Gui) refreshRebaseCommits() error {
gui.Mutexes.BranchCommitsMutex.Lock() gui.Mutexes.BranchCommitsMutex.Lock()
defer gui.Mutexes.BranchCommitsMutex.Unlock() defer gui.Mutexes.BranchCommitsMutex.Unlock()
loader := loaders.NewCommitLoader(gui.Common, gui.GitCommand, gui.OSCommand) loader := loaders.NewCommitLoader(gui.Common, gui.GitCommand)
updatedCommits, err := loader.MergeRebasingCommits(gui.State.Commits) updatedCommits, err := loader.MergeRebasingCommits(gui.State.Commits)
if err != nil { if err != nil {

View File

@ -7,6 +7,7 @@ import (
"github.com/jesseduffield/gocui" "github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/loaders"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/config"
@ -553,7 +554,9 @@ func (gui *Gui) refreshStateFiles() error {
prevNodes := gui.State.FileManager.GetAllItems() prevNodes := gui.State.FileManager.GetAllItems()
prevSelectedLineIdx := gui.State.Panels.Files.SelectedLineIdx prevSelectedLineIdx := gui.State.Panels.Files.SelectedLineIdx
files := gui.GitCommand.GetStatusFiles(commands.GetStatusFileOptions{}) files := loaders.
NewFileLoader(gui.Common, gui.GitCommand.Cmd, gui.GitCommand.GitConfig).
GetStatusFiles(loaders.GetStatusFileOptions{})
// for when you stage the old file of a rename and the new file is in a collapsed dir // for when you stage the old file of a rename and the new file is in a collapsed dir
state.FileManager.RWMutex.Lock() state.FileManager.RWMutex.Lock()

View File

@ -75,7 +75,7 @@ func (gui *Gui) handleViewSubCommitFiles() error {
func (gui *Gui) switchToSubCommitsContext(refName string) error { func (gui *Gui) switchToSubCommitsContext(refName string) error {
// need to populate my sub commits // need to populate my sub commits
loader := loaders.NewCommitLoader(gui.Common, gui.GitCommand, gui.OSCommand) loader := loaders.NewCommitLoader(gui.Common, gui.GitCommand)
commits, err := loader.GetCommits( commits, err := loader.GetCommits(
loaders.GetCommitsOptions{ loaders.GetCommitsOptions{