mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-04-25 12:24:47 +02:00
Merge branch 'master' into hotfix/cursor-positioning
This commit is contained in:
commit
bd04ecff69
5
main.go
5
main.go
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -40,13 +41,13 @@ func main() {
|
|||||||
}
|
}
|
||||||
appConfig, err := config.NewAppConfig("lazygit", version, commit, date, buildSource, debuggingFlag)
|
appConfig, err := config.NewAppConfig("lazygit", version, commit, date, buildSource, debuggingFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
log.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
app, err := app.Setup(appConfig)
|
app, err := app.Setup(appConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.Log.Error(err.Error())
|
app.Log.Error(err.Error())
|
||||||
panic(err)
|
log.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Gui.RunWithSubprocesses()
|
app.Gui.RunWithSubprocesses()
|
||||||
|
@ -327,56 +327,50 @@ func (c *GitCommand) Push(branchName string, force bool) error {
|
|||||||
// retaining the message of the higher commit
|
// retaining the message of the higher commit
|
||||||
func (c *GitCommand) SquashPreviousTwoCommits(message string) error {
|
func (c *GitCommand) SquashPreviousTwoCommits(message string) error {
|
||||||
// TODO: test this
|
// TODO: test this
|
||||||
err := c.OSCommand.RunCommand("git reset --soft HEAD^")
|
if err := c.OSCommand.RunCommand("git reset --soft HEAD^"); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// TODO: if password is required, we need to return a subprocess
|
// TODO: if password is required, we need to return a subprocess
|
||||||
return c.OSCommand.RunCommand("git commit --amend -m " + c.OSCommand.Quote(message))
|
return c.OSCommand.RunCommand(fmt.Sprintf("git commit --amend -m %s", c.OSCommand.Quote(message)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SquashFixupCommit squashes a 'FIXUP' commit into the commit beneath it,
|
// SquashFixupCommit squashes a 'FIXUP' commit into the commit beneath it,
|
||||||
// retaining the commit message of the lower commit
|
// retaining the commit message of the lower commit
|
||||||
func (c *GitCommand) SquashFixupCommit(branchName string, shaValue string) error {
|
func (c *GitCommand) SquashFixupCommit(branchName string, shaValue string) error {
|
||||||
var err error
|
|
||||||
commands := []string{
|
commands := []string{
|
||||||
"git checkout -q " + shaValue,
|
fmt.Sprintf("git checkout -q %s", shaValue),
|
||||||
"git reset --soft " + shaValue + "^",
|
fmt.Sprintf("git reset --soft %s^", shaValue),
|
||||||
"git commit --amend -C " + shaValue + "^",
|
fmt.Sprintf("git commit --amend -C %s^", shaValue),
|
||||||
"git rebase --onto HEAD " + shaValue + " " + branchName,
|
fmt.Sprintf("git rebase --onto HEAD %s %s", shaValue, branchName),
|
||||||
}
|
}
|
||||||
ret := ""
|
|
||||||
for _, command := range commands {
|
for _, command := range commands {
|
||||||
c.Log.Info(command)
|
c.Log.Info(command)
|
||||||
output, err := c.OSCommand.RunCommandWithOutput(command)
|
|
||||||
ret += output
|
if output, err := c.OSCommand.RunCommandWithOutput(command); err != nil {
|
||||||
if err != nil {
|
ret := output
|
||||||
c.Log.Info(ret)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
// We are already in an error state here so we're just going to append
|
// We are already in an error state here so we're just going to append
|
||||||
// the output of these commands
|
// the output of these commands
|
||||||
output, _ := c.OSCommand.RunCommandWithOutput("git branch -d " + shaValue)
|
output, _ := c.OSCommand.RunCommandWithOutput(fmt.Sprintf("git branch -d %s", shaValue))
|
||||||
ret += output
|
ret += output
|
||||||
output, _ = c.OSCommand.RunCommandWithOutput("git checkout " + branchName)
|
output, _ = c.OSCommand.RunCommandWithOutput(fmt.Sprintf("git checkout %s", branchName))
|
||||||
ret += output
|
ret += output
|
||||||
}
|
|
||||||
if err != nil {
|
c.Log.Info(ret)
|
||||||
return errors.New(ret)
|
return errors.New(ret)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CatFile obtain the contents of a file
|
// CatFile obtains the content of a file
|
||||||
func (c *GitCommand) CatFile(fileName string) (string, error) {
|
func (c *GitCommand) CatFile(fileName string) (string, error) {
|
||||||
return c.OSCommand.RunCommandWithOutput("cat " + c.OSCommand.Quote(fileName))
|
return c.OSCommand.RunCommandWithOutput(fmt.Sprintf("cat %s", c.OSCommand.Quote(fileName)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// StageFile stages a file
|
// StageFile stages a file
|
||||||
func (c *GitCommand) StageFile(fileName string) error {
|
func (c *GitCommand) StageFile(fileName string) error {
|
||||||
return c.OSCommand.RunCommand("git add " + c.OSCommand.Quote(fileName))
|
return c.OSCommand.RunCommand(fmt.Sprintf("git add %s", c.OSCommand.Quote(fileName)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// StageAll stages all files
|
// StageAll stages all files
|
||||||
@ -391,13 +385,11 @@ func (c *GitCommand) UnstageAll() error {
|
|||||||
|
|
||||||
// UnStageFile unstages a file
|
// UnStageFile unstages a file
|
||||||
func (c *GitCommand) UnStageFile(fileName string, tracked bool) error {
|
func (c *GitCommand) UnStageFile(fileName string, tracked bool) error {
|
||||||
var command string
|
command := "git rm --cached %s"
|
||||||
if tracked {
|
if tracked {
|
||||||
command = "git reset HEAD "
|
command = "git reset HEAD %s"
|
||||||
} else {
|
|
||||||
command = "git rm --cached "
|
|
||||||
}
|
}
|
||||||
return c.OSCommand.RunCommand(command + c.OSCommand.Quote(fileName))
|
return c.OSCommand.RunCommand(fmt.Sprintf(command, c.OSCommand.Quote(fileName)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GitStatus returns the plaintext short status of the repo
|
// GitStatus returns the plaintext short status of the repo
|
||||||
|
@ -917,7 +917,7 @@ func TestGitCommandPush(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Push with force enable",
|
"Push with force enabled",
|
||||||
func(cmd string, args ...string) *exec.Cmd {
|
func(cmd string, args ...string) *exec.Cmd {
|
||||||
assert.EqualValues(t, "git", cmd)
|
assert.EqualValues(t, "git", cmd)
|
||||||
assert.EqualValues(t, []string{"push", "--force-with-lease", "-u", "origin", "test"}, args)
|
assert.EqualValues(t, []string{"push", "--force-with-lease", "-u", "origin", "test"}, args)
|
||||||
@ -953,6 +953,272 @@ func TestGitCommandPush(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGitCommandSquashPreviousTwoCommits(t *testing.T) {
|
||||||
|
type scenario struct {
|
||||||
|
testName string
|
||||||
|
command func(string, ...string) *exec.Cmd
|
||||||
|
test func(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []scenario{
|
||||||
|
{
|
||||||
|
"Git reset triggers an error",
|
||||||
|
func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
assert.EqualValues(t, "git", cmd)
|
||||||
|
assert.EqualValues(t, []string{"reset", "--soft", "HEAD^"}, args)
|
||||||
|
|
||||||
|
return exec.Command("exit", "1")
|
||||||
|
},
|
||||||
|
func(err error) {
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Git commit triggers an error",
|
||||||
|
func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
if len(args) > 0 && args[0] == "reset" {
|
||||||
|
return exec.Command("echo")
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.EqualValues(t, "git", cmd)
|
||||||
|
assert.EqualValues(t, []string{"commit", "--amend", "-m", "test"}, args)
|
||||||
|
|
||||||
|
return exec.Command("exit", "1")
|
||||||
|
},
|
||||||
|
func(err error) {
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Stash succeeded",
|
||||||
|
func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
if len(args) > 0 && args[0] == "reset" {
|
||||||
|
return exec.Command("echo")
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.EqualValues(t, "git", cmd)
|
||||||
|
assert.EqualValues(t, []string{"commit", "--amend", "-m", "test"}, args)
|
||||||
|
|
||||||
|
return exec.Command("echo")
|
||||||
|
},
|
||||||
|
func(err error) {
|
||||||
|
assert.Nil(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
|
gitCmd := newDummyGitCommand()
|
||||||
|
gitCmd.OSCommand.command = s.command
|
||||||
|
s.test(gitCmd.SquashPreviousTwoCommits("test"))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGitCommandSquashFixupCommit(t *testing.T) {
|
||||||
|
type scenario struct {
|
||||||
|
testName string
|
||||||
|
command func() (func(string, ...string) *exec.Cmd, *[][]string)
|
||||||
|
test func(*[][]string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []scenario{
|
||||||
|
{
|
||||||
|
"An error occurred with one of the sub git command",
|
||||||
|
func() (func(string, ...string) *exec.Cmd, *[][]string) {
|
||||||
|
cmdsCalled := [][]string{}
|
||||||
|
return func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
cmdsCalled = append(cmdsCalled, args)
|
||||||
|
if len(args) > 0 && args[0] == "checkout" {
|
||||||
|
return exec.Command("exit", "1")
|
||||||
|
}
|
||||||
|
|
||||||
|
return exec.Command("echo")
|
||||||
|
}, &cmdsCalled
|
||||||
|
},
|
||||||
|
func(cmdsCalled *[][]string, err error) {
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.Len(t, *cmdsCalled, 3)
|
||||||
|
assert.EqualValues(t, *cmdsCalled, [][]string{
|
||||||
|
{"checkout", "-q", "6789abcd"},
|
||||||
|
{"branch", "-d", "6789abcd"},
|
||||||
|
{"checkout", "test"},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Squash fixup succeeded",
|
||||||
|
func() (func(string, ...string) *exec.Cmd, *[][]string) {
|
||||||
|
cmdsCalled := [][]string{}
|
||||||
|
return func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
cmdsCalled = append(cmdsCalled, args)
|
||||||
|
return exec.Command("echo")
|
||||||
|
}, &cmdsCalled
|
||||||
|
},
|
||||||
|
func(cmdsCalled *[][]string, err error) {
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Len(t, *cmdsCalled, 4)
|
||||||
|
assert.EqualValues(t, *cmdsCalled, [][]string{
|
||||||
|
{"checkout", "-q", "6789abcd"},
|
||||||
|
{"reset", "--soft", "6789abcd^"},
|
||||||
|
{"commit", "--amend", "-C", "6789abcd^"},
|
||||||
|
{"rebase", "--onto", "HEAD", "6789abcd", "test"},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
|
var cmdsCalled *[][]string
|
||||||
|
gitCmd := newDummyGitCommand()
|
||||||
|
gitCmd.OSCommand.command, cmdsCalled = s.command()
|
||||||
|
s.test(cmdsCalled, gitCmd.SquashFixupCommit("test", "6789abcd"))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGitCommandCatFile(t *testing.T) {
|
||||||
|
gitCmd := newDummyGitCommand()
|
||||||
|
gitCmd.OSCommand.command = func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
assert.EqualValues(t, "cat", cmd)
|
||||||
|
assert.EqualValues(t, []string{"test.txt"}, args)
|
||||||
|
|
||||||
|
return exec.Command("echo", "-n", "test")
|
||||||
|
}
|
||||||
|
|
||||||
|
o, err := gitCmd.CatFile("test.txt")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "test", o)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGitCommandStageFile(t *testing.T) {
|
||||||
|
gitCmd := newDummyGitCommand()
|
||||||
|
gitCmd.OSCommand.command = func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
assert.EqualValues(t, "git", cmd)
|
||||||
|
assert.EqualValues(t, []string{"add", "test.txt"}, args)
|
||||||
|
|
||||||
|
return exec.Command("echo")
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.NoError(t, gitCmd.StageFile("test.txt"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGitCommandUnstageFile(t *testing.T) {
|
||||||
|
type scenario struct {
|
||||||
|
testName string
|
||||||
|
command func(string, ...string) *exec.Cmd
|
||||||
|
test func(error)
|
||||||
|
tracked bool
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []scenario{
|
||||||
|
{
|
||||||
|
"Remove an untracked file from staging",
|
||||||
|
func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
assert.EqualValues(t, "git", cmd)
|
||||||
|
assert.EqualValues(t, []string{"rm", "--cached", "test.txt"}, args)
|
||||||
|
|
||||||
|
return exec.Command("echo")
|
||||||
|
},
|
||||||
|
func(err error) {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Remove a tracked file from staging",
|
||||||
|
func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
assert.EqualValues(t, "git", cmd)
|
||||||
|
assert.EqualValues(t, []string{"reset", "HEAD", "test.txt"}, args)
|
||||||
|
|
||||||
|
return exec.Command("echo")
|
||||||
|
},
|
||||||
|
func(err error) {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
|
gitCmd := newDummyGitCommand()
|
||||||
|
gitCmd.OSCommand.command = s.command
|
||||||
|
s.test(gitCmd.UnStageFile("test.txt", s.tracked))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGitCommandIsInMergeState(t *testing.T) {
|
||||||
|
type scenario struct {
|
||||||
|
testName string
|
||||||
|
command func(string, ...string) *exec.Cmd
|
||||||
|
test func(bool, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []scenario{
|
||||||
|
{
|
||||||
|
"An error occurred when running status command",
|
||||||
|
func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
assert.EqualValues(t, "git", cmd)
|
||||||
|
assert.EqualValues(t, []string{"status", "--untracked-files=all"}, args)
|
||||||
|
|
||||||
|
return exec.Command("exit", "1")
|
||||||
|
},
|
||||||
|
func(isInMergeState bool, err error) {
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.False(t, isInMergeState)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Is not in merge state",
|
||||||
|
func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
assert.EqualValues(t, "git", cmd)
|
||||||
|
assert.EqualValues(t, []string{"status", "--untracked-files=all"}, args)
|
||||||
|
return exec.Command("echo")
|
||||||
|
},
|
||||||
|
func(isInMergeState bool, err error) {
|
||||||
|
assert.False(t, isInMergeState)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Command output contains conclude merge",
|
||||||
|
func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
assert.EqualValues(t, "git", cmd)
|
||||||
|
assert.EqualValues(t, []string{"status", "--untracked-files=all"}, args)
|
||||||
|
return exec.Command("echo", "'conclude merge'")
|
||||||
|
},
|
||||||
|
func(isInMergeState bool, err error) {
|
||||||
|
assert.True(t, isInMergeState)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Command output contains unmerged paths",
|
||||||
|
func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
assert.EqualValues(t, "git", cmd)
|
||||||
|
assert.EqualValues(t, []string{"status", "--untracked-files=all"}, args)
|
||||||
|
return exec.Command("echo", "'unmerged paths'")
|
||||||
|
},
|
||||||
|
func(isInMergeState bool, err error) {
|
||||||
|
assert.True(t, isInMergeState)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
|
gitCmd := newDummyGitCommand()
|
||||||
|
gitCmd.OSCommand.command = s.command
|
||||||
|
s.test(gitCmd.IsInMergeState())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGitCommandDiff(t *testing.T) {
|
func TestGitCommandDiff(t *testing.T) {
|
||||||
gitCommand := newDummyGitCommand()
|
gitCommand := newDummyGitCommand()
|
||||||
assert.NoError(t, test.GenerateRepo("lots_of_diffs.sh"))
|
assert.NoError(t, test.GenerateRepo("lots_of_diffs.sh"))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user