func (r *Repository) PullContext(ctx context.Context, o *PullOptions) error {
	if r == nil {
		return errors.New("PullContext was called with a nil repository")
	}
	r.mu.Lock()
	defer r.mu.Unlock()
	remoteName := "origin"
	if o.RemoteName != "" {
		remoteName = o.RemoteName
	}
	referenceName := "master"
	if o.ReferenceName != "" {
		referenceName = string(o.ReferenceName)
	}
	pullCmd := exec.Command("git", "pull", remoteName, referenceName)
	pullCmd.Dir = r.dir
	pullOut, err := pullCmd.Output()
	if err != nil {
		log.Errorf("Hit an error pulling %v, in %v. \n\tError: %v\n\t:Log: %v", r.url, r.dir, err, string(pullOut))
		return err
	}
	if strings.HasSuffix(string(pullOut), "Already up to date.\n") {
		return ErrAlreadyUpToDate
	}
	return nil
}
PullContext runs git pull with the given cancelation context
package git
import (
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"regexp"
	"runtime/debug"
	"strconv"
	"strings"
	"sync"
	"time"
)
const (
	commitFormat = "--pretty=commit: %H%nAuthor: %an%nAuthor Email: %ae%nAuthor Date: %at%nCommitter: %cn%nCommitter Email: %ce%nCommitter Date: %ct%nSubject: %s%n"
)
var (
	commitItemRegExp = regexp.MustCompile(`(?m)Commit: (\w{40})\nAuthor: (.*)\nAuthor Email: (.*)\nAuthor Date: (.*)\nCommitter: (.*)\nCommitter Email: (.*)\nCommitter Date: (.*)\nSubject: (.*)\nBody:(.*)\nFiles:\n((^[ADRMC](\d{3})?\s+[\w-\.\/ ]+(\s+[\w-\.\/ ]+)?\n)+)*`)
	fileNameRegex    = regexp.MustCompile(`^([\w \/\.-]+)$`)
	refsRegex        = regexp.MustCompile(`(\w{40}) ([\w\/\-\.]+)`)
	newRegex         = regexp.MustCompile(`^A\s+(?P<from>[\w \/\.-]+)$`)
	goneRegex        = regexp.MustCompile(`^D\s+(?P<from>[\w \/\.-]+)$`)
	modifiedRegex    = regexp.MustCompile(`^M\s+(?P<from>[\w \/\.-]+)$`)
	renamedRegex     = regexp.MustCompile(`^R\d{3}\s+(?P<from>[\w \/\.-]+)\t(?P<to>[\w /\.-]+)$`)
	copyRegex        = regexp.MustCompile(`^C\d{3}\s+(?P<from>[\w \/\.-]+)\t+(?P<to>[\w /\.-]+)$`)
)
type Repository struct {
	mu  sync.Mutex
	dir string
	url string
}
type FetchOptions struct {
}
type PullOptions struct {
	RemoteName string
	ReferenceName ReferenceName
}
type LogOptions struct {
	From Hash
}
func (r *Repository) Remotes() (RemoteIter, error) {
	if r == nil {
		return nil, errors.New("No repository")
	}
	log.Debugf("Getting Remotes for repository %v, stored in %v", r.url, r.dir)
	remCmd := exec.Command("git", "remote", "-v")
	remCmd.Dir = r.dir
	remOut, err := remCmd.Output()
	if err != nil {
		return nil, err
	}
	remotesRegex := regexp.MustCompile(`(\w+)\s+([\w\/:\-\.@]+)\s+\((fetch|push)\)`)
	remMap := make(map[string]*RemoteConfig)
	for _, match := range remotesRegex.FindAllStringSubmatch(string(remOut), -1) {
		rName := match[1]
		rURL := match[2]
		if _, ok := remMap[rName]; !ok {
			remMap[rName] = &RemoteConfig{
				Name: rName,
			}
		}
		rcfg := remMap[rName]
		rcfg.URLs = append(rcfg.URLs, rURL)
	}
	rems := make([]Remote, 0)
	for _, rem := range remMap {
		rems = append(rems, Remote{
			c: rem,
		})
	}
	return &sliceRemoteIter{pos: 0, series: rems}, nil
}
func (r *Repository) Branches() (ReferenceIter, error) {
	log.Debugf("Getting Branches for repository %v, stored in %v", r.url, r.dir)
	if r == nil {
		return nil, errors.New("No repository")
	}
	refCmd := exec.Command("git", "show-ref")
	refCmd.Dir = r.dir
	refOut, err := refCmd.Output()
	if err != nil {
		return nil, err
	}
	refs := make([]Reference, 0)
	for _, match := range refsRegex.FindAllStringSubmatch(string(refOut), -1) {
		refs = append(refs, Reference{
			t: HashReference,
			n: ReferenceName(match[2]),
			h: NewHash(match[1]),
		})
	}
	return &sliceRefIter{pos: 0, series: refs}, nil
}
func (r *Repository) Log(opts *LogOptions) (CommitIter, error) {
	r.mu.Lock()
	log.Debugf("Calling Log on %v from: %v", r.dir, opts.From)
	if err := r.checkout(opts.From); err != nil {
		r.mu.Unlock()
		return nil, err
	}
	commits, err := r.getCommits(opts.From)
	if err != nil {
		r.mu.Unlock()
		return nil, err
	}
	r.mu.Unlock()
	return &sliceCommitIter{
		series: commits,
		pos:    0,
	}, nil
}
func (r *Repository) FetchContext(ctx context.Context, o *FetchOptions) error {
	if r == nil {
		return errors.New("FetchContext was called with a nil repository")
	}
	r.mu.Lock()
	defer r.mu.Unlock()
	fetchCmd := exec.Command("git", "fetch")
	fetchCmd.Dir = r.dir
	fetchOut, err := fetchCmd.CombinedOutput()
	if err != nil {
		log.Errorf("Hit an error fetching %v, in %v. \n\tError: %v.\n\tLog: %s", r.url, r.dir, err, fetchOut)
		return err
	}
	if len(fetchOut) == 0 {
		return ErrAlreadyUpToDate
	}
	return nil
}