mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-10-16 09:27:37 +03:00
This is an object that is owned by Gui, is accessible through GuiCommon.State(), and also passed down to GitCommand, where it is mostly needed. Right now it simply wraps access to the Git.Paging config, which isn't very exciting, but we'll extend it in the next commit to handle a slice of pagers (and maintain the currently selected pager index), and doing this refactoring up front allows us to make that change without having to touch clients.
219 lines
5.8 KiB
Go
219 lines
5.8 KiB
Go
package git_commands
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
|
)
|
|
|
|
type StashCommands struct {
|
|
*GitCommon
|
|
fileLoader *FileLoader
|
|
workingTree *WorkingTreeCommands
|
|
}
|
|
|
|
func NewStashCommands(
|
|
gitCommon *GitCommon,
|
|
fileLoader *FileLoader,
|
|
workingTree *WorkingTreeCommands,
|
|
) *StashCommands {
|
|
return &StashCommands{
|
|
GitCommon: gitCommon,
|
|
fileLoader: fileLoader,
|
|
workingTree: workingTree,
|
|
}
|
|
}
|
|
|
|
func (self *StashCommands) DropNewest() error {
|
|
cmdArgs := NewGitCmd("stash").Arg("drop").ToArgv()
|
|
|
|
return self.cmd.New(cmdArgs).Run()
|
|
}
|
|
|
|
func (self *StashCommands) Drop(index int) error {
|
|
cmdArgs := NewGitCmd("stash").Arg("drop", fmt.Sprintf("refs/stash@{%d}", index)).
|
|
ToArgv()
|
|
|
|
return self.cmd.New(cmdArgs).Run()
|
|
}
|
|
|
|
func (self *StashCommands) Pop(index int) error {
|
|
cmdArgs := NewGitCmd("stash").Arg("pop", fmt.Sprintf("refs/stash@{%d}", index)).
|
|
ToArgv()
|
|
|
|
return self.cmd.New(cmdArgs).Run()
|
|
}
|
|
|
|
func (self *StashCommands) Apply(index int) error {
|
|
cmdArgs := NewGitCmd("stash").Arg("apply", fmt.Sprintf("refs/stash@{%d}", index)).
|
|
ToArgv()
|
|
|
|
return self.cmd.New(cmdArgs).Run()
|
|
}
|
|
|
|
// Push push stash
|
|
func (self *StashCommands) Push(message string) error {
|
|
cmdArgs := NewGitCmd("stash").Arg("push", "-m", message).
|
|
ToArgv()
|
|
|
|
return self.cmd.New(cmdArgs).Run()
|
|
}
|
|
|
|
func (self *StashCommands) Store(hash string, message string) error {
|
|
trimmedMessage := strings.Trim(message, " \t")
|
|
|
|
cmdArgs := NewGitCmd("stash").Arg("store").
|
|
ArgIf(trimmedMessage != "", "-m", trimmedMessage).
|
|
Arg(hash).
|
|
ToArgv()
|
|
|
|
return self.cmd.New(cmdArgs).Run()
|
|
}
|
|
|
|
func (self *StashCommands) Hash(index int) (string, error) {
|
|
cmdArgs := NewGitCmd("rev-parse").
|
|
Arg(fmt.Sprintf("refs/stash@{%d}", index)).
|
|
ToArgv()
|
|
|
|
hash, _, err := self.cmd.New(cmdArgs).DontLog().RunWithOutputs()
|
|
return strings.Trim(hash, "\r\n"), err
|
|
}
|
|
|
|
func (self *StashCommands) ShowStashEntryCmdObj(index int) *oscommands.CmdObj {
|
|
extDiffCmd := self.pagerConfig.GetExternalDiffCommand()
|
|
useExtDiffGitConfig := self.pagerConfig.GetUseExternalDiffGitConfig()
|
|
|
|
// "-u" is the same as "--include-untracked", but the latter fails in older git versions for some reason
|
|
cmdArgs := NewGitCmd("stash").Arg("show").
|
|
Arg("-p").
|
|
Arg("--stat").
|
|
Arg("-u").
|
|
ConfigIf(extDiffCmd != "", "diff.external="+extDiffCmd).
|
|
ArgIfElse(extDiffCmd != "" || useExtDiffGitConfig, "--ext-diff", "--no-ext-diff").
|
|
Arg(fmt.Sprintf("--color=%s", self.pagerConfig.GetColorArg())).
|
|
Arg(fmt.Sprintf("--unified=%d", self.UserConfig().Git.DiffContextSize)).
|
|
ArgIf(self.UserConfig().Git.IgnoreWhitespaceInDiffView, "--ignore-all-space").
|
|
Arg(fmt.Sprintf("--find-renames=%d%%", self.UserConfig().Git.RenameSimilarityThreshold)).
|
|
Arg(fmt.Sprintf("refs/stash@{%d}", index)).
|
|
Dir(self.repoPaths.worktreePath).
|
|
ToArgv()
|
|
|
|
return self.cmd.New(cmdArgs).DontLog()
|
|
}
|
|
|
|
func (self *StashCommands) StashAndKeepIndex(message string) error {
|
|
cmdArgs := NewGitCmd("stash").Arg("push", "--keep-index", "-m", message).
|
|
ToArgv()
|
|
|
|
return self.cmd.New(cmdArgs).Run()
|
|
}
|
|
|
|
func (self *StashCommands) StashUnstagedChanges(message string) error {
|
|
if err := self.cmd.New(
|
|
NewGitCmd("commit").
|
|
Arg("--no-verify", "-m", "[lazygit] stashing unstaged changes").
|
|
ToArgv(),
|
|
).Run(); err != nil {
|
|
return err
|
|
}
|
|
if err := self.Push(message); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := self.cmd.New(
|
|
NewGitCmd("reset").Arg("--soft", "HEAD^").ToArgv(),
|
|
).Run(); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// SaveStagedChanges stashes only the currently staged changes.
|
|
func (self *StashCommands) SaveStagedChanges(message string) error {
|
|
if self.version.IsAtLeast(2, 35, 0) {
|
|
return self.cmd.New(NewGitCmd("stash").Arg("push").Arg("--staged").Arg("-m", message).ToArgv()).Run()
|
|
}
|
|
|
|
// Git versions older than 2.35.0 don't support the --staged flag, so we
|
|
// need to fall back to a more complex solution.
|
|
// Shoutouts to Joe on https://stackoverflow.com/questions/14759748/stashing-only-staged-changes-in-git-is-it-possible
|
|
//
|
|
// Note that this method has a few bugs:
|
|
// - it fails when there are *only* staged changes
|
|
// - it fails when staged and unstaged changes within a single file are too close together
|
|
// We don't bother fixing these, because users can simply update git when
|
|
// they are affected by these issues.
|
|
|
|
// wrap in 'writing', which uses a mutex
|
|
if err := self.cmd.New(
|
|
NewGitCmd("stash").Arg("--keep-index").ToArgv(),
|
|
).Run(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := self.Push(message); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := self.cmd.New(
|
|
NewGitCmd("stash").Arg("apply", "refs/stash@{1}").ToArgv(),
|
|
).Run(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := self.os.PipeCommands(
|
|
self.cmd.New(NewGitCmd("stash").Arg("show", "-p").ToArgv()),
|
|
self.cmd.New(NewGitCmd("apply").Arg("-R").ToArgv()),
|
|
); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := self.cmd.New(
|
|
NewGitCmd("stash").Arg("drop", "refs/stash@{1}").ToArgv(),
|
|
).Run(); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 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
|
|
// now safely stashed, we need to remove it.
|
|
files := self.fileLoader.
|
|
GetStatusFiles(GetStatusFileOptions{})
|
|
|
|
for _, file := range files {
|
|
if file.ShortStatus == "AD" {
|
|
if err := self.workingTree.UnStageFile(file.Names(), false); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (self *StashCommands) StashIncludeUntrackedChanges(message string) error {
|
|
return self.cmd.New(
|
|
NewGitCmd("stash").Arg("push", "--include-untracked", "-m", message).
|
|
ToArgv(),
|
|
).Run()
|
|
}
|
|
|
|
func (self *StashCommands) Rename(index int, message string) error {
|
|
hash, err := self.Hash(index)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := self.Drop(index); err != nil {
|
|
return err
|
|
}
|
|
|
|
err = self.Store(hash, message)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|