diff --git a/vcs.go b/vcs.go index 7d3c88fc..770693b8 100644 --- a/vcs.go +++ b/vcs.go @@ -13,6 +13,7 @@ import ( "strings" "github.com/x-motemen/ghq/cmdutil" + "github.com/x-motemen/ghq/logger" ) func run(silent bool) func(command string, args ...string) error { @@ -47,9 +48,34 @@ type vcsGetOption struct { branch string } +func gitAddTarget(vg *vcsGetOption, target string) error { + dir, _ := filepath.Split(vg.dir) + return runInDir(vg.silent)(dir, "git", "add", target) +} + +func gitDetectInsideWorktree(vg *vcsGetOption, dir string) bool { + cmd := exec.Command( + "git", + "rev-parse", + "--is-inside-work-tree") + cmd.Stdout = io.Discard + cmd.Stderr = io.Discard + cmd.Dir = dir + if !vg.silent { + logger.Log(cmd.Args[0], strings.Join(cmd.Args[1:], " ")) + } + err := cmd.Run() + return err == nil +} + +type GitSubmoduleOptionError struct {} + +func (e *GitSubmoduleOptionError) Error() string { + return fmt.Sprintf("Cloning as submodule, option '--bare' is not supported") +} + // GitBackend is the VCSBackend of git var GitBackend = &VCSBackend{ - // support submodules? Clone: func(vg *vcsGetOption) error { dir, _ := filepath.Split(vg.dir) err := os.MkdirAll(dir, 0755) @@ -57,22 +83,40 @@ var GitBackend = &VCSBackend{ return err } - args := []string{"clone"} + args := []string{} + if gitDetectInsideWorktree(vg, dir) { + // use git-submodule + if vg.bare { + return &GitSubmoduleOptionError{} + } + err := gitAddTarget(vg, dir) + if err != nil { + return err + } + args = []string{"submodule", "add"} + } else { + args = append(args, "clone") + if vg.recursive { + args = append(args, "--recursive") + } + if vg.bare { + args = append(args, "--bare") + } + } + if vg.shallow { args = append(args, "--depth", "1") } if vg.branch != "" { args = append(args, "--branch", vg.branch, "--single-branch") } - if vg.recursive { - args = append(args, "--recursive") - } - if vg.bare { - args = append(args, "--bare") - } args = append(args, vg.url.String(), vg.dir) + err = runInDir(vg.silent)(dir, "git", args...) + if err != nil { + return err + } - return run(vg.silent)("git", args...) + return nil }, Update: func(vg *vcsGetOption) error { if _, err := os.Stat(filepath.Join(vg.dir, ".git/svn")); err == nil { diff --git a/vcs_test.go b/vcs_test.go index 1d9e0685..7175dece 100644 --- a/vcs_test.go +++ b/vcs_test.go @@ -56,6 +56,7 @@ func TestVCSBackend(t *testing.T) { }) }, expect: []string{"git", "clone", remoteDummyURL.String(), localDir}, + dir: tempDir + "/", }, { name: "[git] shallow clone", f: func() error { @@ -67,6 +68,7 @@ func TestVCSBackend(t *testing.T) { }) }, expect: []string{"git", "clone", "--depth", "1", remoteDummyURL.String(), localDir}, + dir: tempDir + "/", }, { name: "[git] clone specific branch", f: func() error { @@ -77,6 +79,7 @@ func TestVCSBackend(t *testing.T) { }) }, expect: []string{"git", "clone", "--branch", "hello", "--single-branch", remoteDummyURL.String(), localDir}, + dir: tempDir + "/", }, { name: "[git] update", f: func() error { @@ -115,6 +118,7 @@ func TestVCSBackend(t *testing.T) { }) }, expect: []string{"git", "clone", "--recursive", remoteDummyURL.String(), localDir}, + dir:tempDir + "/", }, { name: "[git] update recursive", f: func() error { @@ -136,6 +140,7 @@ func TestVCSBackend(t *testing.T) { }) }, expect: []string{"git", "clone", "--bare", remoteDummyURL.String(), localDir}, + dir:tempDir + "/", }, { name: "[git] switch git-svn on update", f: func() error {