diff options
28 files changed, 990 insertions, 347 deletions
diff --git a/pkg/git/branch_list_builder.go b/pkg/commands/branch_list_builder.go index 09c95ba97..d7a232055 100644 --- a/pkg/git/branch_list_builder.go +++ b/pkg/commands/branch_list_builder.go @@ -1,10 +1,9 @@ -package git +package commands import ( "regexp" "strings" - "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/utils" "github.com/sirupsen/logrus" @@ -26,28 +25,28 @@ import ( // BranchListBuilder returns a list of Branch objects for the current repo type BranchListBuilder struct { Log *logrus.Entry - GitCommand *commands.GitCommand + GitCommand *GitCommand } // NewBranchListBuilder builds a new branch list builder -func NewBranchListBuilder(log *logrus.Entry, gitCommand *commands.GitCommand) (*BranchListBuilder, error) { +func NewBranchListBuilder(log *logrus.Entry, gitCommand *GitCommand) (*BranchListBuilder, error) { return &BranchListBuilder{ Log: log, GitCommand: gitCommand, }, nil } -func (b *BranchListBuilder) obtainCurrentBranch() *commands.Branch { +func (b *BranchListBuilder) obtainCurrentBranch() *Branch { branchName, err := b.GitCommand.CurrentBranchName() if err != nil { panic(err.Error()) } - return &commands.Branch{Name: strings.TrimSpace(branchName)} + return &Branch{Name: strings.TrimSpace(branchName)} } -func (b *BranchListBuilder) obtainReflogBranches() []*commands.Branch { - branches := make([]*commands.Branch, 0) +func (b *BranchListBuilder) obtainReflogBranches() []*Branch { + branches := make([]*Branch, 0) rawString, err := b.GitCommand.OSCommand.RunCommandWithOutput("git reflog -n100 --pretty='%cr|%gs' --grep-reflog='checkout: moving' HEAD") if err != nil { return branches @@ -57,14 +56,14 @@ func (b *BranchListBuilder) obtainReflogBranches() []*commands.Branch { for _, line := range branchLines { timeNumber, timeUnit, branchName := branchInfoFromLine(line) timeUnit = abbreviatedTimeUnit(timeUnit) - branch := &commands.Branch{Name: branchName, Recency: timeNumber + timeUnit} + branch := &Branch{Name: branchName, Recency: timeNumber + timeUnit} branches = append(branches, branch) } return uniqueByName(branches) } -func (b *BranchListBuilder) obtainSafeBranches() []*commands.Branch { - branches := make([]*commands.Branch, 0) +func (b *BranchListBuilder) obtainSafeBranches() []*Branch { + branches := make([]*Branch, 0) bIter, err := b.GitCommand.Repo.Branches() if err != nil { @@ -72,14 +71,14 @@ func (b *BranchListBuilder) obtainSafeBranches() []*commands.Branch { } bIter.ForEach(func(b *plumbing.Reference) error { name := b.Name().Short() - branches = append(branches, &commands.Branch{Name: name}) + branches = append(branches, &Branch{Name: name}) return nil }) return branches } -func (b *BranchListBuilder) appendNewBranches(finalBranches, newBranches, existingBranches []*commands.Branch, included bool) []*commands.Branch { +func (b *BranchListBuilder) appendNewBranches(finalBranches, newBranches, existingBranches []*Branch, included bool) []*Branch { for _, newBranch := range newBranches { if included == branchIncluded(newBranch.Name, existingBranches) { finalBranches = append(finalBranches, newBranch) @@ -88,7 +87,7 @@ func (b *BranchListBuilder) appendNewBranches(finalBranches, newBranches, existi return finalBranches } -func sanitisedReflogName(reflogBranch *commands.Branch, safeBranches []*commands.Branch) string { +func sanitisedReflogName(reflogBranch *Branch, safeBranches []*Branch) string { for _, safeBranch := range safeBranches { if strings.ToLower(safeBranch.Name) == strings.ToLower(reflogBranch.Name) { return safeBranch.Name @@ -98,8 +97,8 @@ func sanitisedReflogName(reflogBranch *commands.Branch, safeBranches []*commands } // Build the list of branches for the current repo -func (b *BranchListBuilder) Build() []*commands.Branch { - branches := make([]*commands.Branch, 0) +func (b *BranchListBuilder) Build() []*Branch { + branches := make([]*Branch, 0) head := b.obtainCurrentBranch() safeBranches := b.obtainSafeBranches() @@ -112,7 +111,7 @@ func (b *BranchListBuilder) Build() []*commands.Branch { branches = b.appendNewBranches(branches, safeBranches, branches, false) if len(branches) == 0 || branches[0].Name != head.Name { - branches = append([]*commands.Branch{head}, branches...) + branches = append([]*Branch{head}, branches...) } branches[0].Recency = " *" @@ -120,7 +119,7 @@ func (b *BranchListBuilder) Build() []*commands.Branch { return branches } -func branchIncluded(branchName string, branches []*commands.Branch) bool { +func branchIncluded(branchName string, branches []*Branch) bool { for _, existingBranch := range branches { if strings.ToLower(existingBranch.Name) == strings.ToLower(branchName) { return true @@ -129,8 +128,8 @@ func branchIncluded(branchName string, branches []*commands.Branch) bool { return false } -func uniqueByName(branches []*commands.Branch) []*commands.Branch { - finalBranches := make([]*commands.Branch, 0) +func uniqueByName(branches []*Branch) []*Branch { + finalBranches := make([]*Branch, 0) for _, branch := range branches { if branchIncluded(branch.Name, finalBranches) { continue diff --git a/pkg/commands/commit_file.go b/pkg/commands/commit_file.go index 8bc6a11c2..ddd09b23b 100644 --- a/pkg/commands/commit_file.go +++ b/pkg/commands/commit_file.go @@ -1,13 +1,42 @@ package commands +import ( + "github.com/fatih/color" + "github.com/jesseduffield/lazygit/pkg/theme" +) + // CommitFile : A git commit file type CommitFile struct { Sha string Name string DisplayString string + Status int // one of 'WHOLE' 'PART' 'NONE' } +const ( + // UNSELECTED is for when the commit file has not been added to the patch in any way + UNSELECTED = iota + // WHOLE is for when you want to add the whole diff of a file to the patch, + // including e.g. if it was deleted + WHOLE = iota + // PART is for when you're only talking about specific lines that have been modified + PART +) + // GetDisplayStrings is a function. func (f *CommitFile) GetDisplayStrings(isFocused bool) []string { - return []string{f.DisplayString} + yellow := color.New(color.FgYellow) + green := color.New(color.FgGreen) + defaultColor := color.New(theme.DefaultTextColor) + + var colour *color.Color + switch f.Status { + case UNSELECTED: + colour = defaultColor + case WHOLE: + colour = green + case PART: + colour = yellow + } + return []string{colour.Sprint(f.DisplayString)} } diff --git a/pkg/git/commit_list_builder.go b/pkg/commands/commit_list_builder.go index a47fcbfe2..aab6de6a3 100644 --- a/pkg/git/commit_list_builder.go +++ b/pkg/commands/commit_list_builder.go @@ -1,4 +1,4 @@ -package git +package commands import ( "fmt" @@ -9,7 +9,6 @@ import ( "strings" "github.com/fatih/color" - "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/i18n" "github.com/jesseduffield/lazygit/pkg/utils" "github.com/sirupsen/logrus" @@ -27,15 +26,15 @@ import ( // CommitListBuilder returns a list of Branch objects for the current repo type CommitListBuilder struct { Log *logrus.Entry - GitCommand *commands.GitCommand - OSCommand *commands.OSCommand + GitCommand *GitCommand + OSCommand *OSCommand Tr *i18n.Localizer - CherryPickedCommits []*commands.Commit - DiffEntries []*commands.Commit + CherryPickedCommits []*Commit + DiffEntries []*Commit } // NewCommitListBuilder builds a new commit list builder -func NewCommitListBuilder(log *logrus.Entry, gitCommand *commands.GitCommand, osCommand *commands.OSCommand, tr *i18n.Localizer, cherryPickedCommits []*commands.Commit, diffEntries []*commands.Commit) (*CommitListBuilder, error) { +func NewCommitListBuilder(log *logrus.Entry, gitCommand *GitCommand, osCommand *OSCommand, tr *i18n.Localizer, cherryPickedCommits []*Commit, diffEntries []*Commit) (*CommitListBuilder, error) { return &CommitListBuilder{ Log: log, GitCommand: gitCommand, @@ -47,9 +46,9 @@ func NewCommitListBuilder(log *logrus.Entry, gitCommand *commands.GitCommand, os } // GetCommits obtains the commits of the current branch -func (c *CommitListBuilder) GetCommits() ([]*commands.Commit, error) { - commits := []*commands.Commit{} - var rebasingCommits []*commands.Commit +func (c *CommitListBuilder) GetCommits() ([]*Commit, error) { + commits := []*Commit{} + var rebasingCommits []*Commit rebaseMode, err := c.GitCommand.RebaseMode() if err != nil { return nil, err @@ -74,7 +73,7 @@ func (c *CommitListBuilder) GetCommits() ([]*commands.Commit, error) { sha := splitLine[0] _, unpushed := unpushedCommits[sha] status := map[bool]string{true: "unpushed", false: "pushed"}[unpushed] - commits = append(commits, &commands.Commit{ + commits = append(commits, &Commit{ Sha: sha, Name: strings.Join(splitLine[1:], " "), Status: status, @@ -110,7 +109,7 @@ func (c *CommitListBuilder) GetCommits() ([]*commands.Commit, error) { } // getRebasingCommits obtains the commits that we're in the process of rebasing -func (c *CommitListBuilder) getRebasingCommits(rebaseMode string) ([]*commands.Commit, error) { +func (c *CommitListBuilder) getRebasingCommits(rebaseMode string) ([]*Commit, error) { switch rebaseMode { case "normal": return c.getNormalRebasingCommits() @@ -121,7 +120,7 @@ func (c *CommitListBuilder) getRebasingCommits(rebaseMode string) ([]*commands.C } } -func (c *CommitListBuilder) getNormalRebasingCommits() ([]*commands.Commit, error) { +func (c *CommitListBuilder) getNormalRebasingCommits() ([]*Commit, error) { rewrittenCount := 0 bytesContent, err := ioutil.ReadFile(fmt.Sprintf("%s/rebase-apply/rewritten", c.GitCommand.DotGitDir)) if err == nil { @@ -130,7 +129,7 @@ func (c *CommitListBuilder) getNormalRebasingCommits() ([]*commands.Commit, erro } // we know we're rebasing, so lets get all the files whose names have numbers - commits := []*commands.Commit{} + commits := []*Commit{} err = filepath.Walk(fmt.Sprintf("%s/rebase-apply", c.GitCommand.DotGitDir), func(path string, f os.FileInfo, err error) error { if rewrittenCount > 0 { rewrittenCount-- @@ -152,7 +151,7 @@ func (c *CommitListBuilder) getNormalRebasingCommits() ([]*commands.Commit, erro if err != nil { return err } - commits = append([]*commands.Commit{commit}, commits...) + commits = append([]*Commit{commit}, commits...) return nil }) if err != nil { @@ -174,7 +173,7 @@ func (c *CommitListBuilder) getNormalRebasingCommits() ([]*commands.Commit, erro // getInteractiveRebasingCommits takes our git-rebase-todo and our git-rebase-todo.backup files // and extracts out the sha and names of commits that we still have to go // in the rebase: -func (c *CommitListBuilder) getInteractiveRebasingCommits() ([]*commands.Commit, error) { +func (c *CommitListBuilder) getInteractiveRebasingCommits() ([]*Commit, error) { bytesContent, err := ioutil.ReadFile(fmt.Sprintf("%s/rebase-merge/git-rebase-todo", c.GitCommand.DotGitDir)) if err != nil { c.Log.Info(fmt.Sprintf("error occurred reading git-rebase-todo: %s", err.Error())) @@ -182,14 +181,14 @@ func (c *CommitListBuilder) getInteractiveRebasingCommits() ([]*commands.Commit, return nil, nil } - commits := []*commands.Commit{} + commits := []*Commit{} lines := strings.Split(string(bytesContent), "\n") for _, line := range lines { if line == "" || line == "noop" { return commits, nil } splitLine := strings.Split(line, " ") - commits = append([]*commands.Commit{{ + commits = append([]*Commit{{ Sha: splitLine[1][0:7], Name: strings.Join(splitLine[2:], " "), Status: "rebasing", @@ -205,18 +204,18 @@ func (c *CommitListBuilder) getInteractiveRebasingCommits() ([]*commands.Commit, // From: Lazygit Tester <test@example.com> // Date: Wed, 5 Dec 2018 21:03:23 +1100 // Subject: second commit on master -func (c *CommitListBuilder) commitFromPatch(content string) (*commands.Commit, error) { +func (c *CommitListBuilder) commitFromPatch(content string) (*Commit, error) { lines := strings.Split(content, "\n") sha := strings.Split(lines[0], " ")[1][0:7] name := strings.TrimPrefix(lines[3], "Subject: ") - return &commands.Commit{ + return &Commit{ Sha: sha, Name: name, Status: "rebasing", }, nil } -func (c *CommitListBuilder) setCommitMergedStatuses(commits []*commands.Commit) ([]*commands.Commit, error) { +func (c *CommitListBuilder) setCommitMergedStatuses(commits []*Commit) ([]*Commit, error) { ancestor, err := c.getMergeBase() if err != nil { return nil, err @@ -239,7 +238,7 @@ func (c *CommitListBuilder) setCommitMergedStatuses(commits []*commands.Commit) return commits, nil } -func (c *CommitListBuilder) setCommitCherryPickStatuses(commits []*commands.Commit) ([]*commands.Commit, error) { +func (c *CommitListBuilder) setCommitCherryPickStatuses(commits []*Commit) ([]*Commit, error) { for _, commit := range commits { for _, cherryPickedCommit := range c.CherryPickedCommits { if commit.Sha == cherryPickedCommit.Sha { diff --git a/pkg/git/commit_list_builder_test.go b/pkg/commands/commit_list_builder_test.go index 81bb7b3cb..cdd360ce8 100644 --- a/pkg/git/commit_list_builder_test.go +++ b/pkg/commands/commit_list_builder_test.go @@ -1,24 +1,23 @@ -package git +package commands import ( "os/exec" "testing" - "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/i18n" "github.com/stretchr/testify/assert" ) // NewDummyCommitListBuilder creates a new dummy CommitListBuilder for testing func NewDummyCommitListBuilder() *CommitListBuilder { - osCommand := commands.NewDummyOSCommand() + osCommand := NewDummyOSCommand() return &CommitListBuilder{ - Log: commands.NewDummyLog(), - GitCommand: commands.NewDummyGitCommandWithOSCommand(osCommand), + Log: NewDummyLog(), + GitCommand: NewDummyGitCommandWithOSCommand(osCommand), OSCommand: osCommand, - Tr: i18n.NewLocalizer(commands.NewDummyLog()), - CherryPickedCommits: []*commands.Commit{}, + Tr: i18n.NewLocalizer(NewDummyLog()), + CherryPickedCommits: []*Commit{}, } } @@ -199,7 +198,7 @@ func TestCommitListBuilderGetCommits(t *testing.T) { type scenario struct { testName string command func(string, ...string) *exec.Cmd - test func([]*commands.Commit, error) + test func([]*Commit, error) } scenarios := []scenario{ @@ -225,7 +224,7 @@ func TestCommitListBuilderGetCommits(t *testing.T) { return nil }, - func(commits []*commands.Commit, err error) { + func(commits []*Commit, err error) { assert.NoError(t, err) assert.Len(t, commits, 0) }, @@ -252,10 +251,10 @@ func TestCommitListBuilderGetCommits(t *testing.T) { return nil }, - func(commits []*commands.Commit, err error) { + func(commits []*Commit, err error) { assert.NoError(t, err) assert.Len(t, commits, 2) - assert.EqualValues(t, []*commands.Commit{ + assert.EqualValues(t, []*Commit{ { Sha: "8a2bb0e", Name: "commit 1", @@ -298,7 +297,7 @@ func TestCommitListBuilderGetCommits(t *testing.T) { return nil }, - func(commits []*commands.Commit, err error) { + func(commits []*Commit, err error) { assert.Error(t, err) assert.Len(t, commits, 0) }, diff --git a/pkg/commands/git.go b/pkg/commands/git.go index 6e86fe0b5..815c84423 100644 --- a/pkg/commands/git.go +++ b/pkg/commands/git.go @@ -63,16 +63,17 @@ func setupRepositoryAndWorktree(openGitRepository func(string) (*gogit.Repositor // GitCommand is our main git interface type GitCommand struct { - Log *logrus.Entry - OSCommand *OSCommand - Worktree *gogit.Worktree - Repo *gogit.Repository - Tr *i18n.Localizer - Config config.AppConfigurer - getGlobalGitConfig func(string) (string, error) - getLocalGitConfig func(string) (string, error) - removeFile func(string) error - DotGitDir string + Log *logrus.Entry + OSCommand *OSCommand + Worktree *gogit.Worktree + Repo *gogit.Repository + Tr *i18n.Localizer + Config config.AppConfigurer + getGlobalGitConfig func(string) (string, error) + getLocalGitConfig func(string) (string, error) + removeFile func(string) error + DotGitDir string + onSuccessfulContinue func() error } // NewGitCommand it runs git commands @@ -376,7 +377,7 @@ func (c *GitCommand) Commit(message string, flags string) (*exec.Cmd, error) { // AmendHead amends HEAD with whatever is staged in your working tree func (c *GitCommand) AmendHead() (*exec.Cmd, error) { - command := "git commit --amend --no-edit" + command := "git commit --amend --no-edit --allow-empty" if c.usingGpg() { return c.OSCommand.PrepareSubProcess(c.OSCommand.Platform.shell, c.OSCommand.Platform.shellArg, command), nil } @@ -530,7 +531,7 @@ func (c *GitCommand) Ignore(filename string) error { // Show shows the diff of a commit func (c *GitCommand) Show(sha string) (string, error) { - show, err := c.OSCommand.RunCommandWithOutput(fmt.Sprintf("git show --color %s", sha)) + show, err := c.OSCommand.RunCommandWithOutput(fmt.Sprintf("git show --color --no-renames %s", sha)) if err != nil { return "", err } @@ -605,11 +606,11 @@ func (c *GitCommand) Diff(file *File, plain bool, cached bool) string { return s } -func (c *GitCommand) ApplyPatch(patch string, reverse bool, cached bool) (string, error) { +func (c *GitCommand) ApplyPatch(patch string, reverse bool, cached bool, extraFlags string) error { filename, err := c.OSCommand.CreateTempFile("patch", patch) if err != nil { c.Log.Error(err) - return "", err + return err } defer func() { _ = c.OSCommand.Remove(filename) }() @@ -624,7 +625,7 @@ func (c *GitCommand) ApplyPatch(patch string, reverse bool, cached bool) (string cachedFlag = "--cached" } - return c.OSCommand.RunCommandWithOutput(fmt.Sprintf("git apply %s %s %s", cachedFlag, reverseFlag, c.OSCommand.Quote(filename))) + return c.OSCommand.RunCommand(fmt.Sprintf("git apply %s %s %s %s", cachedFlag, reverseFlag, extraFlags, c.OSCommand.Quote(filename))) } func (c *GitCommand) FastForward(branchName string) error { @@ -645,13 +646,29 @@ func (c *GitCommand) RunSkipEditorCommand(command string) error { // GenericMerge takes a commandType of "merge" or "rebase" and a command of "abort", "skip" or "continue" // By default we skip the editor in the case where a commit will be made func (c *GitCommand) GenericMerge(commandType string, command string) error { - return c.RunSkipEditorCommand( + err := c.RunSkipEditorCommand( fmt.Sprintf( "git %s --%s", commandType, command, ), ) + if err != nil { + return err + } + + // sometimes we need to do a sequence of things in a rebase but the user needs to + // fix merge conflicts along the way. When this happens we queue up the next step + // so that after the next successful rebase continue we can continue from where we left off + if commandType == "rebase" && command == "continue" && c.onSuccessfulContinue != nil { + f := c.onSuccessfulContinue + c.onSuccessfulContinue = nil + return f() + } + if command == "abort" { + c.onSuccessfulContinue = nil + } + return nil } func (c *GitCommand) RewordCommit(commits []*Commit, index int) (*exec.Cmd, error) { @@ -852,8 +869,8 @@ func (c *GitCommand) CherryPickCommits(commits []*Commit) error { } // GetCommitFiles get the specified commit files -func (c *GitCommand) GetCommitFiles(commitSha string) ([]*CommitFile, error) { - cmd := fmt.Sprintf("git show --pretty= --name-only %s", commitSha) +func (c *GitCommand) GetCommitFiles(commitSha string, patchManager *PatchManager) ([]*CommitFile, error) { + cmd := fmt.Sprintf("git show --pretty= --name-only --no-renames %s", commitSha) files, err := c.OSCommand.RunCommandWithOutput(cmd) if err != nil { return nil, err @@ -862,10 +879,16 @@ func (c *GitCommand) GetCommitFiles(commitSha string) ([]*CommitFile, error) { commitFiles := make([]*CommitFile, 0) for _, file := range strings.Split(strings.TrimRight(files, "\n"), "\n") { + status := UNSELECTED + if patchManager != nil && patchManager.CommitSha == commitSha { + status = patchManager.GetFileStatus(file) + } + commitFiles = append(commitFiles, &CommitFile{ Sha: commitSha, Name: file, DisplayString: file, + Status: status, }) } @@ -873,8 +896,12 @@ func (c *GitCommand) GetCommitFiles(commitSha string) ([]*CommitFile, error) { } // ShowCommitFile get the diff of specified commit file -func (c *GitCommand) ShowCommitFile(commitSha, fileName string) (string, error) { - cmd := fmt.Sprintf("git show --color %s -- %s", commitSha, fileName) +func (c *GitCommand) ShowCommitFile(commitSha, fileName string, plain bool) (string, error) { + colorArg := "--color" + if plain { + colorArg = "" + } + cmd := fmt.Sprintf("git show --no-renames %s %s -- %s", colorArg, commitSha, fileName) return c.OSCommand.RunCommandWithOutput(cmd) } @@ -886,28 +913,7 @@ func (c *GitCommand) CheckoutFile(commitSha, fileName string) error { // DiscardOldFileChanges discards changes to a file from an old commit func (c *GitCommand) DiscardOldFileChanges(commits []*Commit, commitIndex int, fileName string) error { - if len(commits)-1 < commitIndex { - return errors.New("index outside of range of commits") - } - - // we can make this GPG thing possible it just means we need to do this in two parts: - // one where we handle the possibility of a credential request, and the other - // where we continue the rebase - if c.usingGpg() { - return errors.New(c.Tr.SLocalize("DisabledForGPG")) - } - - todo, sha, err := c.GenerateGenericRebaseTodo(commits, commitIndex, "edit") - if err != nil { - return err - } - - cmd, err := c.PrepareInteractiveRebaseCommand(sha, todo, true) - if err != nil { - return err - } - - if err := c.OSCommand.RunPreparedCommand(cmd); err != nil { + if err := c.BeginInteractiveRebaseForCommit(commits, commitIndex); err != nil { return err } @@ -924,7 +930,7 @@ func (c *GitCommand) DiscardOldFileChanges(commits []*Commit, commitIndex int, f } // amend the commit - cmd, err = c.AmendHead() + cmd, err := c.AmendHead() if cmd != nil { return errors.New("received unexpected pointer to cmd") } @@ -1016,3 +1022,34 @@ func (c *GitCommand) StashSaveStagedChanges(message string) error { return nil } + +// BeginInteractiveRebaseForCommit starts an interactive rebase to edit the current +// commit and pick all others. After this you'll want to call `c.GenericMerge("rebase", "continue")` +func (c *GitCommand) BeginInteractiveRebaseForCommit(commits []*Commit, commitIndex int) error { + if len(commits)-1 < commitIndex { + return errors.New("index outside of range of commits") + } + + // we can make this GPG thing possible it just means we need to do this in two parts: + // one where we handle the possibility of a credential request, and the other + // where we continue the rebase + if c.usingGpg() { + return errors.New(c.Tr.SLocalize("DisabledForGPG")) + } + + todo, sha, err := c.GenerateGenericRebaseTodo(commits, commitIndex, "edit") + if err != nil { + return err + } + + cmd, err := c.PrepareInteractiveRebaseCommand(sha, todo, true) + if err != nil { + return err + } + + if err := c.OSCommand.RunPreparedCommand(cmd); err != nil { + return err + } + + return nil +} diff --git a/pkg/commands/git_test.go b/pkg/commands/git_test.go index c132de98a..52db798ed 100644 --- a/pkg/commands/git_test.go +++ b/pkg/commands/git_test.go @@ -1685,7 +1685,7 @@ func TestGitCommandApplyPatch(t *testing.T) { type scenario struct { testName string command func(string, ...string) *exec.Cmd - test func(string, error) + test func(error) } scenarios := []scenario{ @@ -1702,9 +1702,8 @@ func TestGitCommandApplyPatch(t *testing.T) { return exec.Command("echo", "done") }, - func(output string, err error) { + func(err error) { assert.NoError(t, err) - assert.EqualValues(t, "done\n", output) }, }, { @@ -1724,7 +1723,7 @@ func TestGitCommandApplyPatch(t *testing.T) { return exec.Command("test") }, - func(output string, err error) { + func(err error) { assert.Error(t, err) }, }, @@ -1734,7 +1733,7 @@ func TestGitCommandApplyPatch(t *testing.T) { t.Run(s.testName, func(t *testing.T) { gitCmd := NewDummyGitCommand() gitCmd.OSCommand.command = s.command - s.test(gitCmd.ApplyPatch("test", false, true)) + s.test(gitCmd.ApplyPatch("test", false, true, "")) }) } } @@ -1962,7 +1961,7 @@ func TestGitCommandShowCommitFile(t *testing.T) { for _, s := range scenarios { t.Run(s.testName, func(t *testing.T) { gitCmd.OSCommand.command = s.command - s.test(gitCmd.ShowCommitFile(s.commitSha, s.fileName)) + s.test(gitCmd.ShowCommitFile(s.commitSha, s.fileName, true)) }) } } @@ -2001,7 +2000,7 @@ func TestGitCommandGetCommitFiles(t *testing.T) { for _, s := range scenarios { t.Run(s.testName, func(t *testing.T) { gitCmd.OSCommand.command = s.command - s.test(gitCmd.GetCommitFiles(s.commitSha)) + s.test(gitCmd.GetCommitFiles(s.commitSha, nil)) }) } } diff --git a/pkg/commands/patch_manager.go b/pkg/commands/patch_manager.go new file mode 100644 index 000000000..7c0da245d --- /dev/null +++ b/pkg/commands/patch_manager.go @@ -0,0 +1,194 @@ +package commands + +import ( + "sort" + "strings" + + "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/sirupsen/logrus" +) + +type fileInfo struct { + mode int // one of WHOLE/PART + includedLineIndices []int + diff string +} + |