func (c *RemoteConfig) Validate() error {
	if c.Name == "" {
		return ErrRemoteConfigEmptyName
	}
	if len(c.URLs) == 0 {
		return ErrRemoteConfigEmptyURL
	}
	for _, r := range c.Fetch {
		if err := r.Validate(); err != nil {
			return err
		}
	}
	if len(c.Fetch) == 0 {
		c.Fetch = []RefSpec{RefSpec(fmt.Sprintf(DefaultFetchRefSpec, c.Name))}
	}
	return nil
}
Validate validates the fields and sets the default values.
package config
import (
	"bytes"
	"errors"
	"fmt"
	"sort"
	"strconv"
	"gopkg.in/src-d/go-git.v4/internal/url"
	format "gopkg.in/src-d/go-git.v4/plumbing/format/config"
)
const (
	DefaultFetchRefSpec = "+refs/heads/*:refs/remotes/%s/*"
	DefaultPushRefSpec = "refs/heads/*:refs/heads/*"
)
type ConfigStorer interface {
	Config() (*Config, error)
	SetConfig(*Config) error
}
var (
	ErrInvalid               = errors.New("config invalid key in remote or branch")
	ErrRemoteConfigNotFound  = errors.New("remote config not found")
	ErrRemoteConfigEmptyURL  = errors.New("remote config: empty URL")
	ErrRemoteConfigEmptyName = errors.New("remote config: empty name")
)
type Config struct {
	Core struct {
		IsBare bool
		Worktree string
		CommentChar string
	}
	Pack struct {
		Window uint
	}
	Remotes map[string]*RemoteConfig
	Submodules map[string]*Submodule
	Branches map[string]*Branch
	Raw *format.Config
}
func NewConfig() *Config {
	config := &Config{
		Remotes:    make(map[string]*RemoteConfig),
		Submodules: make(map[string]*Submodule),
		Branches:   make(map[string]*Branch),
		Raw:        format.New(),
	}
	config.Pack.Window = DefaultPackWindow
	return config
}
func (c *Config) Validate() error {
	for name, r := range c.Remotes {
		if r.Name != name {
			return ErrInvalid
		}
		if err := r.Validate(); err != nil {
			return err
		}
	}
	for name, b := range c.Branches {
		if b.Name != name {
			return ErrInvalid
		}
		if err := b.Validate(); err != nil {
			return err
		}
	}
	return nil
}
const (
	remoteSection    = "remote"
	submoduleSection = "submodule"
	branchSection    = "branch"
	coreSection      = "core"
	packSection      = "pack"
	fetchKey         = "fetch"
	urlKey           = "url"
	bareKey          = "bare"
	worktreeKey      = "worktree"
	commentCharKey   = "commentChar"
	windowKey        = "window"
	mergeKey         = "merge"
	DefaultPackWindow = uint(10)
)
func (c *Config) Unmarshal(b []byte) error {
	r := bytes.NewBuffer(b)
	d := format.NewDecoder(r)
	c.Raw = format.New()
	if err := d.Decode(c.Raw); err != nil {
		return err
	}
	c.unmarshalCore()
	if err := c.unmarshalPack(); err != nil {
		return err
	}
	unmarshalSubmodules(c.Raw, c.Submodules)
	if err := c.unmarshalBranches(); err != nil {
		return err
	}
	return c.unmarshalRemotes()
}
func (c *Config) unmarshalCore() {
	s := c.Raw.Section(coreSection)
	if s.Options.Get(bareKey) == "true" {
		c.Core.IsBare = true
	}
	c.Core.Worktree = s.Options.Get(worktreeKey)
	c.Core.CommentChar = s.Options.Get(commentCharKey)
}
func (c *Config) unmarshalPack() error {
	s := c.Raw.Section(packSection)
	window := s.Options.Get(windowKey)
	if window == "" {
		c.Pack.Window = DefaultPackWindow
	} else {
		winUint, err := strconv.ParseUint(window, 10, 32)
		if err != nil {
			return err
		}
		c.Pack.Window = uint(winUint)
	}
	return nil
}
func (c *Config) unmarshalRemotes() error {
	s := c.Raw.Section(remoteSection)
	for _, sub := range s.Subsections {
		r := &RemoteConfig{}
		if err := r.unmarshal(sub); err != nil {
			return err
		}
		c.Remotes[r.Name] = r
	}
	return nil
}
func unmarshalSubmodules(fc *format.Config, submodules map[string]*Submodule) {
	s := fc.Section(submoduleSection)
	for _, sub := range s.Subsections {
		m := &Submodule{}
		m.unmarshal(sub)
		if m.Validate() == ErrModuleBadPath {
			continue
		}
		submodules[m.Name] = m
	}
}
func (c *Config) unmarshalBranches() error {
	bs := c.Raw.Section(branchSection)
	for _, sub := range bs.Subsections {
		b := &Branch{}
		if err := b.unmarshal(sub); err != nil {
			return err
		}
		c.Branches[b.Name] = b
	}
	return nil
}
func (c *Config) Marshal() ([]byte, error) {
	c.marshalCore()
	c.marshalPack()
	c.marshalRemotes()
	c.marshalSubmodules()
	c.marshalBranches()
	buf := bytes.NewBuffer(nil)
	if err := format.NewEncoder(buf).Encode(c.Raw); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}
