summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2019-05-12 17:04:32 +1000
committerJesse Duffield <jessedduffield@gmail.com>2019-05-12 17:59:49 +1000
commitc61bfbdd4cd46243ef6663533e0c9db05dd1f7bd (patch)
treee9128ab7a1e590e636ef354338c6816f494c7c4e
parente38d9d5f226a22e5299b82fe9c4ea46b7f7db120 (diff)
Support opening lazygit in a submodulev0.8
-rw-r--r--pkg/commands/git.go43
-rw-r--r--pkg/commands/git_test.go76
-rw-r--r--pkg/commands/testdata/a_dir/file0
-rw-r--r--pkg/commands/testdata/a_file0
-rw-r--r--pkg/git/commit_list_builder.go6
5 files changed, 113 insertions, 12 deletions
diff --git a/pkg/commands/git.go b/pkg/commands/git.go
index 159c88cca..2a6f57659 100644
--- a/pkg/commands/git.go
+++ b/pkg/commands/git.go
@@ -25,13 +25,10 @@ func verifyInGitRepo(runCmd func(string) error) error {
func navigateToRepoRootDirectory(stat func(string) (os.FileInfo, error), chdir func(string) error) error {
for {
- f, err := stat(".git")
+ _, err := stat(".git")
if err == nil {
- if f.IsDir() {
- return nil
- }
- return errors.New("expected .git to be a directory")
+ return nil
}
if !os.IsNotExist(err) {
@@ -75,6 +72,7 @@ type GitCommand struct {
getGlobalGitConfig func(string) (string, error)
getLocalGitConfig func(string) (string, error)
removeFile func(string) error
+ DotGitDir string
}
// NewGitCommand it runs git commands
@@ -102,6 +100,11 @@ func NewGitCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.Localizer,
}
}
+ dotGitDir, err := findDotGitDir(os.Stat, ioutil.ReadFile)
+ if err != nil {
+ return nil, err
+ }
+
return &GitCommand{
Log: log,
OSCommand: osCommand,
@@ -112,9 +115,31 @@ func NewGitCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.Localizer,
getGlobalGitConfig: gitconfig.Global,
getLocalGitConfig: gitconfig.Local,
removeFile: os.RemoveAll,
+ DotGitDir: dotGitDir,
}, nil
}
+func findDotGitDir(stat func(string) (os.FileInfo, error), readFile func(filename string) ([]byte, error)) (string, error) {
+ f, err := stat(".git")
+ if err != nil {
+ return "", err
+ }
+
+ if f.IsDir() {
+ return ".git", nil
+ }
+
+ fileBytes, err := readFile(".git")
+ if err != nil {
+ return "", err
+ }
+ fileContent := string(fileBytes)
+ if !strings.HasPrefix(fileContent, "gitdir: ") {
+ return "", errors.New(".git is a file which suggests we are in a submodule but the file's contents do not contain a gitdir pointing to the actual .git directory")
+ }
+ return strings.TrimSpace(strings.TrimPrefix(fileContent, "gitdir: ")), nil
+}
+
// GetStashEntries stash entryies
func (c *GitCommand) GetStashEntries() []*StashEntry {
rawString, _ := c.OSCommand.RunCommandWithOutput("git stash list --pretty='%gs'")
@@ -426,14 +451,14 @@ func (c *GitCommand) IsInMergeState() (bool, error) {
// RebaseMode returns "" for non-rebase mode, "normal" for normal rebase
// and "interactive" for interactive rebase
func (c *GitCommand) RebaseMode() (string, error) {
- exists, err := c.OSCommand.FileExists(".git/rebase-apply")
+ exists, err := c.OSCommand.FileExists(fmt.Sprintf("%s/rebase-apply", c.DotGitDir))
if err != nil {
return "", err
}
if exists {
return "normal", nil
}
- exists, err = c.OSCommand.FileExists(".git/rebase-merge")
+ exists, err = c.OSCommand.FileExists(fmt.Sprintf("%s/rebase-merge", c.DotGitDir))
if exists {
return "interactive", err
} else {
@@ -743,7 +768,7 @@ func (c *GitCommand) AmendTo(sha string) error {
// EditRebaseTodo sets the action at a given index in the git-rebase-todo file
func (c *GitCommand) EditRebaseTodo(index int, action string) error {
- fileName := ".git/rebase-merge/git-rebase-todo"
+ fileName := fmt.Sprintf("%s/rebase-merge/git-rebase-todo", c.DotGitDir)
bytes, err := ioutil.ReadFile(fileName)
if err != nil {
return err
@@ -775,7 +800,7 @@ func (c *GitCommand) getTodoCommitCount(content []string) int {
// MoveTodoDown moves a rebase todo item down by one position
func (c *GitCommand) MoveTodoDown(index int) error {
- fileName := ".git/rebase-merge/git-rebase-todo"
+ fileName := fmt.Sprintf("%s/rebase-merge/git-rebase-todo", c.DotGitDir)
bytes, err := ioutil.ReadFile(fileName)
if err != nil {
return err
diff --git a/pkg/commands/git_test.go b/pkg/commands/git_test.go
index 0d59c30b7..be9f8c883 100644
--- a/pkg/commands/git_test.go
+++ b/pkg/commands/git_test.go
@@ -8,6 +8,7 @@ import (
"testing"
"time"
+ "github.com/go-errors/errors"
"github.com/jesseduffield/lazygit/pkg/i18n"
"github.com/jesseduffield/lazygit/pkg/test"
"github.com/stretchr/testify/assert"
@@ -2122,3 +2123,78 @@ func TestGitCommandCreateFixupCommit(t *testing.T) {
})
}
}
+
+func TestFindDotGitDir(t *testing.T) {
+ type scenario struct {
+ testName string
+ stat func(string) (os.FileInfo, error)
+ readFile func(filename string) ([]byte, error)
+ test func(string, error)
+ }
+
+ scenarios := []scenario{
+ {
+ ".git is a directory",
+ func(dotGit string) (os.FileInfo, error) {
+ assert.Equal(t, ".git", dotGit)
+ return os.Stat("testdata/a_dir")
+ },
+ func(dotGit string) ([]byte, error) {
+ assert.Fail(t, "readFile should not be called if .git is a directory")
+ return nil, nil
+ },
+ func(gitDir string, err error) {
+ assert.NoError(t, err)
+ assert.Equal(t, ".git", gitDir)
+ },
+ },
+ {
+ ".git is a file",
+ func(dotGit string) (os.FileInfo, error) {
+ assert.Equal(t, ".git", dotGit)
+ return os.Stat("testdata/a_file")
+ },
+ func(dotGit string) ([]byte, error) {
+ assert.Equal(t, ".git", dotGit)
+ return []byte("gitdir: blah\n"), nil
+ },
+ func(gitDir string, err error) {
+ assert.NoError(t, err)
+ assert.Equal(t, "blah", gitDir)
+ },
+ },
+ {
+ "os.Stat returns an error",
+ func(dotGit string) (os.FileInfo, error) {
+ assert.Equal(t, ".git", dotGit)
+ return nil, errors.New("error")
+ },
+ func(dotGit string) ([]byte, error) {
+ assert.Fail(t, "readFile should not be called os.Stat returns an error")
+ return nil, nil
+ },
+ func(gitDir string, err error) {
+ assert.Error(t, err)
+ },
+ },
+ {
+ "readFile returns an error",
+ func(dotGit string) (os.FileInfo, error) {
+ assert.Equal(t, ".git", dotGit)
+ return os.Stat("testdata/a_file")
+ },
+ func(dotGit string) ([]byte, error) {
+ return nil, errors.New("error")
+ },
+ func(gitDir string, err error) {
+ assert.Error(t, err)
+ },
+ },
+ }
+
+ for _, s := range scenarios {
+ t.Run(s.testName, func(t *testing.T) {
+ s.test(findDotGitDir(s.stat, s.readFile))
+ })
+ }
+}
diff --git a/pkg/commands/testdata/a_dir/file b/pkg/commands/testdata/a_dir/file
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/pkg/commands/testdata/a_dir/file
diff --git a/pkg/commands/testdata/a_file b/pkg/commands/testdata/a_file
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/pkg/commands/testdata/a_file
diff --git a/pkg/git/commit_list_builder.go b/pkg/git/commit_list_builder.go
index 32116656d..f3ba685f6 100644
--- a/pkg/git/commit_list_builder.go
+++ b/pkg/git/commit_list_builder.go
@@ -123,7 +123,7 @@ func (c *CommitListBuilder) getRebasingCommits(rebaseMode string) ([]*commands.C
func (c *CommitListBuilder) getNormalRebasingCommits() ([]*commands.Commit, error) {
rewrittenCount := 0
- bytesContent, err := ioutil.ReadFile(".git/rebase-apply/rewritten")
+ bytesContent, err := ioutil.ReadFile(fmt.Sprintf("%s/rebase-apply/rewritten", c.GitCommand.DotGitDir))
if err == nil {
content := string(bytesContent)
rewrittenCount = len(strings.Split(content, "\n"))
@@ -131,7 +131,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{}
- err = filepath.Walk(".git/rebase-apply", func(path string, f os.FileInfo, err error) error {
+ err = filepath.Walk(fmt.Sprintf("%s/rebase-apply", c.GitCommand.DotGitDir), func(path string, f os.FileInfo, err error) error {
if rewrittenCount > 0 {
rewrittenCount--
return nil
@@ -175,7 +175,7 @@ func (c *CommitListBuilder) getNormalRebasingCommits() ([]*commands.Commit, erro
// 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) {
- bytesContent, err := ioutil.ReadFile(".git/rebase-merge/git-rebase-todo")
+ bytesContent, err := ioutil.ReadFile(fmt.Sprintf("%s/rebase-merge/git-rebase-todo", c.GitCommand.DotGitDir))
if err != nil {
c.Log.Info(fmt.Sprintf("error occured reading git-rebase-todo: %s", err.Error()))
// we assume an error means the file doesn't exist so we just return