func (s Submodules) Status() (SubmodulesStatus, error) {
	var list SubmodulesStatus
	var r *Repository
	for _, sub := range s {
		if r == nil {
			r = sub.w.r
		}
		idx, err := r.Storer.Index()
		if err != nil {
			return nil, err
		}
		status, err := sub.status(idx)
		if err != nil {
			return nil, err
		}
		list = append(list, status)
	}
	return list, nil
}
Status returns the status of the submodules.
package git
import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"gopkg.in/src-d/go-billy.v4"
	"gopkg.in/src-d/go-git.v4/config"
	"gopkg.in/src-d/go-git.v4/plumbing"
	"gopkg.in/src-d/go-git.v4/plumbing/format/index"
)
var (
	ErrSubmoduleAlreadyInitialized = errors.New("submodule already initialized")
	ErrSubmoduleNotInitialized     = errors.New("submodule not initialized")
)
type Submodule struct {
	initialized bool
	c *config.Submodule
	w *Worktree
}
func (s *Submodule) Config() *config.Submodule {
	return s.c
}
func (s *Submodule) Init() error {
	cfg, err := s.w.r.Storer.Config()
	if err != nil {
		return err
	}
	_, ok := cfg.Submodules[s.c.Name]
	if ok {
		return ErrSubmoduleAlreadyInitialized
	}
	s.initialized = true
	cfg.Submodules[s.c.Name] = s.c
	return s.w.r.Storer.SetConfig(cfg)
}
func (s *Submodule) Status() (*SubmoduleStatus, error) {
	idx, err := s.w.r.Storer.Index()
	if err != nil {
		return nil, err
	}
	return s.status(idx)
}
func (s *Submodule) status(idx *index.Index) (*SubmoduleStatus, error) {
	status := &SubmoduleStatus{
		Path: s.c.Path,
	}
	e, err := idx.Entry(s.c.Path)
	if err != nil && err != index.ErrEntryNotFound {
		return nil, err
	}
	if e != nil {
		status.Expected = e.Hash
	}
	if !s.initialized {
		return status, nil
	}
	r, err := s.Repository()
	if err != nil {
		return nil, err
	}
	head, err := r.Head()
	if err == nil {
		status.Current = head.Hash()
	}
	if err != nil && err == plumbing.ErrReferenceNotFound {
		err = nil
	}
	return status, err
}
func (s *Submodule) Repository() (*Repository, error) {
	if !s.initialized {
		return nil, ErrSubmoduleNotInitialized
	}
	storer, err := s.w.r.Storer.Module(s.c.Name)
	if err != nil {
		return nil, err
	}
	_, err = storer.Reference(plumbing.HEAD)
	if err != nil && err != plumbing.ErrReferenceNotFound {
		return nil, err
	}
	var exists bool
	if err == nil {
		exists = true
	}
	var worktree billy.Filesystem
	if worktree, err = s.w.Filesystem.Chroot(s.c.Path); err != nil {
		return nil, err
	}
	if exists {
		return Open(storer, worktree)
	}
	r, err := Init(storer, worktree)
	if err != nil {
		return nil, err
	}
	_, err = r.CreateRemote(&config.RemoteConfig{
		Name: DefaultRemoteName,
		URLs: []string{s.c.URL},
	})
	return r, err
}
func (s *Submodule) Update(o *SubmoduleUpdateOptions) error {
	return s.UpdateContext(context.Background(), o)
}
func (s *Submodule) UpdateContext(ctx context.Context, o *SubmoduleUpdateOptions) error {
	return s.update(ctx, o, plumbing.ZeroHash)
}
func (s *Submodule) update(ctx context.Context, o *SubmoduleUpdateOptions, forceHash plumbing.Hash) error {
	if !s.initialized && !o.Init {
		return ErrSubmoduleNotInitialized
	}
	if !s.initialized && o.Init {
		if err := s.Init(); err != nil {
			return err
		}
	}
	idx, err := s.w.r.Storer.Index()
	if err != nil {
		return err
	}
	hash := forceHash
	if hash.IsZero() {
		e, err := idx.Entry(s.c.Path)
		if err != nil {
			return err
		}
		hash = e.Hash
	}
	r, err := s.Repository()
	if err != nil {
		return err
	}
	if err := s.fetchAndCheckout(ctx, r, o, hash); err != nil {
		return err
	}
	return s.doRecursiveUpdate(r, o)
}
func (s *Submodule) doRecursiveUpdate(r *Repository, o *SubmoduleUpdateOptions) error {
	if o.RecurseSubmodules == NoRecurseSubmodules {
		return nil
	}
	w, err := r.Worktree()
	if err != nil {
		return err
	}
	l, err := w.Submodules()
	if err != nil {
		return err
	}
	new := &SubmoduleUpdateOptions{}
	*new = *o
	new.RecurseSubmodules--
	return l.Update(new)
}
func (s *Submodule) fetchAndCheckout(
	ctx context.Context, r *Repository, o *SubmoduleUpdateOptions, hash plumbing.Hash,
) error {
	if !o.NoFetch {
		err := r.FetchContext(ctx, &FetchOptions{Auth: o.Auth})
		if err != nil && err != NoErrAlreadyUpToDate {
			return err
		}
	}
	w, err := r.Worktree()
	if err != nil {
		return err
	}
	if err := w.Checkout(&CheckoutOptions{Hash: hash}); err != nil {
		return err
	}
	head := plumbing.NewHashReference(plumbing.HEAD, hash)
	return r.Storer.SetReference(head)
}
type Submodules []*Submodule
func (s Submodules) Init() error {
	for _, sub := range s {
		if err := sub.Init(); err != nil {
			return err
		}
	}
	return nil
}
func (s Submodules) Update(o *SubmoduleUpdateOptions) error {
	return s.UpdateContext(context.Background(), o)
}
func (s Submodules) UpdateContext(ctx context.Context, o *SubmoduleUpdateOptions) error {
	for _, sub := range s {
		if err := sub.UpdateContext(ctx, o); err != nil {
			return err
		}
	}
	return nil
}