2 Star 0 Fork 7

hequan / go-git

forked from Gitee 极速下载 / go-git 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
repository_test.go 69.28 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673
package git
import (
"bytes"
"context"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"time"
"golang.org/x/crypto/openpgp"
"golang.org/x/crypto/openpgp/armor"
openpgperr "golang.org/x/crypto/openpgp/errors"
"gopkg.in/src-d/go-git.v4/config"
"gopkg.in/src-d/go-git.v4/plumbing"
"gopkg.in/src-d/go-git.v4/plumbing/cache"
"gopkg.in/src-d/go-git.v4/plumbing/object"
"gopkg.in/src-d/go-git.v4/plumbing/storer"
"gopkg.in/src-d/go-git.v4/plumbing/transport"
"gopkg.in/src-d/go-git.v4/storage"
"gopkg.in/src-d/go-git.v4/storage/filesystem"
"gopkg.in/src-d/go-git.v4/storage/memory"
. "gopkg.in/check.v1"
"gopkg.in/src-d/go-billy.v4/memfs"
"gopkg.in/src-d/go-billy.v4/osfs"
"gopkg.in/src-d/go-billy.v4/util"
"gopkg.in/src-d/go-git-fixtures.v3"
)
type RepositorySuite struct {
BaseSuite
}
var _ = Suite(&RepositorySuite{})
func (s *RepositorySuite) TestInit(c *C) {
r, err := Init(memory.NewStorage(), memfs.New())
c.Assert(err, IsNil)
c.Assert(r, NotNil)
cfg, err := r.Config()
c.Assert(err, IsNil)
c.Assert(cfg.Core.IsBare, Equals, false)
}
func (s *RepositorySuite) TestInitNonStandardDotGit(c *C) {
dir, err := ioutil.TempDir("", "init-non-standard")
c.Assert(err, IsNil)
c.Assert(os.RemoveAll(dir), IsNil)
fs := osfs.New(dir)
dot, _ := fs.Chroot("storage")
storage := filesystem.NewStorage(dot, cache.NewObjectLRUDefault())
wt, _ := fs.Chroot("worktree")
r, err := Init(storage, wt)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
f, err := fs.Open(fs.Join("worktree", ".git"))
c.Assert(err, IsNil)
all, err := ioutil.ReadAll(f)
c.Assert(err, IsNil)
c.Assert(string(all), Equals, fmt.Sprintf("gitdir: %s\n", filepath.Join("..", "storage")))
cfg, err := r.Config()
c.Assert(err, IsNil)
c.Assert(cfg.Core.Worktree, Equals, filepath.Join("..", "worktree"))
}
func (s *RepositorySuite) TestInitStandardDotGit(c *C) {
dir, err := ioutil.TempDir("", "init-standard")
c.Assert(err, IsNil)
c.Assert(os.RemoveAll(dir), IsNil)
fs := osfs.New(dir)
dot, _ := fs.Chroot(".git")
storage := filesystem.NewStorage(dot, cache.NewObjectLRUDefault())
r, err := Init(storage, fs)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
l, err := fs.ReadDir(".git")
c.Assert(err, IsNil)
c.Assert(len(l) > 0, Equals, true)
cfg, err := r.Config()
c.Assert(err, IsNil)
c.Assert(cfg.Core.Worktree, Equals, "")
}
func (s *RepositorySuite) TestInitBare(c *C) {
r, err := Init(memory.NewStorage(), nil)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
cfg, err := r.Config()
c.Assert(err, IsNil)
c.Assert(cfg.Core.IsBare, Equals, true)
}
func (s *RepositorySuite) TestInitAlreadyExists(c *C) {
st := memory.NewStorage()
r, err := Init(st, nil)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
r, err = Init(st, nil)
c.Assert(err, Equals, ErrRepositoryAlreadyExists)
c.Assert(r, IsNil)
}
func (s *RepositorySuite) TestOpen(c *C) {
st := memory.NewStorage()
r, err := Init(st, memfs.New())
c.Assert(err, IsNil)
c.Assert(r, NotNil)
r, err = Open(st, memfs.New())
c.Assert(err, IsNil)
c.Assert(r, NotNil)
}
func (s *RepositorySuite) TestOpenBare(c *C) {
st := memory.NewStorage()
r, err := Init(st, nil)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
r, err = Open(st, nil)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
}
func (s *RepositorySuite) TestOpenBareMissingWorktree(c *C) {
st := memory.NewStorage()
r, err := Init(st, memfs.New())
c.Assert(err, IsNil)
c.Assert(r, NotNil)
r, err = Open(st, nil)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
}
func (s *RepositorySuite) TestOpenNotExists(c *C) {
r, err := Open(memory.NewStorage(), nil)
c.Assert(err, Equals, ErrRepositoryNotExists)
c.Assert(r, IsNil)
}
func (s *RepositorySuite) TestClone(c *C) {
r, err := Clone(memory.NewStorage(), nil, &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
remotes, err := r.Remotes()
c.Assert(err, IsNil)
c.Assert(remotes, HasLen, 1)
}
func (s *RepositorySuite) TestCloneContext(c *C) {
ctx, cancel := context.WithCancel(context.Background())
cancel()
r, err := CloneContext(ctx, memory.NewStorage(), nil, &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(r, NotNil)
c.Assert(err, ErrorMatches, ".* context canceled")
}
func (s *RepositorySuite) TestCloneWithTags(c *C) {
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(),
)
r, err := Clone(memory.NewStorage(), nil, &CloneOptions{URL: url, Tags: NoTags})
c.Assert(err, IsNil)
remotes, err := r.Remotes()
c.Assert(err, IsNil)
c.Assert(remotes, HasLen, 1)
i, err := r.References()
c.Assert(err, IsNil)
var count int
i.ForEach(func(r *plumbing.Reference) error { count++; return nil })
c.Assert(count, Equals, 3)
}
func (s *RepositorySuite) TestCreateRemoteAndRemote(c *C) {
r, _ := Init(memory.NewStorage(), nil)
remote, err := r.CreateRemote(&config.RemoteConfig{
Name: "foo",
URLs: []string{"http://foo/foo.git"},
})
c.Assert(err, IsNil)
c.Assert(remote.Config().Name, Equals, "foo")
alt, err := r.Remote("foo")
c.Assert(err, IsNil)
c.Assert(alt, Not(Equals), remote)
c.Assert(alt.Config().Name, Equals, "foo")
}
func (s *RepositorySuite) TestCreateRemoteInvalid(c *C) {
r, _ := Init(memory.NewStorage(), nil)
remote, err := r.CreateRemote(&config.RemoteConfig{})
c.Assert(err, Equals, config.ErrRemoteConfigEmptyName)
c.Assert(remote, IsNil)
}
func (s *RepositorySuite) TestCreateRemoteAnonymous(c *C) {
r, _ := Init(memory.NewStorage(), nil)
remote, err := r.CreateRemoteAnonymous(&config.RemoteConfig{
Name: "anonymous",
URLs: []string{"http://foo/foo.git"},
})
c.Assert(err, IsNil)
c.Assert(remote.Config().Name, Equals, "anonymous")
}
func (s *RepositorySuite) TestCreateRemoteAnonymousInvalidName(c *C) {
r, _ := Init(memory.NewStorage(), nil)
remote, err := r.CreateRemoteAnonymous(&config.RemoteConfig{
Name: "not_anonymous",
URLs: []string{"http://foo/foo.git"},
})
c.Assert(err, Equals, ErrAnonymousRemoteName)
c.Assert(remote, IsNil)
}
func (s *RepositorySuite) TestCreateRemoteAnonymousInvalid(c *C) {
r, _ := Init(memory.NewStorage(), nil)
remote, err := r.CreateRemoteAnonymous(&config.RemoteConfig{})
c.Assert(err, Equals, config.ErrRemoteConfigEmptyName)
c.Assert(remote, IsNil)
}
func (s *RepositorySuite) TestDeleteRemote(c *C) {
r, _ := Init(memory.NewStorage(), nil)
_, err := r.CreateRemote(&config.RemoteConfig{
Name: "foo",
URLs: []string{"http://foo/foo.git"},
})
c.Assert(err, IsNil)
err = r.DeleteRemote("foo")
c.Assert(err, IsNil)
alt, err := r.Remote("foo")
c.Assert(err, Equals, ErrRemoteNotFound)
c.Assert(alt, IsNil)
}
func (s *RepositorySuite) TestCreateBranchAndBranch(c *C) {
r, _ := Init(memory.NewStorage(), nil)
testBranch := &config.Branch{
Name: "foo",
Remote: "origin",
Merge: "refs/heads/foo",
}
err := r.CreateBranch(testBranch)
c.Assert(err, IsNil)
cfg, err := r.Config()
c.Assert(err, IsNil)
c.Assert(len(cfg.Branches), Equals, 1)
branch := cfg.Branches["foo"]
c.Assert(branch.Name, Equals, testBranch.Name)
c.Assert(branch.Remote, Equals, testBranch.Remote)
c.Assert(branch.Merge, Equals, testBranch.Merge)
branch, err = r.Branch("foo")
c.Assert(err, IsNil)
c.Assert(branch.Name, Equals, testBranch.Name)
c.Assert(branch.Remote, Equals, testBranch.Remote)
c.Assert(branch.Merge, Equals, testBranch.Merge)
}
func (s *RepositorySuite) TestCreateBranchUnmarshal(c *C) {
r, _ := Init(memory.NewStorage(), nil)
expected := []byte(`[core]
bare = true
[remote "foo"]
url = http://foo/foo.git
fetch = +refs/heads/*:refs/remotes/foo/*
[branch "foo"]
remote = origin
merge = refs/heads/foo
[branch "master"]
remote = origin
merge = refs/heads/master
`)
_, err := r.CreateRemote(&config.RemoteConfig{
Name: "foo",
URLs: []string{"http://foo/foo.git"},
})
c.Assert(err, IsNil)
testBranch1 := &config.Branch{
Name: "master",
Remote: "origin",
Merge: "refs/heads/master",
}
testBranch2 := &config.Branch{
Name: "foo",
Remote: "origin",
Merge: "refs/heads/foo",
}
err = r.CreateBranch(testBranch1)
err = r.CreateBranch(testBranch2)
c.Assert(err, IsNil)
cfg, err := r.Config()
c.Assert(err, IsNil)
marshaled, err := cfg.Marshal()
c.Assert(string(expected), Equals, string(marshaled))
}
func (s *RepositorySuite) TestBranchInvalid(c *C) {
r, _ := Init(memory.NewStorage(), nil)
branch, err := r.Branch("foo")
c.Assert(err, NotNil)
c.Assert(branch, IsNil)
}
func (s *RepositorySuite) TestCreateBranchInvalid(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.CreateBranch(&config.Branch{})
c.Assert(err, NotNil)
testBranch := &config.Branch{
Name: "foo",
Remote: "origin",
Merge: "refs/heads/foo",
}
err = r.CreateBranch(testBranch)
c.Assert(err, IsNil)
err = r.CreateBranch(testBranch)
c.Assert(err, NotNil)
}
func (s *RepositorySuite) TestDeleteBranch(c *C) {
r, _ := Init(memory.NewStorage(), nil)
testBranch := &config.Branch{
Name: "foo",
Remote: "origin",
Merge: "refs/heads/foo",
}
err := r.CreateBranch(testBranch)
c.Assert(err, IsNil)
err = r.DeleteBranch("foo")
c.Assert(err, IsNil)
b, err := r.Branch("foo")
c.Assert(err, Equals, ErrBranchNotFound)
c.Assert(b, IsNil)
err = r.DeleteBranch("foo")
c.Assert(err, Equals, ErrBranchNotFound)
}
func (s *RepositorySuite) TestPlainInit(c *C) {
dir, err := ioutil.TempDir("", "plain-init")
c.Assert(err, IsNil)
defer os.RemoveAll(dir)
r, err := PlainInit(dir, true)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
cfg, err := r.Config()
c.Assert(err, IsNil)
c.Assert(cfg.Core.IsBare, Equals, true)
}
func (s *RepositorySuite) TestPlainInitAlreadyExists(c *C) {
dir, err := ioutil.TempDir("", "plain-init")
c.Assert(err, IsNil)
defer os.RemoveAll(dir)
r, err := PlainInit(dir, true)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
r, err = PlainInit(dir, true)
c.Assert(err, Equals, ErrRepositoryAlreadyExists)
c.Assert(r, IsNil)
}
func (s *RepositorySuite) TestPlainOpen(c *C) {
dir, err := ioutil.TempDir("", "plain-open")
c.Assert(err, IsNil)
defer os.RemoveAll(dir)
r, err := PlainInit(dir, false)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
r, err = PlainOpen(dir)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
}
func (s *RepositorySuite) TestPlainOpenBare(c *C) {
dir, err := ioutil.TempDir("", "plain-open")
c.Assert(err, IsNil)
defer os.RemoveAll(dir)
r, err := PlainInit(dir, true)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
r, err = PlainOpen(dir)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
}
func (s *RepositorySuite) TestPlainOpenNotBare(c *C) {
dir, err := ioutil.TempDir("", "plain-open")
c.Assert(err, IsNil)
defer os.RemoveAll(dir)
r, err := PlainInit(dir, false)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
r, err = PlainOpen(filepath.Join(dir, ".git"))
c.Assert(err, IsNil)
c.Assert(r, NotNil)
}
func (s *RepositorySuite) testPlainOpenGitFile(c *C, f func(string, string) string) {
dir, err := ioutil.TempDir("", "plain-open")
c.Assert(err, IsNil)
defer os.RemoveAll(dir)
r, err := PlainInit(dir, true)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
altDir, err := ioutil.TempDir("", "plain-open")
c.Assert(err, IsNil)
defer os.RemoveAll(altDir)
err = ioutil.WriteFile(filepath.Join(altDir, ".git"), []byte(f(dir, altDir)), 0644)
c.Assert(err, IsNil)
r, err = PlainOpen(altDir)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
}
func (s *RepositorySuite) TestPlainOpenBareAbsoluteGitDirFile(c *C) {
s.testPlainOpenGitFile(c, func(dir, altDir string) string {
return fmt.Sprintf("gitdir: %s\n", dir)
})
}
func (s *RepositorySuite) TestPlainOpenBareAbsoluteGitDirFileNoEOL(c *C) {
s.testPlainOpenGitFile(c, func(dir, altDir string) string {
return fmt.Sprintf("gitdir: %s", dir)
})
}
func (s *RepositorySuite) TestPlainOpenBareRelativeGitDirFile(c *C) {
s.testPlainOpenGitFile(c, func(dir, altDir string) string {
dir, err := filepath.Rel(altDir, dir)
c.Assert(err, IsNil)
return fmt.Sprintf("gitdir: %s\n", dir)
})
}
func (s *RepositorySuite) TestPlainOpenBareRelativeGitDirFileNoEOL(c *C) {
s.testPlainOpenGitFile(c, func(dir, altDir string) string {
dir, err := filepath.Rel(altDir, dir)
c.Assert(err, IsNil)
return fmt.Sprintf("gitdir: %s\n", dir)
})
}
func (s *RepositorySuite) TestPlainOpenBareRelativeGitDirFileTrailingGarbage(c *C) {
dir, err := ioutil.TempDir("", "plain-open")
c.Assert(err, IsNil)
defer os.RemoveAll(dir)
r, err := PlainInit(dir, true)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
altDir, err := ioutil.TempDir("", "plain-open")
c.Assert(err, IsNil)
err = ioutil.WriteFile(filepath.Join(altDir, ".git"), []byte(fmt.Sprintf("gitdir: %s\nTRAILING", altDir)), 0644)
c.Assert(err, IsNil)
r, err = PlainOpen(altDir)
c.Assert(err, Equals, ErrRepositoryNotExists)
c.Assert(r, IsNil)
}
func (s *RepositorySuite) TestPlainOpenBareRelativeGitDirFileBadPrefix(c *C) {
dir, err := ioutil.TempDir("", "plain-open")
c.Assert(err, IsNil)
defer os.RemoveAll(dir)
r, err := PlainInit(dir, true)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
altDir, err := ioutil.TempDir("", "plain-open")
c.Assert(err, IsNil)
err = ioutil.WriteFile(filepath.Join(altDir, ".git"), []byte(fmt.Sprintf("xgitdir: %s\n", dir)), 0644)
c.Assert(err, IsNil)
r, err = PlainOpen(altDir)
c.Assert(err, ErrorMatches, ".*gitdir.*")
c.Assert(r, IsNil)
}
func (s *RepositorySuite) TestPlainOpenNotExists(c *C) {
r, err := PlainOpen("/not-exists/")
c.Assert(err, Equals, ErrRepositoryNotExists)
c.Assert(r, IsNil)
}
func (s *RepositorySuite) TestPlainOpenDetectDotGit(c *C) {
dir, err := ioutil.TempDir("", "plain-open")
c.Assert(err, IsNil)
defer os.RemoveAll(dir)
subdir := filepath.Join(dir, "a", "b")
err = os.MkdirAll(subdir, 0755)
c.Assert(err, IsNil)
r, err := PlainInit(dir, false)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
opt := &PlainOpenOptions{DetectDotGit: true}
r, err = PlainOpenWithOptions(subdir, opt)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
}
func (s *RepositorySuite) TestPlainOpenNotExistsDetectDotGit(c *C) {
dir, err := ioutil.TempDir("", "plain-open")
c.Assert(err, IsNil)
defer os.RemoveAll(dir)
opt := &PlainOpenOptions{DetectDotGit: true}
r, err := PlainOpenWithOptions(dir, opt)
c.Assert(err, Equals, ErrRepositoryNotExists)
c.Assert(r, IsNil)
}
func (s *RepositorySuite) TestPlainClone(c *C) {
r, err := PlainClone(c.MkDir(), false, &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
remotes, err := r.Remotes()
c.Assert(err, IsNil)
c.Assert(remotes, HasLen, 1)
cfg, err := r.Config()
c.Assert(err, IsNil)
c.Assert(cfg.Branches, HasLen, 1)
c.Assert(cfg.Branches["master"].Name, Equals, "master")
}
func (s *RepositorySuite) TestPlainCloneWithRemoteName(c *C) {
r, err := PlainClone(c.MkDir(), false, &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
RemoteName: "test",
})
c.Assert(err, IsNil)
remote, err := r.Remote("test")
c.Assert(err, IsNil)
c.Assert(remote, NotNil)
}
func (s *RepositorySuite) TestPlainCloneOverExistingGitDirectory(c *C) {
tmpDir := c.MkDir()
r, err := PlainInit(tmpDir, false)
c.Assert(r, NotNil)
c.Assert(err, IsNil)
r, err = PlainClone(tmpDir, false, &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(r, IsNil)
c.Assert(err, Equals, ErrRepositoryAlreadyExists)
}
func (s *RepositorySuite) TestPlainCloneContextCancel(c *C) {
ctx, cancel := context.WithCancel(context.Background())
cancel()
r, err := PlainCloneContext(ctx, c.MkDir(), false, &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(r, NotNil)
c.Assert(err, ErrorMatches, ".* context canceled")
}
func (s *RepositorySuite) TestPlainCloneContextNonExistentWithExistentDir(c *C) {
ctx, cancel := context.WithCancel(context.Background())
cancel()
tmpDir := c.MkDir()
repoDir := tmpDir
r, err := PlainCloneContext(ctx, repoDir, false, &CloneOptions{
URL: "incorrectOnPurpose",
})
c.Assert(r, NotNil)
c.Assert(err, Equals, transport.ErrRepositoryNotFound)
_, err = os.Stat(repoDir)
c.Assert(os.IsNotExist(err), Equals, false)
names, err := ioutil.ReadDir(repoDir)
c.Assert(err, IsNil)
c.Assert(names, HasLen, 0)
}
func (s *RepositorySuite) TestPlainCloneContextNonExistentWithNonExistentDir(c *C) {
ctx, cancel := context.WithCancel(context.Background())
cancel()
tmpDir := c.MkDir()
repoDir := filepath.Join(tmpDir, "repoDir")
r, err := PlainCloneContext(ctx, repoDir, false, &CloneOptions{
URL: "incorrectOnPurpose",
})
c.Assert(r, NotNil)
c.Assert(err, Equals, transport.ErrRepositoryNotFound)
_, err = os.Stat(repoDir)
c.Assert(os.IsNotExist(err), Equals, true)
}
func (s *RepositorySuite) TestPlainCloneContextNonExistentWithNotDir(c *C) {
ctx, cancel := context.WithCancel(context.Background())
cancel()
tmpDir := c.MkDir()
repoDir := filepath.Join(tmpDir, "repoDir")
f, err := os.Create(repoDir)
c.Assert(err, IsNil)
c.Assert(f.Close(), IsNil)
r, err := PlainCloneContext(ctx, repoDir, false, &CloneOptions{
URL: "incorrectOnPurpose",
})
c.Assert(r, IsNil)
c.Assert(err, ErrorMatches, ".*not a directory.*")
fi, err := os.Stat(repoDir)
c.Assert(err, IsNil)
c.Assert(fi.IsDir(), Equals, false)
}
func (s *RepositorySuite) TestPlainCloneContextNonExistentWithNotEmptyDir(c *C) {
ctx, cancel := context.WithCancel(context.Background())
cancel()
tmpDir := c.MkDir()
repoDirPath := filepath.Join(tmpDir, "repoDir")
err := os.Mkdir(repoDirPath, 0777)
c.Assert(err, IsNil)
dummyFile := filepath.Join(repoDirPath, "dummyFile")
err = ioutil.WriteFile(dummyFile, []byte(fmt.Sprint("dummyContent")), 0644)
c.Assert(err, IsNil)
r, err := PlainCloneContext(ctx, repoDirPath, false, &CloneOptions{
URL: "incorrectOnPurpose",
})
c.Assert(r, NotNil)
c.Assert(err, Equals, transport.ErrRepositoryNotFound)
_, err = os.Stat(dummyFile)
c.Assert(err, IsNil)
}
func (s *RepositorySuite) TestPlainCloneContextNonExistingOverExistingGitDirectory(c *C) {
ctx, cancel := context.WithCancel(context.Background())
cancel()
tmpDir := c.MkDir()
r, err := PlainInit(tmpDir, false)
c.Assert(r, NotNil)
c.Assert(err, IsNil)
r, err = PlainCloneContext(ctx, tmpDir, false, &CloneOptions{
URL: "incorrectOnPurpose",
})
c.Assert(r, IsNil)
c.Assert(err, Equals, ErrRepositoryAlreadyExists)
}
func (s *RepositorySuite) TestPlainCloneWithRecurseSubmodules(c *C) {
if testing.Short() {
c.Skip("skipping test in short mode.")
}
dir, err := ioutil.TempDir("", "plain-clone-submodule")
c.Assert(err, IsNil)
defer os.RemoveAll(dir)
path := fixtures.ByTag("submodule").One().Worktree().Root()
r, err := PlainClone(dir, false, &CloneOptions{
URL: path,
RecurseSubmodules: DefaultSubmoduleRecursionDepth,
})
c.Assert(err, IsNil)
cfg, err := r.Config()
c.Assert(err, IsNil)
c.Assert(cfg.Remotes, HasLen, 1)
c.Assert(cfg.Branches, HasLen, 1)
c.Assert(cfg.Submodules, HasLen, 2)
}
func (s *RepositorySuite) TestPlainCloneNoCheckout(c *C) {
dir, err := ioutil.TempDir("", "plain-clone-no-checkout")
c.Assert(err, IsNil)
defer os.RemoveAll(dir)
path := fixtures.ByTag("submodule").One().Worktree().Root()
r, err := PlainClone(dir, false, &CloneOptions{
URL: path,
NoCheckout: true,
RecurseSubmodules: DefaultSubmoduleRecursionDepth,
})
c.Assert(err, IsNil)
h, err := r.Head()
c.Assert(err, IsNil)
c.Assert(h.Hash().String(), Equals, "b685400c1f9316f350965a5993d350bc746b0bf4")
fi, err := osfs.New(dir).ReadDir("")
c.Assert(err, IsNil)
c.Assert(fi, HasLen, 1) // .git
}
func (s *RepositorySuite) TestFetch(c *C) {
r, _ := Init(memory.NewStorage(), nil)
_, err := r.CreateRemote(&config.RemoteConfig{
Name: DefaultRemoteName,
URLs: []string{s.GetBasicLocalRepositoryURL()},
})
c.Assert(err, IsNil)
c.Assert(r.Fetch(&FetchOptions{}), IsNil)
remotes, err := r.Remotes()
c.Assert(err, IsNil)
c.Assert(remotes, HasLen, 1)
_, err = r.Head()
c.Assert(err, Equals, plumbing.ErrReferenceNotFound)
branch, err := r.Reference("refs/remotes/origin/master", false)
c.Assert(err, IsNil)
c.Assert(branch, NotNil)
c.Assert(branch.Type(), Equals, plumbing.HashReference)
c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
}
func (s *RepositorySuite) TestFetchContext(c *C) {
r, _ := Init(memory.NewStorage(), nil)
_, err := r.CreateRemote(&config.RemoteConfig{
Name: DefaultRemoteName,
URLs: []string{s.GetBasicLocalRepositoryURL()},
})
c.Assert(err, IsNil)
ctx, cancel := context.WithCancel(context.Background())
cancel()
c.Assert(r.FetchContext(ctx, &FetchOptions{}), NotNil)
}
func (s *RepositorySuite) TestCloneWithProgress(c *C) {
fs := memfs.New()
buf := bytes.NewBuffer(nil)
_, err := Clone(memory.NewStorage(), fs, &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
Progress: buf,
})
c.Assert(err, IsNil)
c.Assert(buf.Len(), Not(Equals), 0)
}
func (s *RepositorySuite) TestCloneDeep(c *C) {
fs := memfs.New()
r, _ := Init(memory.NewStorage(), fs)
head, err := r.Head()
c.Assert(err, Equals, plumbing.ErrReferenceNotFound)
c.Assert(head, IsNil)
err = r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
remotes, err := r.Remotes()
c.Assert(err, IsNil)
c.Assert(remotes, HasLen, 1)
head, err = r.Reference(plumbing.HEAD, false)
c.Assert(err, IsNil)
c.Assert(head, NotNil)
c.Assert(head.Type(), Equals, plumbing.SymbolicReference)
c.Assert(head.Target().String(), Equals, "refs/heads/master")
branch, err := r.Reference(head.Target(), false)
c.Assert(err, IsNil)
c.Assert(branch, NotNil)
c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
branch, err = r.Reference("refs/remotes/origin/master", false)
c.Assert(err, IsNil)
c.Assert(branch, NotNil)
c.Assert(branch.Type(), Equals, plumbing.HashReference)
c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
fi, err := fs.ReadDir("")
c.Assert(err, IsNil)
c.Assert(fi, HasLen, 8)
}
func (s *RepositorySuite) TestCloneConfig(c *C) {
r, _ := Init(memory.NewStorage(), nil)
head, err := r.Head()
c.Assert(err, Equals, plumbing.ErrReferenceNotFound)
c.Assert(head, IsNil)
err = r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
cfg, err := r.Config()
c.Assert(err, IsNil)
c.Assert(cfg.Core.IsBare, Equals, true)
c.Assert(cfg.Remotes, HasLen, 1)
c.Assert(cfg.Remotes["origin"].Name, Equals, "origin")
c.Assert(cfg.Remotes["origin"].URLs, HasLen, 1)
c.Assert(cfg.Branches, HasLen, 1)
c.Assert(cfg.Branches["master"].Name, Equals, "master")
}
func (s *RepositorySuite) TestCloneSingleBranchAndNonHEAD(c *C) {
r, _ := Init(memory.NewStorage(), nil)
head, err := r.Head()
c.Assert(err, Equals, plumbing.ErrReferenceNotFound)
c.Assert(head, IsNil)
err = r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
ReferenceName: plumbing.ReferenceName("refs/heads/branch"),
SingleBranch: true,
})
c.Assert(err, IsNil)
remotes, err := r.Remotes()
c.Assert(err, IsNil)
c.Assert(remotes, HasLen, 1)
cfg, err := r.Config()
c.Assert(err, IsNil)
c.Assert(cfg.Branches, HasLen, 1)
c.Assert(cfg.Branches["branch"].Name, Equals, "branch")
c.Assert(cfg.Branches["branch"].Remote, Equals, "origin")
c.Assert(cfg.Branches["branch"].Merge, Equals, plumbing.ReferenceName("refs/heads/branch"))
head, err = r.Reference(plumbing.HEAD, false)
c.Assert(err, IsNil)
c.Assert(head, NotNil)
c.Assert(head.Type(), Equals, plumbing.SymbolicReference)
c.Assert(head.Target().String(), Equals, "refs/heads/branch")
branch, err := r.Reference(head.Target(), false)
c.Assert(err, IsNil)
c.Assert(branch, NotNil)
c.Assert(branch.Hash().String(), Equals, "e8d3ffab552895c19b9fcf7aa264d277cde33881")
branch, err = r.Reference("refs/remotes/origin/branch", false)
c.Assert(err, IsNil)
c.Assert(branch, NotNil)
c.Assert(branch.Type(), Equals, plumbing.HashReference)
c.Assert(branch.Hash().String(), Equals, "e8d3ffab552895c19b9fcf7aa264d277cde33881")
}
func (s *RepositorySuite) TestCloneSingleBranch(c *C) {
r, _ := Init(memory.NewStorage(), nil)
head, err := r.Head()
c.Assert(err, Equals, plumbing.ErrReferenceNotFound)
c.Assert(head, IsNil)
err = r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
SingleBranch: true,
})
c.Assert(err, IsNil)
remotes, err := r.Remotes()
c.Assert(err, IsNil)
c.Assert(remotes, HasLen, 1)
cfg, err := r.Config()
c.Assert(err, IsNil)
c.Assert(cfg.Branches, HasLen, 1)
c.Assert(cfg.Branches["master"].Name, Equals, "master")
c.Assert(cfg.Branches["master"].Remote, Equals, "origin")
c.Assert(cfg.Branches["master"].Merge, Equals, plumbing.ReferenceName("refs/heads/master"))
head, err = r.Reference(plumbing.HEAD, false)
c.Assert(err, IsNil)
c.Assert(head, NotNil)
c.Assert(head.Type(), Equals, plumbing.SymbolicReference)
c.Assert(head.Target().String(), Equals, "refs/heads/master")
branch, err := r.Reference(head.Target(), false)
c.Assert(err, IsNil)
c.Assert(branch, NotNil)
c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
branch, err = r.Reference("refs/remotes/origin/master", false)
c.Assert(err, IsNil)
c.Assert(branch, NotNil)
c.Assert(branch.Type(), Equals, plumbing.HashReference)
c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
}
func (s *RepositorySuite) TestCloneSingleTag(c *C) {
r, _ := Init(memory.NewStorage(), nil)
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(),
)
err := r.clone(context.Background(), &CloneOptions{
URL: url,
SingleBranch: true,
ReferenceName: plumbing.ReferenceName("refs/tags/commit-tag"),
})
c.Assert(err, IsNil)
branch, err := r.Reference("refs/tags/commit-tag", false)
c.Assert(err, IsNil)
c.Assert(branch, NotNil)
conf, err := r.Config()
c.Assert(err, IsNil)
originRemote := conf.Remotes["origin"]
c.Assert(originRemote, NotNil)
c.Assert(originRemote.Fetch, HasLen, 1)
c.Assert(originRemote.Fetch[0].String(), Equals, "+refs/tags/commit-tag:refs/tags/commit-tag")
}
func (s *RepositorySuite) TestCloneDetachedHEAD(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
ReferenceName: plumbing.ReferenceName("refs/tags/v1.0.0"),
})
c.Assert(err, IsNil)
cfg, err := r.Config()
c.Assert(err, IsNil)
c.Assert(cfg.Branches, HasLen, 0)
head, err := r.Reference(plumbing.HEAD, false)
c.Assert(err, IsNil)
c.Assert(head, NotNil)
c.Assert(head.Type(), Equals, plumbing.HashReference)
c.Assert(head.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
count := 0
objects, err := r.Objects()
c.Assert(err, IsNil)
objects.ForEach(func(object.Object) error { count++; return nil })
c.Assert(count, Equals, 28)
}
func (s *RepositorySuite) TestCloneDetachedHEADAndSingle(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
ReferenceName: plumbing.ReferenceName("refs/tags/v1.0.0"),
SingleBranch: true,
})
c.Assert(err, IsNil)
cfg, err := r.Config()
c.Assert(err, IsNil)
c.Assert(cfg.Branches, HasLen, 0)
head, err := r.Reference(plumbing.HEAD, false)
c.Assert(err, IsNil)
c.Assert(head, NotNil)
c.Assert(head.Type(), Equals, plumbing.HashReference)
c.Assert(head.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
count := 0
objects, err := r.Objects()
c.Assert(err, IsNil)
objects.ForEach(func(object.Object) error { count++; return nil })
c.Assert(count, Equals, 28)
}
func (s *RepositorySuite) TestCloneDetachedHEADAndShallow(c *C) {
r, _ := Init(memory.NewStorage(), memfs.New())
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
ReferenceName: plumbing.ReferenceName("refs/tags/v1.0.0"),
Depth: 1,
})
c.Assert(err, IsNil)
cfg, err := r.Config()
c.Assert(err, IsNil)
c.Assert(cfg.Branches, HasLen, 0)
head, err := r.Reference(plumbing.HEAD, false)
c.Assert(err, IsNil)
c.Assert(head, NotNil)
c.Assert(head.Type(), Equals, plumbing.HashReference)
c.Assert(head.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
count := 0
objects, err := r.Objects()
c.Assert(err, IsNil)
objects.ForEach(func(object.Object) error { count++; return nil })
c.Assert(count, Equals, 15)
}
func (s *RepositorySuite) TestCloneDetachedHEADAnnotatedTag(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetLocalRepositoryURL(fixtures.ByTag("tags").One()),
ReferenceName: plumbing.ReferenceName("refs/tags/annotated-tag"),
})
c.Assert(err, IsNil)
cfg, err := r.Config()
c.Assert(err, IsNil)
c.Assert(cfg.Branches, HasLen, 0)
head, err := r.Reference(plumbing.HEAD, false)
c.Assert(err, IsNil)
c.Assert(head, NotNil)
c.Assert(head.Type(), Equals, plumbing.HashReference)
c.Assert(head.Hash().String(), Equals, "f7b877701fbf855b44c0a9e86f3fdce2c298b07f")
count := 0
objects, err := r.Objects()
c.Assert(err, IsNil)
objects.ForEach(func(object.Object) error { count++; return nil })
c.Assert(count, Equals, 7)
}
func (s *RepositorySuite) TestPush(c *C) {
url := c.MkDir()
server, err := PlainInit(url, true)
c.Assert(err, IsNil)
_, err = s.Repository.CreateRemote(&config.RemoteConfig{
Name: "test",
URLs: []string{url},
})
c.Assert(err, IsNil)
err = s.Repository.Push(&PushOptions{
RemoteName: "test",
})
c.Assert(err, IsNil)
AssertReferences(c, server, map[string]string{
"refs/heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
"refs/heads/branch": "e8d3ffab552895c19b9fcf7aa264d277cde33881",
})
AssertReferences(c, s.Repository, map[string]string{
"refs/remotes/test/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
"refs/remotes/test/branch": "e8d3ffab552895c19b9fcf7aa264d277cde33881",
})
}
func (s *RepositorySuite) TestPushContext(c *C) {
url := c.MkDir()
_, err := PlainInit(url, true)
c.Assert(err, IsNil)
_, err = s.Repository.CreateRemote(&config.RemoteConfig{
Name: "foo",
URLs: []string{url},
})
c.Assert(err, IsNil)
ctx, cancel := context.WithCancel(context.Background())
cancel()
err = s.Repository.PushContext(ctx, &PushOptions{
RemoteName: "foo",
})
c.Assert(err, NotNil)
}
// installPreReceiveHook installs a pre-receive hook in the .git
// directory at path which prints message m before exiting
// successfully.
func installPreReceiveHook(c *C, path, m string) {
hooks := filepath.Join(path, "hooks")
err := os.MkdirAll(hooks, 0777)
c.Assert(err, IsNil)
err = ioutil.WriteFile(filepath.Join(hooks, "pre-receive"), preReceiveHook(m), 0777)
c.Assert(err, IsNil)
}
func (s *RepositorySuite) TestPushWithProgress(c *C) {
url := c.MkDir()
server, err := PlainInit(url, true)
c.Assert(err, IsNil)
m := "Receiving..."
installPreReceiveHook(c, url, m)
_, err = s.Repository.CreateRemote(&config.RemoteConfig{
Name: "bar",
URLs: []string{url},
})
c.Assert(err, IsNil)
var p bytes.Buffer
err = s.Repository.Push(&PushOptions{
RemoteName: "bar",
Progress: &p,
})
c.Assert(err, IsNil)
AssertReferences(c, server, map[string]string{
"refs/heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
"refs/heads/branch": "e8d3ffab552895c19b9fcf7aa264d277cde33881",
})
c.Assert((&p).Bytes(), DeepEquals, []byte(m))
}
func (s *RepositorySuite) TestPushDepth(c *C) {
url := c.MkDir()
server, err := PlainClone(url, true, &CloneOptions{
URL: fixtures.Basic().One().DotGit().Root(),
})
c.Assert(err, IsNil)
r, err := Clone(memory.NewStorage(), memfs.New(), &CloneOptions{
URL: url,
Depth: 1,
})
c.Assert(err, IsNil)
err = util.WriteFile(r.wt, "foo", nil, 0755)
c.Assert(err, IsNil)
w, err := r.Worktree()
c.Assert(err, IsNil)
_, err = w.Add("foo")
c.Assert(err, IsNil)
hash, err := w.Commit("foo", &CommitOptions{
Author: defaultSignature(),
Committer: defaultSignature(),
})
c.Assert(err, IsNil)
err = r.Push(&PushOptions{})
c.Assert(err, IsNil)
AssertReferences(c, server, map[string]string{
"refs/heads/master": hash.String(),
})
AssertReferences(c, r, map[string]string{
"refs/remotes/origin/master": hash.String(),
})
}
func (s *RepositorySuite) TestPushNonExistentRemote(c *C) {
srcFs := fixtures.Basic().One().DotGit()
sto := filesystem.NewStorage(srcFs, cache.NewObjectLRUDefault())
r, err := Open(sto, srcFs)
c.Assert(err, IsNil)
err = r.Push(&PushOptions{RemoteName: "myremote"})
c.Assert(err, ErrorMatches, ".*remote not found.*")
}
func (s *RepositorySuite) TestLog(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
cIter, err := r.Log(&LogOptions{
From: plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"),
})
c.Assert(err, IsNil)
commitOrder := []plumbing.Hash{
plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"),
plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"),
}
for _, o := range commitOrder {
commit, err := cIter.Next()
c.Assert(err, IsNil)
c.Assert(commit.Hash, Equals, o)
}
_, err = cIter.Next()
c.Assert(err, Equals, io.EOF)
}
func (s *RepositorySuite) TestLogAll(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
rIter, err := r.Storer.IterReferences()
c.Assert(err, IsNil)
refCount := 0
err = rIter.ForEach(func(ref *plumbing.Reference) error {
refCount++
return nil
})
c.Assert(err, IsNil)
c.Assert(refCount, Equals, 5)
cIter, err := r.Log(&LogOptions{
All: true,
})
c.Assert(err, IsNil)
commitOrder := []plumbing.Hash{
plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"),
plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881"),
plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"),
plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"),
plumbing.NewHash("1669dce138d9b841a518c64b10914d88f5e488ea"),
plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"),
plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"),
plumbing.NewHash("a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69"),
plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"),
}
for _, o := range commitOrder {
commit, err := cIter.Next()
c.Assert(err, IsNil)
c.Assert(commit.Hash, Equals, o)
}
_, err = cIter.Next()
c.Assert(err, Equals, io.EOF)
cIter.Close()
}
func (s *RepositorySuite) TestLogAllMissingReferences(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
err = r.Storer.RemoveReference(plumbing.HEAD)
c.Assert(err, IsNil)
rIter, err := r.Storer.IterReferences()
c.Assert(err, IsNil)
refCount := 0
err = rIter.ForEach(func(ref *plumbing.Reference) error {
refCount++
return nil
})
c.Assert(err, IsNil)
c.Assert(refCount, Equals, 4)
err = r.Storer.SetReference(plumbing.NewHashReference(plumbing.ReferenceName("DUMMY"), plumbing.NewHash("DUMMY")))
c.Assert(err, IsNil)
rIter, err = r.Storer.IterReferences()
c.Assert(err, IsNil)
refCount = 0
err = rIter.ForEach(func(ref *plumbing.Reference) error {
refCount++
return nil
})
c.Assert(err, IsNil)
c.Assert(refCount, Equals, 5)
cIter, err := r.Log(&LogOptions{
All: true,
})
c.Assert(cIter, NotNil)
c.Assert(err, IsNil)
cCount := 0
cIter.ForEach(func(c *object.Commit) error {
cCount++
return nil
})
c.Assert(cCount, Equals, 9)
_, err = cIter.Next()
c.Assert(err, Equals, io.EOF)
cIter.Close()
}
func (s *RepositorySuite) TestLogAllOrderByTime(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
cIter, err := r.Log(&LogOptions{
Order: LogOrderCommitterTime,
All: true,
})
c.Assert(err, IsNil)
commitOrder := []plumbing.Hash{
plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"),
plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881"),
plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"),
plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"),
plumbing.NewHash("1669dce138d9b841a518c64b10914d88f5e488ea"),
plumbing.NewHash("a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69"),
plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"),
plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"),
plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"),
}
for _, o := range commitOrder {
commit, err := cIter.Next()
c.Assert(err, IsNil)
c.Assert(commit.Hash, Equals, o)
}
_, err = cIter.Next()
c.Assert(err, Equals, io.EOF)
cIter.Close()
}
func (s *RepositorySuite) TestLogHead(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
cIter, err := r.Log(&LogOptions{})
c.Assert(err, IsNil)
commitOrder := []plumbing.Hash{
plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"),
plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"),
plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"),
plumbing.NewHash("1669dce138d9b841a518c64b10914d88f5e488ea"),
plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"),
plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"),
plumbing.NewHash("a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69"),
plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"),
}
for _, o := range commitOrder {
commit, err := cIter.Next()
c.Assert(err, IsNil)
c.Assert(commit.Hash, Equals, o)
}
_, err = cIter.Next()
c.Assert(err, Equals, io.EOF)
}
func (s *RepositorySuite) TestLogError(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
_, err = r.Log(&LogOptions{
From: plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
})
c.Assert(err, NotNil)
}
func (s *RepositorySuite) TestLogFileNext(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
fileName := "vendor/foo.go"
cIter, err := r.Log(&LogOptions{FileName: &fileName})
c.Assert(err, IsNil)
commitOrder := []plumbing.Hash{
plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"),
}
for _, o := range commitOrder {
commit, err := cIter.Next()
c.Assert(err, IsNil)
c.Assert(commit.Hash, Equals, o)
}
_, err = cIter.Next()
c.Assert(err, Equals, io.EOF)
}
func (s *RepositorySuite) TestLogFileForEach(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
fileName := "php/crappy.php"
cIter, err := r.Log(&LogOptions{FileName: &fileName})
c.Assert(err, IsNil)
defer cIter.Close()
commitOrder := []plumbing.Hash{
plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"),
}
expectedIndex := 0
cIter.ForEach(func(commit *object.Commit) error {
expectedCommitHash := commitOrder[expectedIndex]
c.Assert(commit.Hash.String(), Equals, expectedCommitHash.String())
expectedIndex++
return nil
})
c.Assert(expectedIndex, Equals, 1)
}
func (s *RepositorySuite) TestLogNonHeadFile(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
fileName := "README"
cIter, err := r.Log(&LogOptions{FileName: &fileName})
c.Assert(err, IsNil)
defer cIter.Close()
_, err = cIter.Next()
c.Assert(err, Equals, io.EOF)
}
func (s *RepositorySuite) TestLogAllFileForEach(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
fileName := "README"
cIter, err := r.Log(&LogOptions{FileName: &fileName, All: true})
c.Assert(err, IsNil)
defer cIter.Close()
commitOrder := []plumbing.Hash{
plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881"),
}
expectedIndex := 0
cIter.ForEach(func(commit *object.Commit) error {
expectedCommitHash := commitOrder[expectedIndex]
c.Assert(commit.Hash.String(), Equals, expectedCommitHash.String())
expectedIndex++
return nil
})
c.Assert(expectedIndex, Equals, 1)
}
func (s *RepositorySuite) TestLogInvalidFile(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
// Throwing in a file that does not exist
fileName := "vendor/foo12.go"
cIter, err := r.Log(&LogOptions{FileName: &fileName})
// Not raising an error since `git log -- vendor/foo12.go` responds silently
c.Assert(err, IsNil)
defer cIter.Close()
_, err = cIter.Next()
c.Assert(err, Equals, io.EOF)
}
func (s *RepositorySuite) TestLogFileInitialCommit(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
fileName := "LICENSE"
cIter, err := r.Log(&LogOptions{
Order: LogOrderCommitterTime,
FileName: &fileName,
})
c.Assert(err, IsNil)
defer cIter.Close()
commitOrder := []plumbing.Hash{
plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"),
}
expectedIndex := 0
cIter.ForEach(func(commit *object.Commit) error {
expectedCommitHash := commitOrder[expectedIndex]
c.Assert(commit.Hash.String(), Equals, expectedCommitHash.String())
expectedIndex++
return nil
})
c.Assert(expectedIndex, Equals, 1)
}
func (s *RepositorySuite) TestLogFileWithOtherParamsFail(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
fileName := "vendor/foo.go"
cIter, err := r.Log(&LogOptions{
Order: LogOrderCommitterTime,
FileName: &fileName,
From: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"),
})
c.Assert(err, IsNil)
defer cIter.Close()
_, iterErr := cIter.Next()
c.Assert(iterErr, Equals, io.EOF)
}
func (s *RepositorySuite) TestLogFileWithOtherParamsPass(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
fileName := "LICENSE"
cIter, err := r.Log(&LogOptions{
Order: LogOrderCommitterTime,
FileName: &fileName,
From: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"),
})
c.Assert(err, IsNil)
commitVal, iterErr := cIter.Next()
c.Assert(iterErr, Equals, nil)
c.Assert(commitVal.Hash.String(), Equals, "b029517f6300c2da0f4b651b8642506cd6aaf45d")
_, iterErr = cIter.Next()
c.Assert(iterErr, Equals, io.EOF)
}
func (s *RepositorySuite) TestCommit(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
hash := plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47")
commit, err := r.CommitObject(hash)
c.Assert(err, IsNil)
c.Assert(commit.Hash.IsZero(), Equals, false)
c.Assert(commit.Hash, Equals, commit.ID())
c.Assert(commit.Hash, Equals, hash)
c.Assert(commit.Type(), Equals, plumbing.CommitObject)
tree, err := commit.Tree()
c.Assert(err, IsNil)
c.Assert(tree.Hash.IsZero(), Equals, false)
c.Assert(commit.Author.Email, Equals, "daniel@lordran.local")
}
func (s *RepositorySuite) TestCommits(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
c.Assert(err, IsNil)
count := 0
commits, err := r.CommitObjects()
c.Assert(err, IsNil)
for {
commit, err := commits.Next()
if err != nil {
break
}
count++
c.Assert(commit.Hash.IsZero(), Equals, false)
c.Assert(commit.Hash, Equals, commit.ID())
c.Assert(commit.Type(), Equals, plumbing.CommitObject)
}
c.Assert(count, Equals, 9)
}
func (s *RepositorySuite) TestBlob(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
blob, err := r.BlobObject(plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"))
c.Assert(err, NotNil)
c.Assert(blob, IsNil)
blobHash := plumbing.NewHash("9a48f23120e880dfbe41f7c9b7b708e9ee62a492")
blob, err = r.BlobObject(blobHash)
c.Assert(err, IsNil)
c.Assert(blob.Hash.IsZero(), Equals, false)
c.Assert(blob.Hash, Equals, blob.ID())
c.Assert(blob.Hash, Equals, blobHash)
c.Assert(blob.Type(), Equals, plumbing.BlobObject)
}
func (s *RepositorySuite) TestBlobs(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
c.Assert(err, IsNil)
count := 0
blobs, err := r.BlobObjects()
c.Assert(err, IsNil)
for {
blob, err := blobs.Next()
if err != nil {
break
}
count++
c.Assert(blob.Hash.IsZero(), Equals, false)
c.Assert(blob.Hash, Equals, blob.ID())
c.Assert(blob.Type(), Equals, plumbing.BlobObject)
}
c.Assert(count, Equals, 10)
}
func (s *RepositorySuite) TestTagObject(c *C) {
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(),
)
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
hash := plumbing.NewHash("ad7897c0fb8e7d9a9ba41fa66072cf06095a6cfc")
tag, err := r.TagObject(hash)
c.Assert(err, IsNil)
c.Assert(tag.Hash.IsZero(), Equals, false)
c.Assert(tag.Hash, Equals, hash)
c.Assert(tag.Type(), Equals, plumbing.TagObject)
}
func (s *RepositorySuite) TestTags(c *C) {
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(),
)
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
count := 0
tags, err := r.Tags()
c.Assert(err, IsNil)
tags.ForEach(func(tag *plumbing.Reference) error {
count++
c.Assert(tag.Hash().IsZero(), Equals, false)
c.Assert(tag.Name().IsTag(), Equals, true)
return nil
})
c.Assert(count, Equals, 5)
}
func (s *RepositorySuite) TestCreateTagLightweight(c *C) {
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(),
)
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
expected, err := r.Head()
c.Assert(err, IsNil)
ref, err := r.CreateTag("foobar", expected.Hash(), nil)
c.Assert(err, IsNil)
c.Assert(ref, NotNil)
actual, err := r.Tag("foobar")
c.Assert(err, IsNil)
c.Assert(expected.Hash(), Equals, actual.Hash())
}
func (s *RepositorySuite) TestCreateTagLightweightExists(c *C) {
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(),
)
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
expected, err := r.Head()
c.Assert(err, IsNil)
ref, err := r.CreateTag("lightweight-tag", expected.Hash(), nil)
c.Assert(ref, IsNil)
c.Assert(err, Equals, ErrTagExists)
}
func (s *RepositorySuite) TestCreateTagAnnotated(c *C) {
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(),
)
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
h, err := r.Head()
c.Assert(err, IsNil)
expectedHash := h.Hash()
ref, err := r.CreateTag("foobar", expectedHash, &CreateTagOptions{
Tagger: defaultSignature(),
Message: "foo bar baz qux",
})
c.Assert(err, IsNil)
tag, err := r.Tag("foobar")
c.Assert(err, IsNil)
obj, err := r.TagObject(tag.Hash())
c.Assert(err, IsNil)
c.Assert(ref, DeepEquals, tag)
c.Assert(obj.Hash, Equals, ref.Hash())
c.Assert(obj.Type(), Equals, plumbing.TagObject)
c.Assert(obj.Target, Equals, expectedHash)
}
func (s *RepositorySuite) TestCreateTagAnnotatedBadOpts(c *C) {
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(),
)
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
h, err := r.Head()
c.Assert(err, IsNil)
expectedHash := h.Hash()
ref, err := r.CreateTag("foobar", expectedHash, &CreateTagOptions{
Message: "foo bar baz qux",
})
c.Assert(ref, IsNil)
c.Assert(err, Equals, ErrMissingTagger)
ref, err = r.CreateTag("foobar", expectedHash, &CreateTagOptions{
Tagger: defaultSignature(),
})
c.Assert(ref, IsNil)
c.Assert(err, Equals, ErrMissingMessage)
}
func (s *RepositorySuite) TestCreateTagAnnotatedBadHash(c *C) {
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(),
)
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
ref, err := r.CreateTag("foobar", plumbing.ZeroHash, &CreateTagOptions{
Tagger: defaultSignature(),
Message: "foo bar baz qux",
})
c.Assert(ref, IsNil)
c.Assert(err, Equals, plumbing.ErrObjectNotFound)
}
func (s *RepositorySuite) TestCreateTagSigned(c *C) {
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(),
)
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
h, err := r.Head()
c.Assert(err, IsNil)
key := commitSignKey(c, true)
_, err = r.CreateTag("foobar", h.Hash(), &CreateTagOptions{
Tagger: defaultSignature(),
Message: "foo bar baz qux",
SignKey: key,
})
c.Assert(err, IsNil)
tag, err := r.Tag("foobar")
c.Assert(err, IsNil)
obj, err := r.TagObject(tag.Hash())
c.Assert(err, IsNil)
// Verify the tag.
pks := new(bytes.Buffer)
pkw, err := armor.Encode(pks, openpgp.PublicKeyType, nil)
c.Assert(err, IsNil)
err = key.Serialize(pkw)
c.Assert(err, IsNil)
err = pkw.Close()
c.Assert(err, IsNil)
actual, err := obj.Verify(pks.String())
c.Assert(err, IsNil)
c.Assert(actual.PrimaryKey, DeepEquals, key.PrimaryKey)
}
func (s *RepositorySuite) TestCreateTagSignedBadKey(c *C) {
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(),
)
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
h, err := r.Head()
c.Assert(err, IsNil)
key := commitSignKey(c, false)
_, err = r.CreateTag("foobar", h.Hash(), &CreateTagOptions{
Tagger: defaultSignature(),
Message: "foo bar baz qux",
SignKey: key,
})
c.Assert(err, Equals, openpgperr.InvalidArgumentError("signing key is encrypted"))
}
func (s *RepositorySuite) TestCreateTagCanonicalize(c *C) {
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(),
)
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
h, err := r.Head()
c.Assert(err, IsNil)
key := commitSignKey(c, true)
_, err = r.CreateTag("foobar", h.Hash(), &CreateTagOptions{
Tagger: defaultSignature(),
Message: "\n\nfoo bar baz qux\n\nsome message here",
SignKey: key,
})
c.Assert(err, IsNil)
tag, err := r.Tag("foobar")
c.Assert(err, IsNil)
obj, err := r.TagObject(tag.Hash())
c.Assert(err, IsNil)
// Assert the new canonicalized message.
c.Assert(obj.Message, Equals, "foo bar baz qux\n\nsome message here\n")
// Verify the tag.
pks := new(bytes.Buffer)
pkw, err := armor.Encode(pks, openpgp.PublicKeyType, nil)
c.Assert(err, IsNil)
err = key.Serialize(pkw)
c.Assert(err, IsNil)
err = pkw.Close()
c.Assert(err, IsNil)
actual, err := obj.Verify(pks.String())
c.Assert(err, IsNil)
c.Assert(actual.PrimaryKey, DeepEquals, key.PrimaryKey)
}
func (s *RepositorySuite) TestTagLightweight(c *C) {
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(),
)
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
expected := plumbing.NewHash("f7b877701fbf855b44c0a9e86f3fdce2c298b07f")
tag, err := r.Tag("lightweight-tag")
c.Assert(err, IsNil)
actual := tag.Hash()
c.Assert(expected, Equals, actual)
}
func (s *RepositorySuite) TestTagLightweightMissingTag(c *C) {
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(),
)
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
tag, err := r.Tag("lightweight-tag-tag")
c.Assert(tag, IsNil)
c.Assert(err, Equals, ErrTagNotFound)
}
func (s *RepositorySuite) TestDeleteTag(c *C) {
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(),
)
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
err = r.DeleteTag("lightweight-tag")
c.Assert(err, IsNil)
_, err = r.Tag("lightweight-tag")
c.Assert(err, Equals, ErrTagNotFound)
}
func (s *RepositorySuite) TestDeleteTagMissingTag(c *C) {
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(),
)
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
err = r.DeleteTag("lightweight-tag-tag")
c.Assert(err, Equals, ErrTagNotFound)
}
func (s *RepositorySuite) TestDeleteTagAnnotated(c *C) {
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(),
)
dir, err := ioutil.TempDir("", "go-git-test-deletetag-annotated")
c.Assert(err, IsNil)
defer os.RemoveAll(dir) // clean up
fss := filesystem.NewStorage(osfs.New(dir), cache.NewObjectLRUDefault())
r, _ := Init(fss, nil)
err = r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
ref, err := r.Tag("annotated-tag")
c.Assert(ref, NotNil)
c.Assert(err, IsNil)
obj, err := r.TagObject(ref.Hash())
c.Assert(obj, NotNil)
c.Assert(err, IsNil)
err = r.DeleteTag("annotated-tag")
c.Assert(err, IsNil)
_, err = r.Tag("annotated-tag")
c.Assert(err, Equals, ErrTagNotFound)
// Run a prune (and repack, to ensure that we are GCing everything regardless
// of the fixture in use) and try to get the tag object again.
//
// The repo needs to be re-opened after the repack.
err = r.Prune(PruneOptions{Handler: r.DeleteObject})
c.Assert(err, IsNil)
err = r.RepackObjects(&RepackConfig{})
c.Assert(err, IsNil)
r, err = PlainOpen(dir)
c.Assert(r, NotNil)
c.Assert(err, IsNil)
// Now check to see if the GC was effective in removing the tag object.
obj, err = r.TagObject(ref.Hash())
c.Assert(obj, IsNil)
c.Assert(err, Equals, plumbing.ErrObjectNotFound)
}
func (s *RepositorySuite) TestDeleteTagAnnotatedUnpacked(c *C) {
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(),
)
dir, err := ioutil.TempDir("", "go-git-test-deletetag-annotated-unpacked")
c.Assert(err, IsNil)
defer os.RemoveAll(dir) // clean up
fss := filesystem.NewStorage(osfs.New(dir), cache.NewObjectLRUDefault())
r, _ := Init(fss, nil)
err = r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
// Create a tag for the deletion test. This ensures that the ultimate loose
// object will be unpacked (as we aren't doing anything that should pack it),
// so that we can effectively test that a prune deletes it, without having to
// resort to a repack.
h, err := r.Head()
c.Assert(err, IsNil)
expectedHash := h.Hash()
ref, err := r.CreateTag("foobar", expectedHash, &CreateTagOptions{
Tagger: defaultSignature(),
Message: "foo bar baz qux",
})
c.Assert(err, IsNil)
tag, err := r.Tag("foobar")
c.Assert(err, IsNil)
obj, err := r.TagObject(tag.Hash())
c.Assert(obj, NotNil)
c.Assert(err, IsNil)
err = r.DeleteTag("foobar")
c.Assert(err, IsNil)
_, err = r.Tag("foobar")
c.Assert(err, Equals, ErrTagNotFound)
// As mentioned, only run a prune. We are not testing for packed objects
// here.
err = r.Prune(PruneOptions{Handler: r.DeleteObject})
c.Assert(err, IsNil)
// Now check to see if the GC was effective in removing the tag object.
obj, err = r.TagObject(ref.Hash())
c.Assert(obj, IsNil)
c.Assert(err, Equals, plumbing.ErrObjectNotFound)
}
func (s *RepositorySuite) TestBranches(c *C) {
f := fixtures.ByURL("https://github.com/git-fixtures/root-references.git").One()
sto := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault())
r, err := Open(sto, f.DotGit())
c.Assert(err, IsNil)
count := 0
branches, err := r.Branches()
c.Assert(err, IsNil)
branches.ForEach(func(branch *plumbing.Reference) error {
count++
c.Assert(branch.Hash().IsZero(), Equals, false)
c.Assert(branch.Name().IsBranch(), Equals, true)
return nil
})
c.Assert(count, Equals, 8)
}
func (s *RepositorySuite) TestNotes(c *C) {
// TODO add fixture with Notes
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(),
)
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
count := 0
notes, err := r.Notes()
c.Assert(err, IsNil)
notes.ForEach(func(note *plumbing.Reference) error {
count++
c.Assert(note.Hash().IsZero(), Equals, false)
c.Assert(note.Name().IsNote(), Equals, true)
return nil
})
c.Assert(count, Equals, 0)
}
func (s *RepositorySuite) TestTree(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
c.Assert(err, IsNil)
invalidHash := plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
tree, err := r.TreeObject(invalidHash)
c.Assert(tree, IsNil)
c.Assert(err, NotNil)
hash := plumbing.NewHash("dbd3641b371024f44d0e469a9c8f5457b0660de1")
tree, err = r.TreeObject(hash)
c.Assert(err, IsNil)
c.Assert(tree.Hash.IsZero(), Equals, false)
c.Assert(tree.Hash, Equals, tree.ID())
c.Assert(tree.Hash, Equals, hash)
c.Assert(tree.Type(), Equals, plumbing.TreeObject)
c.Assert(len(tree.Entries), Not(Equals), 0)
}
func (s *RepositorySuite) TestTrees(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
c.Assert(err, IsNil)
count := 0
trees, err := r.TreeObjects()
c.Assert(err, IsNil)
for {
tree, err := trees.Next()
if err != nil {
break
}
count++
c.Assert(tree.Hash.IsZero(), Equals, false)
c.Assert(tree.Hash, Equals, tree.ID())
c.Assert(tree.Type(), Equals, plumbing.TreeObject)
c.Assert(len(tree.Entries), Not(Equals), 0)
}
c.Assert(count, Equals, 12)
}
func (s *RepositorySuite) TestTagObjects(c *C) {
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(),
)
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
count := 0
tags, err := r.TagObjects()
c.Assert(err, IsNil)
tags.ForEach(func(tag *object.Tag) error {
count++
c.Assert(tag.Hash.IsZero(), Equals, false)
c.Assert(tag.Type(), Equals, plumbing.TagObject)
return nil
})
refs, _ := r.References()
refs.ForEach(func(ref *plumbing.Reference) error {
return nil
})
c.Assert(count, Equals, 4)
}
func (s *RepositorySuite) TestCommitIterClosePanic(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
c.Assert(err, IsNil)
commits, err := r.CommitObjects()
c.Assert(err, IsNil)
commits.Close()
}
func (s *RepositorySuite) TestRef(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
c.Assert(err, IsNil)
ref, err := r.Reference(plumbing.HEAD, false)
c.Assert(err, IsNil)
c.Assert(ref.Name(), Equals, plumbing.HEAD)
ref, err = r.Reference(plumbing.HEAD, true)
c.Assert(err, IsNil)
c.Assert(ref.Name(), Equals, plumbing.ReferenceName("refs/heads/master"))
}
func (s *RepositorySuite) TestRefs(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
c.Assert(err, IsNil)
c.Assert(err, IsNil)
iter, err := r.References()
c.Assert(err, IsNil)
c.Assert(iter, NotNil)
}
func (s *RepositorySuite) TestObject(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
c.Assert(err, IsNil)
hash := plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
o, err := r.Object(plumbing.CommitObject, hash)
c.Assert(err, IsNil)
c.Assert(o.ID().IsZero(), Equals, false)
c.Assert(o.Type(), Equals, plumbing.CommitObject)
}
func (s *RepositorySuite) TestObjects(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
c.Assert(err, IsNil)
count := 0
objects, err := r.Objects()
c.Assert(err, IsNil)
for {
o, err := objects.Next()
if err != nil {
break
}
count++
c.Assert(o.ID().IsZero(), Equals, false)
c.Assert(o.Type(), Not(Equals), plumbing.AnyObject)
}
c.Assert(count, Equals, 31)
}
func (s *RepositorySuite) TestObjectNotFound(c *C) {
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()})
c.Assert(err, IsNil)
hash := plumbing.NewHash("0a3fb06ff80156fb153bcdcc58b5e16c2d27625c")
tag, err := r.Object(plumbing.TagObject, hash)
c.Assert(err, DeepEquals, plumbing.ErrObjectNotFound)
c.Assert(tag, IsNil)
}
func (s *RepositorySuite) TestWorktree(c *C) {
def := memfs.New()
r, _ := Init(memory.NewStorage(), def)
w, err := r.Worktree()
c.Assert(err, IsNil)
c.Assert(w.Filesystem, Equals, def)
}
func (s *RepositorySuite) TestWorktreeBare(c *C) {
r, _ := Init(memory.NewStorage(), nil)
w, err := r.Worktree()
c.Assert(err, Equals, ErrIsBareRepository)
c.Assert(w, IsNil)
}
func (s *RepositorySuite) TestResolveRevision(c *C) {
f := fixtures.ByURL("https://github.com/git-fixtures/basic.git").One()
sto := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault())
r, err := Open(sto, f.DotGit())
c.Assert(err, IsNil)
datas := map[string]string{
"HEAD": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
"heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
"heads/master~1": "918c48b83bd081e863dbe1b80f8998f058cd8294",
"refs/heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
"refs/heads/master~2^^~": "b029517f6300c2da0f4b651b8642506cd6aaf45d",
"refs/tags/v1.0.0": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
"refs/remotes/origin/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
"refs/remotes/origin/HEAD": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
"HEAD~2^^~": "b029517f6300c2da0f4b651b8642506cd6aaf45d",
"HEAD~3^2": "a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69",
"HEAD~3^2^0": "a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69",
"HEAD~2^{/binary file}": "35e85108805c84807bc66a02d91535e1e24b38b9",
"HEAD~^{/!-some}": "1669dce138d9b841a518c64b10914d88f5e488ea",
"master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
"branch": "e8d3ffab552895c19b9fcf7aa264d277cde33881",
"v1.0.0": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
"branch~1": "918c48b83bd081e863dbe1b80f8998f058cd8294",
"v1.0.0~1": "918c48b83bd081e863dbe1b80f8998f058cd8294",
"master~1": "918c48b83bd081e863dbe1b80f8998f058cd8294",
"918c48b83bd081e863dbe1b80f8998f058cd8294": "918c48b83bd081e863dbe1b80f8998f058cd8294",
}
for rev, hash := range datas {
h, err := r.ResolveRevision(plumbing.Revision(rev))
c.Assert(err, IsNil, Commentf("while checking %s", rev))
c.Check(h.String(), Equals, hash, Commentf("while checking %s", rev))
}
}
func (s *RepositorySuite) TestResolveRevisionAnnotated(c *C) {
f := fixtures.ByURL("https://github.com/git-fixtures/tags.git").One()
sto := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault())
r, err := Open(sto, f.DotGit())
c.Assert(err, IsNil)
datas := map[string]string{
"refs/tags/annotated-tag": "f7b877701fbf855b44c0a9e86f3fdce2c298b07f",
"b742a2a9fa0afcfa9a6fad080980fbc26b007c69": "f7b877701fbf855b44c0a9e86f3fdce2c298b07f",
}
for rev, hash := range datas {
h, err := r.ResolveRevision(plumbing.Revision(rev))
c.Assert(err, IsNil, Commentf("while checking %s", rev))
c.Check(h.String(), Equals, hash, Commentf("while checking %s", rev))
}
}
func (s *RepositorySuite) TestResolveRevisionWithErrors(c *C) {
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/basic.git").One(),
)
r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: url})
c.Assert(err, IsNil)
headRef, err := r.Head()
c.Assert(err, IsNil)
ref := plumbing.NewHashReference("refs/heads/918c48b83bd081e863dbe1b80f8998f058cd8294", headRef.Hash())
err = r.Storer.SetReference(ref)
c.Assert(err, IsNil)
datas := map[string]string{
"efs/heads/master~": "reference not found",
"HEAD^3": `Revision invalid : "3" found must be 0, 1 or 2 after "^"`,
"HEAD^{/whatever}": `No commit message match regexp : "whatever"`,
"4e1243bd22c66e76c2ba9eddc1f91394e57f9f83": "reference not found",
}
for rev, rerr := range datas {
_, err := r.ResolveRevision(plumbing.Revision(rev))
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, rerr)
}
}
func (s *RepositorySuite) testRepackObjects(
c *C, deleteTime time.Time, expectedPacks int) {
srcFs := fixtures.ByTag("unpacked").One().DotGit()
var sto storage.Storer
var err error
sto = filesystem.NewStorage(srcFs, cache.NewObjectLRUDefault())
los := sto.(storer.LooseObjectStorer)
c.Assert(los, NotNil)
numLooseStart := 0
err = los.ForEachObjectHash(func(_ plumbing.Hash) error {
numLooseStart++
return nil
})
c.Assert(err, IsNil)
c.Assert(numLooseStart > 0, Equals, true)
pos := sto.(storer.PackedObjectStorer)
c.Assert(los, NotNil)
packs, err := pos.ObjectPacks()
c.Assert(err, IsNil)
numPacksStart := len(packs)
c.Assert(numPacksStart > 1, Equals, true)
r, err := Open(sto, srcFs)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
err = r.RepackObjects(&RepackConfig{
OnlyDeletePacksOlderThan: deleteTime,
})
c.Assert(err, IsNil)
numLooseEnd := 0
err = los.ForEachObjectHash(func(_ plumbing.Hash) error {
numLooseEnd++
return nil
})
c.Assert(err, IsNil)
c.Assert(numLooseEnd, Equals, 0)
packs, err = pos.ObjectPacks()
c.Assert(err, IsNil)
numPacksEnd := len(packs)
c.Assert(numPacksEnd, Equals, expectedPacks)
}
func (s *RepositorySuite) TestRepackObjects(c *C) {
if testing.Short() {
c.Skip("skipping test in short mode.")
}
s.testRepackObjects(c, time.Time{}, 1)
}
func (s *RepositorySuite) TestRepackObjectsWithNoDelete(c *C) {
if testing.Short() {
c.Skip("skipping test in short mode.")
}
s.testRepackObjects(c, time.Unix(0, 1), 3)
}
func ExecuteOnPath(c *C, path string, cmds ...string) error {
for _, cmd := range cmds {
err := executeOnPath(path, cmd)
c.Assert(err, IsNil)
}
return nil
}
func executeOnPath(path, cmd string) error {
args := strings.Split(cmd, " ")
c := exec.Command(args[0], args[1:]...)
c.Dir = path
c.Env = os.Environ()
buf := bytes.NewBuffer(nil)
c.Stderr = buf
c.Stdout = buf
return c.Run()
}
func (s *RepositorySuite) TestBrokenMultipleShallowFetch(c *C) {
r, _ := Init(memory.NewStorage(), nil)
_, err := r.CreateRemote(&config.RemoteConfig{
Name: DefaultRemoteName,
URLs: []string{s.GetBasicLocalRepositoryURL()},
})
c.Assert(err, IsNil)
c.Assert(r.Fetch(&FetchOptions{
Depth: 2,
RefSpecs: []config.RefSpec{config.RefSpec("refs/heads/master:refs/heads/master")},
}), IsNil)
shallows, err := r.Storer.Shallow()
c.Assert(err, IsNil)
c.Assert(len(shallows), Equals, 1)
ref, err := r.Reference("refs/heads/master", true)
c.Assert(err, IsNil)
cobj, err := r.CommitObject(ref.Hash())
c.Assert(err, IsNil)
c.Assert(cobj, NotNil)
err = object.NewCommitPreorderIter(cobj, nil, nil).ForEach(func(c *object.Commit) error {
for _, ph := range c.ParentHashes {
for _, h := range shallows {
if ph == h {
return storer.ErrStop
}
}
}
return nil
})
c.Assert(err, IsNil)
c.Assert(r.Fetch(&FetchOptions{
Depth: 5,
RefSpecs: []config.RefSpec{config.RefSpec("refs/heads/*:refs/heads/*")},
}), IsNil)
shallows, err = r.Storer.Shallow()
c.Assert(err, IsNil)
c.Assert(len(shallows), Equals, 3)
ref, err = r.Reference("refs/heads/master", true)
c.Assert(err, IsNil)
cobj, err = r.CommitObject(ref.Hash())
c.Assert(err, IsNil)
c.Assert(cobj, NotNil)
err = object.NewCommitPreorderIter(cobj, nil, nil).ForEach(func(c *object.Commit) error {
for _, ph := range c.ParentHashes {
for _, h := range shallows {
if ph == h {
return storer.ErrStop
}
}
}
return nil
})
c.Assert(err, IsNil)
}
func BenchmarkObjects(b *testing.B) {
if err := fixtures.Init(); err != nil {
b.Fatal(err)
}
defer func() {
if err := fixtures.Clean(); err != nil {
b.Fatal(err)
}
}()
for _, f := range fixtures.ByTag("packfile") {
if f.DotGitHash == plumbing.ZeroHash {
continue
}
b.Run(f.URL, func(b *testing.B) {
fs := f.DotGit()
storer := filesystem.NewStorage(fs, cache.NewObjectLRUDefault())
worktree, err := fs.Chroot(filepath.Dir(fs.Root()))
if err != nil {
b.Fatal(err)
}
repo, err := Open(storer, worktree)
if err != nil {
b.Fatal(err)
}
for i := 0; i < b.N; i++ {
iter, err := repo.Objects()
if err != nil {
b.Fatal(err)
}
for {
_, err := iter.Next()
if err == io.EOF {
break
}
if err != nil {
b.Fatal(err)
}
}
iter.Close()
}
})
}
}
Go
1
https://gitee.com/hequan2020/go-git.git
git@gitee.com:hequan2020/go-git.git
hequan2020
go-git
go-git
master

搜索帮助

53164aa7 5694891 3bd8fe86 5694891