aboutsummaryrefslogtreecommitdiffstats
path: root/repository.go
diff options
context:
space:
mode:
Diffstat (limited to 'repository.go')
-rw-r--r--repository.go121
1 files changed, 108 insertions, 13 deletions
diff --git a/repository.go b/repository.go
index a8dd7ef..c065a26 100644
--- a/repository.go
+++ b/repository.go
@@ -4,12 +4,14 @@ import (
"errors"
"fmt"
"os"
+ "path/filepath"
"srcd.works/go-git.v4/config"
"srcd.works/go-git.v4/internal/revision"
"srcd.works/go-git.v4/plumbing"
"srcd.works/go-git.v4/plumbing/object"
"srcd.works/go-git.v4/plumbing/storer"
+ "srcd.works/go-git.v4/storage"
"srcd.works/go-git.v4/storage/filesystem"
"srcd.works/go-billy.v1"
@@ -29,7 +31,7 @@ var (
// Repository represents a git repository
type Repository struct {
- Storer Storer
+ Storer storage.Storer
r map[string]*Remote
wt billy.Filesystem
@@ -38,7 +40,7 @@ type Repository struct {
// Init creates an empty git repository, based on the given Storer and worktree.
// The worktree Filesystem is optional, if nil a bare repository is created. If
// the given storer is not empty ErrRepositoryAlreadyExists is returned
-func Init(s Storer, worktree billy.Filesystem) (*Repository, error) {
+func Init(s storage.Storer, worktree billy.Filesystem) (*Repository, error) {
r := newRepository(s, worktree)
_, err := r.Reference(plumbing.HEAD, false)
switch err {
@@ -56,9 +58,75 @@ func Init(s Storer, worktree billy.Filesystem) (*Repository, error) {
if worktree == nil {
r.setIsBare(true)
+ return r, nil
}
- return r, nil
+ return r, setWorktreeAndStoragePaths(r, worktree)
+}
+
+func setWorktreeAndStoragePaths(r *Repository, worktree billy.Filesystem) error {
+ type fsBased interface {
+ Filesystem() billy.Filesystem
+ }
+
+ // .git file is only created if the storage is file based and the file
+ // system is osfs.OS
+ fs, isFSBased := r.Storer.(fsBased)
+ if !isFSBased {
+ return nil
+ }
+
+ _, isOS := fs.Filesystem().(*osfs.OS)
+ if !isOS {
+ return nil
+ }
+
+ if err := createDotGitFile(worktree, fs.Filesystem()); err != nil {
+ return err
+ }
+
+ return setConfigWorktree(r, worktree, fs.Filesystem())
+}
+
+func createDotGitFile(worktree, storage billy.Filesystem) error {
+ path, err := filepath.Rel(worktree.Base(), storage.Base())
+ if err != nil {
+ path = storage.Base()
+ }
+
+ if path == ".git" {
+ // not needed, since the folder is the default place
+ return nil
+ }
+
+ f, err := worktree.Create(".git")
+ if err != nil {
+ return err
+ }
+
+ defer f.Close()
+ _, err = fmt.Fprintf(f, "gitdir: %s\n", path)
+ return err
+}
+
+func setConfigWorktree(r *Repository, worktree, storage billy.Filesystem) error {
+ path, err := filepath.Rel(storage.Base(), worktree.Base())
+ if err != nil {
+ path = worktree.Base()
+ }
+
+ if path == ".." {
+ // not needed, since the folder is the default place
+ return nil
+ }
+
+ cfg, err := r.Storer.Config()
+ if err != nil {
+ return err
+ }
+
+ cfg.Core.Worktree = path
+ return r.Storer.SetConfig(cfg)
}
// Open opens a git repository using the given Storer and worktree filesystem,
@@ -66,7 +134,7 @@ func Init(s Storer, worktree billy.Filesystem) (*Repository, error) {
// The worktree can be nil when the repository being opened is bare, if the
// repository is a normal one (not bare) and worktree is nil the err
// ErrWorktreeNotProvided is returned
-func Open(s Storer, worktree billy.Filesystem) (*Repository, error) {
+func Open(s storage.Storer, worktree billy.Filesystem) (*Repository, error) {
_, err := s.Reference(plumbing.HEAD)
if err == plumbing.ErrReferenceNotFound {
return nil, ErrRepositoryNotExists
@@ -91,7 +159,7 @@ func Open(s Storer, worktree billy.Filesystem) (*Repository, error) {
// Clone a repository into the given Storer and worktree Filesystem with the
// given options, if worktree is nil a bare repository is created. If the given
// storer is not empty ErrRepositoryAlreadyExists is returned
-func Clone(s Storer, worktree billy.Filesystem, o *CloneOptions) (*Repository, error) {
+func Clone(s storage.Storer, worktree billy.Filesystem, o *CloneOptions) (*Repository, error) {
r, err := Init(s, worktree)
if err != nil {
return nil, err
@@ -159,7 +227,7 @@ func PlainClone(path string, isBare bool, o *CloneOptions) (*Repository, error)
return r, r.clone(o)
}
-func newRepository(s Storer, worktree billy.Filesystem) *Repository {
+func newRepository(s storage.Storer, worktree billy.Filesystem) *Repository {
return &Repository{
Storer: s,
wt: worktree,
@@ -247,12 +315,6 @@ func (r *Repository) clone(o *CloneOptions) error {
return err
}
- // marks the repository as bare in the config, until we have Worktree, all
- // the repository are bare
- if err := r.setIsBare(true); err != nil {
- return err
- }
-
c := &config.RemoteConfig{
Name: o.RemoteName,
URL: o.URL,
@@ -286,9 +348,32 @@ func (r *Repository) clone(o *CloneOptions) error {
return err
}
+ if o.RecurseSubmodules != NoRecurseSubmodules && r.wt != nil {
+ if err := r.updateSubmodules(o.RecurseSubmodules); err != nil {
+ return err
+ }
+ }
+
return r.updateRemoteConfig(remote, o, c, head)
}
+func (r *Repository) updateSubmodules(recursion SubmoduleRescursivity) error {
+ w, err := r.Worktree()
+ if err != nil {
+ return err
+ }
+
+ s, err := w.Submodules()
+ if err != nil {
+ return err
+ }
+
+ return s.Update(&SubmoduleUpdateOptions{
+ Init: true,
+ RecurseSubmodules: recursion,
+ })
+}
+
func (r *Repository) cloneRefSpec(o *CloneOptions,
c *config.RemoteConfig) []config.RefSpec {
@@ -462,7 +547,17 @@ func (r *Repository) Pull(o *PullOptions) error {
return NoErrAlreadyUpToDate
}
- return r.updateWorktree()
+ if err := r.updateWorktree(); err != nil {
+ return err
+ }
+
+ if o.RecurseSubmodules != NoRecurseSubmodules && r.wt != nil {
+ if err := r.updateSubmodules(o.RecurseSubmodules); err != nil {
+ return err
+ }
+ }
+
+ return nil
}
func (r *Repository) updateWorktree() error {