func (c *Config) marshalCore() {
	s := c.Raw.Section(coreSection)
	s.SetOption(bareKey, fmt.Sprintf("%t", c.Core.IsBare))
	if c.Core.Worktree != "" {
		s.SetOption(worktreeKey, c.Core.Worktree)
	}
}
func (c *Config) marshalPack() {
	s := c.Raw.Section(packSection)
	if c.Pack.Window != DefaultPackWindow {
		s.SetOption(windowKey, fmt.Sprintf("%d", c.Pack.Window))
	}
}
func (c *Config) marshalRemotes() {
	s := c.Raw.Section(remoteSection)
	newSubsections := make(format.Subsections, 0, len(c.Remotes))
	added := make(map[string]bool)
	for _, subsection := range s.Subsections {
		if remote, ok := c.Remotes[subsection.Name]; ok {
			newSubsections = append(newSubsections, remote.marshal())
			added[subsection.Name] = true
		}
	}
	remoteNames := make([]string, 0, len(c.Remotes))
	for name := range c.Remotes {
		remoteNames = append(remoteNames, name)
	}
	sort.Strings(remoteNames)
	for _, name := range remoteNames {
		if !added[name] {
			newSubsections = append(newSubsections, c.Remotes[name].marshal())
		}
	}
	s.Subsections = newSubsections
}
func (c *Config) marshalSubmodules() {
	s := c.Raw.Section(submoduleSection)
	s.Subsections = make(format.Subsections, len(c.Submodules))
	var i int
	for _, r := range c.Submodules {
		section := r.marshal()
		section.RemoveOption(pathKey)
		s.Subsections[i] = section
		i++
	}
}
func (c *Config) marshalBranches() {
	s := c.Raw.Section(branchSection)
	newSubsections := make(format.Subsections, 0, len(c.Branches))
	added := make(map[string]bool)
	for _, subsection := range s.Subsections {
		if branch, ok := c.Branches[subsection.Name]; ok {
			newSubsections = append(newSubsections, branch.marshal())
			added[subsection.Name] = true
		}
	}
	branchNames := make([]string, 0, len(c.Branches))
	for name := range c.Branches {
		branchNames = append(branchNames, name)
	}
	sort.Strings(branchNames)
	for _, name := range branchNames {
		if !added[name] {
			newSubsections = append(newSubsections, c.Branches[name].marshal())
		}
	}
	s.Subsections = newSubsections
}
type RemoteConfig struct {
	Name string
	URLs []string
	Fetch []RefSpec
	raw *format.Subsection
}