1 Star 0 Fork 7

TESLA/go-git

forked from Gitee 极速下载/go-git 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
worktree_test.go 47.99 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007
package git
import (
"bytes"
"context"
"errors"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"runtime"
"testing"
"time"
"gopkg.in/src-d/go-git.v4/config"
"gopkg.in/src-d/go-git.v4/plumbing"
"gopkg.in/src-d/go-git.v4/plumbing/filemode"
"gopkg.in/src-d/go-git.v4/plumbing/format/gitignore"
"gopkg.in/src-d/go-git.v4/plumbing/format/index"
"gopkg.in/src-d/go-git.v4/plumbing/object"
"gopkg.in/src-d/go-git.v4/storage/memory"
"golang.org/x/text/unicode/norm"
. "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 WorktreeSuite struct {
BaseSuite
}
var _ = Suite(&WorktreeSuite{})
func (s *WorktreeSuite) SetUpTest(c *C) {
f := fixtures.Basic().One()
s.Repository = s.NewRepositoryWithEmptyWorktree(f)
}
func (s *WorktreeSuite) TestPullCheckout(c *C) {
fs := memfs.New()
r, _ := Init(memory.NewStorage(), fs)
r.CreateRemote(&config.RemoteConfig{
Name: DefaultRemoteName,
URLs: []string{s.GetBasicLocalRepositoryURL()},
})
w, err := r.Worktree()
c.Assert(err, IsNil)
err = w.Pull(&PullOptions{})
c.Assert(err, IsNil)
fi, err := fs.ReadDir("")
c.Assert(err, IsNil)
c.Assert(fi, HasLen, 8)
}
func (s *WorktreeSuite) TestPullFastForward(c *C) {
url := c.MkDir()
path := fixtures.Basic().ByTag("worktree").One().Worktree().Root()
server, err := PlainClone(url, false, &CloneOptions{
URL: path,
})
c.Assert(err, IsNil)
r, err := PlainClone(c.MkDir(), false, &CloneOptions{
URL: url,
})
c.Assert(err, IsNil)
w, err := server.Worktree()
c.Assert(err, IsNil)
err = ioutil.WriteFile(filepath.Join(path, "foo"), []byte("foo"), 0755)
c.Assert(err, IsNil)
hash, err := w.Commit("foo", &CommitOptions{Author: defaultSignature()})
c.Assert(err, IsNil)
w, err = r.Worktree()
c.Assert(err, IsNil)
err = w.Pull(&PullOptions{})
c.Assert(err, IsNil)
head, err := r.Head()
c.Assert(err, IsNil)
c.Assert(head.Hash(), Equals, hash)
}
func (s *WorktreeSuite) TestPullNonFastForward(c *C) {
url := c.MkDir()
path := fixtures.Basic().ByTag("worktree").One().Worktree().Root()
server, err := PlainClone(url, false, &CloneOptions{
URL: path,
})
c.Assert(err, IsNil)
r, err := PlainClone(c.MkDir(), false, &CloneOptions{
URL: url,
})
c.Assert(err, IsNil)
w, err := server.Worktree()
c.Assert(err, IsNil)
err = ioutil.WriteFile(filepath.Join(path, "foo"), []byte("foo"), 0755)
c.Assert(err, IsNil)
_, err = w.Commit("foo", &CommitOptions{Author: defaultSignature()})
c.Assert(err, IsNil)
w, err = r.Worktree()
c.Assert(err, IsNil)
err = ioutil.WriteFile(filepath.Join(path, "bar"), []byte("bar"), 0755)
c.Assert(err, IsNil)
_, err = w.Commit("bar", &CommitOptions{Author: defaultSignature()})
c.Assert(err, IsNil)
err = w.Pull(&PullOptions{})
c.Assert(err, Equals, ErrNonFastForwardUpdate)
}
func (s *WorktreeSuite) TestPullUpdateReferencesIfNeeded(c *C) {
r, _ := Init(memory.NewStorage(), memfs.New())
r.CreateRemote(&config.RemoteConfig{
Name: DefaultRemoteName,
URLs: []string{s.GetBasicLocalRepositoryURL()},
})
err := r.Fetch(&FetchOptions{})
c.Assert(err, IsNil)
_, err = r.Reference("refs/heads/master", false)
c.Assert(err, NotNil)
w, err := r.Worktree()
c.Assert(err, IsNil)
err = w.Pull(&PullOptions{})
c.Assert(err, IsNil)
head, err := r.Reference(plumbing.HEAD, true)
c.Assert(err, IsNil)
c.Assert(head.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
branch, err := r.Reference("refs/heads/master", false)
c.Assert(err, IsNil)
c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
err = w.Pull(&PullOptions{})
c.Assert(err, Equals, NoErrAlreadyUpToDate)
}
func (s *WorktreeSuite) TestPullInSingleBranch(c *C) {
r, _ := Init(memory.NewStorage(), memfs.New())
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
SingleBranch: true,
})
c.Assert(err, IsNil)
w, err := r.Worktree()
c.Assert(err, IsNil)
err = w.Pull(&PullOptions{})
c.Assert(err, Equals, NoErrAlreadyUpToDate)
branch, err := r.Reference("refs/heads/master", false)
c.Assert(err, IsNil)
c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
branch, err = r.Reference("refs/remotes/foo/branch", false)
c.Assert(err, NotNil)
storage := r.Storer.(*memory.Storage)
c.Assert(storage.Objects, HasLen, 28)
}
func (s *WorktreeSuite) TestPullProgress(c *C) {
r, _ := Init(memory.NewStorage(), memfs.New())
r.CreateRemote(&config.RemoteConfig{
Name: DefaultRemoteName,
URLs: []string{s.GetBasicLocalRepositoryURL()},
})
w, err := r.Worktree()
c.Assert(err, IsNil)
buf := bytes.NewBuffer(nil)
err = w.Pull(&PullOptions{
Progress: buf,
})
c.Assert(err, IsNil)
c.Assert(buf.Len(), Not(Equals), 0)
}
func (s *WorktreeSuite) TestPullProgressWithRecursion(c *C) {
if testing.Short() {
c.Skip("skipping test in short mode.")
}
path := fixtures.ByTag("submodule").One().Worktree().Root()
dir, err := ioutil.TempDir("", "plain-clone-submodule")
c.Assert(err, IsNil)
defer os.RemoveAll(dir)
r, _ := PlainInit(dir, false)
r.CreateRemote(&config.RemoteConfig{
Name: DefaultRemoteName,
URLs: []string{path},
})
w, err := r.Worktree()
c.Assert(err, IsNil)
err = w.Pull(&PullOptions{
RecurseSubmodules: DefaultSubmoduleRecursionDepth,
})
c.Assert(err, IsNil)
cfg, err := r.Config()
c.Assert(err, IsNil)
c.Assert(cfg.Submodules, HasLen, 2)
}
func (s *RepositorySuite) TestPullAdd(c *C) {
path := fixtures.Basic().ByTag("worktree").One().Worktree().Root()
r, err := Clone(memory.NewStorage(), memfs.New(), &CloneOptions{
URL: filepath.Join(path, ".git"),
})
c.Assert(err, IsNil)
storage := r.Storer.(*memory.Storage)
c.Assert(storage.Objects, HasLen, 28)
branch, err := r.Reference("refs/heads/master", false)
c.Assert(err, IsNil)
c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
ExecuteOnPath(c, path,
"touch foo",
"git add foo",
"git commit -m foo foo",
)
w, err := r.Worktree()
c.Assert(err, IsNil)
err = w.Pull(&PullOptions{RemoteName: "origin"})
c.Assert(err, IsNil)
// the commit command has introduced a new commit, tree and blob
c.Assert(storage.Objects, HasLen, 31)
branch, err = r.Reference("refs/heads/master", false)
c.Assert(err, IsNil)
c.Assert(branch.Hash().String(), Not(Equals), "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
}
func (s *WorktreeSuite) TestCheckout(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err := w.Checkout(&CheckoutOptions{
Force: true,
})
c.Assert(err, IsNil)
entries, err := fs.ReadDir("/")
c.Assert(err, IsNil)
c.Assert(entries, HasLen, 8)
ch, err := fs.Open("CHANGELOG")
c.Assert(err, IsNil)
content, err := ioutil.ReadAll(ch)
c.Assert(err, IsNil)
c.Assert(string(content), Equals, "Initial changelog\n")
idx, err := s.Repository.Storer.Index()
c.Assert(err, IsNil)
c.Assert(idx.Entries, HasLen, 9)
}
func (s *WorktreeSuite) TestCheckoutForce(c *C) {
w := &Worktree{
r: s.Repository,
Filesystem: memfs.New(),
}
err := w.Checkout(&CheckoutOptions{})
c.Assert(err, IsNil)
w.Filesystem = memfs.New()
err = w.Checkout(&CheckoutOptions{
Force: true,
})
c.Assert(err, IsNil)
entries, err := w.Filesystem.ReadDir("/")
c.Assert(err, IsNil)
c.Assert(entries, HasLen, 8)
}
func (s *WorktreeSuite) TestCheckoutKeep(c *C) {
w := &Worktree{
r: s.Repository,
Filesystem: memfs.New(),
}
err := w.Checkout(&CheckoutOptions{
Force: true,
})
c.Assert(err, IsNil)
// Create a new branch and create a new file.
err = w.Checkout(&CheckoutOptions{
Branch: plumbing.NewBranchReferenceName("new-branch"),
Create: true,
})
c.Assert(err, IsNil)
w.Filesystem = memfs.New()
f, err := w.Filesystem.Create("new-file.txt")
c.Assert(err, IsNil)
_, err = f.Write([]byte("DUMMY"))
c.Assert(err, IsNil)
c.Assert(f.Close(), IsNil)
// Add the file to staging.
_, err = w.Add("new-file.txt")
c.Assert(err, IsNil)
// Switch branch to master, and verify that the new file was kept in staging.
err = w.Checkout(&CheckoutOptions{
Keep: true,
})
c.Assert(err, IsNil)
fi, err := w.Filesystem.Stat("new-file.txt")
c.Assert(err, IsNil)
c.Assert(fi.Size(), Equals, int64(5))
}
func (s *WorktreeSuite) TestCheckoutSymlink(c *C) {
if runtime.GOOS == "windows" {
c.Skip("git doesn't support symlinks by default in windows")
}
dir, err := ioutil.TempDir("", "checkout")
c.Assert(err, IsNil)
defer os.RemoveAll(dir)
r, err := PlainInit(dir, false)
c.Assert(err, IsNil)
w, err := r.Worktree()
c.Assert(err, IsNil)
w.Filesystem.Symlink("not-exists", "bar")
w.Add("bar")
w.Commit("foo", &CommitOptions{Author: defaultSignature()})
r.Storer.SetIndex(&index.Index{Version: 2})
w.Filesystem = osfs.New(filepath.Join(dir, "worktree-empty"))
err = w.Checkout(&CheckoutOptions{})
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status.IsClean(), Equals, true)
target, err := w.Filesystem.Readlink("bar")
c.Assert(target, Equals, "not-exists")
c.Assert(err, IsNil)
}
func (s *WorktreeSuite) TestFilenameNormalization(c *C) {
if runtime.GOOS == "windows" {
c.Skip("windows paths may contain non utf-8 sequences")
}
url := c.MkDir()
path := fixtures.Basic().ByTag("worktree").One().Worktree().Root()
server, err := PlainClone(url, false, &CloneOptions{
URL: path,
})
c.Assert(err, IsNil)
filename := "페"
w, err := server.Worktree()
c.Assert(err, IsNil)
writeFile := func(path string) {
err := util.WriteFile(w.Filesystem, path, []byte("foo"), 0755)
c.Assert(err, IsNil)
}
writeFile(filename)
origHash, err := w.Add(filename)
c.Assert(err, IsNil)
_, err = w.Commit("foo", &CommitOptions{Author: defaultSignature()})
c.Assert(err, IsNil)
r, err := Clone(memory.NewStorage(), memfs.New(), &CloneOptions{
URL: url,
})
c.Assert(err, IsNil)
w, err = r.Worktree()
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status.IsClean(), Equals, true)
err = w.Filesystem.Remove(filename)
c.Assert(err, IsNil)
modFilename := norm.Form(norm.NFKD).String(filename)
writeFile(modFilename)
_, err = w.Add(filename)
c.Assert(err, IsNil)
modHash, err := w.Add(modFilename)
c.Assert(err, IsNil)
// At this point we've got two files with the same content.
// Hence their hashes must be the same.
c.Assert(origHash == modHash, Equals, true)
status, err = w.Status()
c.Assert(err, IsNil)
// However, their names are different and the work tree is still dirty.
c.Assert(status.IsClean(), Equals, false)
// Revert back the deletion of the first file.
writeFile(filename)
_, err = w.Add(filename)
c.Assert(err, IsNil)
status, err = w.Status()
c.Assert(err, IsNil)
// Still dirty - the second file is added.
c.Assert(status.IsClean(), Equals, false)
_, err = w.Remove(modFilename)
c.Assert(err, IsNil)
status, err = w.Status()
c.Assert(err, IsNil)
c.Assert(status.IsClean(), Equals, true)
}
func (s *WorktreeSuite) TestCheckoutSubmodule(c *C) {
url := "https://github.com/git-fixtures/submodule.git"
r := s.NewRepositoryWithEmptyWorktree(fixtures.ByURL(url).One())
w, err := r.Worktree()
c.Assert(err, IsNil)
err = w.Checkout(&CheckoutOptions{})
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status.IsClean(), Equals, true)
}
func (s *WorktreeSuite) TestCheckoutSubmoduleInitialized(c *C) {
url := "https://github.com/git-fixtures/submodule.git"
r := s.NewRepository(fixtures.ByURL(url).One())
w, err := r.Worktree()
c.Assert(err, IsNil)
sub, err := w.Submodules()
c.Assert(err, IsNil)
err = sub.Update(&SubmoduleUpdateOptions{Init: true})
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status.IsClean(), Equals, true)
}
func (s *WorktreeSuite) TestCheckoutIndexMem(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err := w.Checkout(&CheckoutOptions{})
c.Assert(err, IsNil)
idx, err := s.Repository.Storer.Index()
c.Assert(err, IsNil)
c.Assert(idx.Entries, HasLen, 9)
c.Assert(idx.Entries[0].Hash.String(), Equals, "32858aad3c383ed1ff0a0f9bdf231d54a00c9e88")
c.Assert(idx.Entries[0].Name, Equals, ".gitignore")
c.Assert(idx.Entries[0].Mode, Equals, filemode.Regular)
c.Assert(idx.Entries[0].ModifiedAt.IsZero(), Equals, false)
c.Assert(idx.Entries[0].Size, Equals, uint32(189))
// ctime, dev, inode, uid and gid are not supported on memfs fs
c.Assert(idx.Entries[0].CreatedAt.IsZero(), Equals, true)
c.Assert(idx.Entries[0].Dev, Equals, uint32(0))
c.Assert(idx.Entries[0].Inode, Equals, uint32(0))
c.Assert(idx.Entries[0].UID, Equals, uint32(0))
c.Assert(idx.Entries[0].GID, Equals, uint32(0))
}
func (s *WorktreeSuite) TestCheckoutIndexOS(c *C) {
dir, err := ioutil.TempDir("", "checkout")
c.Assert(err, IsNil)
defer os.RemoveAll(dir)
fs := osfs.New(filepath.Join(dir, "worktree"))
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err = w.Checkout(&CheckoutOptions{})
c.Assert(err, IsNil)
idx, err := s.Repository.Storer.Index()
c.Assert(err, IsNil)
c.Assert(idx.Entries, HasLen, 9)
c.Assert(idx.Entries[0].Hash.String(), Equals, "32858aad3c383ed1ff0a0f9bdf231d54a00c9e88")
c.Assert(idx.Entries[0].Name, Equals, ".gitignore")
c.Assert(idx.Entries[0].Mode, Equals, filemode.Regular)
c.Assert(idx.Entries[0].ModifiedAt.IsZero(), Equals, false)
c.Assert(idx.Entries[0].Size, Equals, uint32(189))
c.Assert(idx.Entries[0].CreatedAt.IsZero(), Equals, false)
if runtime.GOOS != "windows" {
c.Assert(idx.Entries[0].Dev, Not(Equals), uint32(0))
c.Assert(idx.Entries[0].Inode, Not(Equals), uint32(0))
c.Assert(idx.Entries[0].UID, Not(Equals), uint32(0))
c.Assert(idx.Entries[0].GID, Not(Equals), uint32(0))
}
}
func (s *WorktreeSuite) TestCheckoutBranch(c *C) {
w := &Worktree{
r: s.Repository,
Filesystem: memfs.New(),
}
err := w.Checkout(&CheckoutOptions{
Branch: "refs/heads/branch",
})
c.Assert(err, IsNil)
head, err := w.r.Head()
c.Assert(err, IsNil)
c.Assert(head.Name().String(), Equals, "refs/heads/branch")
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status.IsClean(), Equals, true)
}
func (s *WorktreeSuite) TestCheckoutCreateWithHash(c *C) {
w := &Worktree{
r: s.Repository,
Filesystem: memfs.New(),
}
err := w.Checkout(&CheckoutOptions{
Create: true,
Branch: "refs/heads/foo",
Hash: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"),
})
c.Assert(err, IsNil)
head, err := w.r.Head()
c.Assert(err, IsNil)
c.Assert(head.Name().String(), Equals, "refs/heads/foo")
c.Assert(head.Hash(), Equals, plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"))
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status.IsClean(), Equals, true)
}
func (s *WorktreeSuite) TestCheckoutCreate(c *C) {
w := &Worktree{
r: s.Repository,
Filesystem: memfs.New(),
}
err := w.Checkout(&CheckoutOptions{
Create: true,
Branch: "refs/heads/foo",
})
c.Assert(err, IsNil)
head, err := w.r.Head()
c.Assert(err, IsNil)
c.Assert(head.Name().String(), Equals, "refs/heads/foo")
c.Assert(head.Hash(), Equals, plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status.IsClean(), Equals, true)
}
func (s *WorktreeSuite) TestCheckoutBranchAndHash(c *C) {
w := &Worktree{
r: s.Repository,
Filesystem: memfs.New(),
}
err := w.Checkout(&CheckoutOptions{
Branch: "refs/heads/foo",
Hash: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"),
})
c.Assert(err, Equals, ErrBranchHashExclusive)
}
func (s *WorktreeSuite) TestCheckoutCreateMissingBranch(c *C) {
w := &Worktree{
r: s.Repository,
Filesystem: memfs.New(),
}
err := w.Checkout(&CheckoutOptions{
Create: true,
})
c.Assert(err, Equals, ErrCreateRequiresBranch)
}
func (s *WorktreeSuite) TestCheckoutTag(c *C) {
f := fixtures.ByTag("tags").One()
r := s.NewRepositoryWithEmptyWorktree(f)
w, err := r.Worktree()
c.Assert(err, IsNil)
err = w.Checkout(&CheckoutOptions{})
c.Assert(err, IsNil)
head, err := w.r.Head()
c.Assert(err, IsNil)
c.Assert(head.Name().String(), Equals, "refs/heads/master")
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status.IsClean(), Equals, true)
err = w.Checkout(&CheckoutOptions{Branch: "refs/tags/lightweight-tag"})
c.Assert(err, IsNil)
head, err = w.r.Head()
c.Assert(err, IsNil)
c.Assert(head.Name().String(), Equals, "HEAD")
c.Assert(head.Hash().String(), Equals, "f7b877701fbf855b44c0a9e86f3fdce2c298b07f")
err = w.Checkout(&CheckoutOptions{Branch: "refs/tags/commit-tag"})
c.Assert(err, IsNil)
head, err = w.r.Head()
c.Assert(err, IsNil)
c.Assert(head.Name().String(), Equals, "HEAD")
c.Assert(head.Hash().String(), Equals, "f7b877701fbf855b44c0a9e86f3fdce2c298b07f")
err = w.Checkout(&CheckoutOptions{Branch: "refs/tags/tree-tag"})
c.Assert(err, NotNil)
head, err = w.r.Head()
c.Assert(err, IsNil)
c.Assert(head.Name().String(), Equals, "HEAD")
}
func (s *WorktreeSuite) TestCheckoutBisect(c *C) {
if testing.Short() {
c.Skip("skipping test in short mode.")
}
s.testCheckoutBisect(c, "https://github.com/src-d/go-git.git")
}
func (s *WorktreeSuite) TestCheckoutBisectSubmodules(c *C) {
s.testCheckoutBisect(c, "https://github.com/git-fixtures/submodule.git")
}
// TestCheckoutBisect simulates a git bisect going through the git history and
// checking every commit over the previous commit
func (s *WorktreeSuite) testCheckoutBisect(c *C, url string) {
f := fixtures.ByURL(url).One()
r := s.NewRepositoryWithEmptyWorktree(f)
w, err := r.Worktree()
c.Assert(err, IsNil)
iter, err := w.r.Log(&LogOptions{})
c.Assert(err, IsNil)
iter.ForEach(func(commit *object.Commit) error {
err := w.Checkout(&CheckoutOptions{Hash: commit.Hash})
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status.IsClean(), Equals, true)
return nil
})
}
func (s *WorktreeSuite) TestStatus(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status.IsClean(), Equals, false)
c.Assert(status, HasLen, 9)
}
func (s *WorktreeSuite) TestStatusEmpty(c *C) {
fs := memfs.New()
storage := memory.NewStorage()
r, err := Init(storage, fs)
c.Assert(err, IsNil)
w, err := r.Worktree()
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status.IsClean(), Equals, true)
c.Assert(status, NotNil)
}
func (s *WorktreeSuite) TestStatusEmptyDirty(c *C) {
fs := memfs.New()
err := util.WriteFile(fs, "foo", []byte("foo"), 0755)
c.Assert(err, IsNil)
storage := memory.NewStorage()
r, err := Init(storage, fs)
c.Assert(err, IsNil)
w, err := r.Worktree()
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status.IsClean(), Equals, false)
c.Assert(status, HasLen, 1)
}
func (s *WorktreeSuite) TestReset(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
commit := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9")
err := w.Checkout(&CheckoutOptions{})
c.Assert(err, IsNil)
branch, err := w.r.Reference(plumbing.Master, false)
c.Assert(err, IsNil)
c.Assert(branch.Hash(), Not(Equals), commit)
err = w.Reset(&ResetOptions{Mode: MergeReset, Commit: commit})
c.Assert(err, IsNil)
branch, err = w.r.Reference(plumbing.Master, false)
c.Assert(err, IsNil)
c.Assert(branch.Hash(), Equals, commit)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status.IsClean(), Equals, true)
}
func (s *WorktreeSuite) TestResetWithUntracked(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
commit := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9")
err := w.Checkout(&CheckoutOptions{})
c.Assert(err, IsNil)
err = util.WriteFile(fs, "foo", nil, 0755)
c.Assert(err, IsNil)
err = w.Reset(&ResetOptions{Mode: MergeReset, Commit: commit})
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status.IsClean(), Equals, true)
}
func (s *WorktreeSuite) TestResetSoft(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
commit := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9")
err := w.Checkout(&CheckoutOptions{})
c.Assert(err, IsNil)
err = w.Reset(&ResetOptions{Mode: SoftReset, Commit: commit})
c.Assert(err, IsNil)
branch, err := w.r.Reference(plumbing.Master, false)
c.Assert(err, IsNil)
c.Assert(branch.Hash(), Equals, commit)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status.IsClean(), Equals, false)
c.Assert(status.File("CHANGELOG").Staging, Equals, Added)
}
func (s *WorktreeSuite) TestResetMixed(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
commit := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9")
err := w.Checkout(&CheckoutOptions{})
c.Assert(err, IsNil)
err = w.Reset(&ResetOptions{Mode: MixedReset, Commit: commit})
c.Assert(err, IsNil)
branch, err := w.r.Reference(plumbing.Master, false)
c.Assert(err, IsNil)
c.Assert(branch.Hash(), Equals, commit)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status.IsClean(), Equals, false)
c.Assert(status.File("CHANGELOG").Staging, Equals, Untracked)
}
func (s *WorktreeSuite) TestResetMerge(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
commitA := plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294")
commitB := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9")
err := w.Checkout(&CheckoutOptions{})
c.Assert(err, IsNil)
err = w.Reset(&ResetOptions{Mode: MergeReset, Commit: commitA})
c.Assert(err, IsNil)
branch, err := w.r.Reference(plumbing.Master, false)
c.Assert(err, IsNil)
c.Assert(branch.Hash(), Equals, commitA)
f, err := fs.Create(".gitignore")
c.Assert(err, IsNil)
_, err = f.Write([]byte("foo"))
c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
err = w.Reset(&ResetOptions{Mode: MergeReset, Commit: commitB})
c.Assert(err, Equals, ErrUnstagedChanges)
branch, err = w.r.Reference(plumbing.Master, false)
c.Assert(err, IsNil)
c.Assert(branch.Hash(), Equals, commitA)
}
func (s *WorktreeSuite) TestResetHard(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
commit := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9")
err := w.Checkout(&CheckoutOptions{})
c.Assert(err, IsNil)
f, err := fs.Create(".gitignore")
c.Assert(err, IsNil)
_, err = f.Write([]byte("foo"))
c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
err = w.Reset(&ResetOptions{Mode: HardReset, Commit: commit})
c.Assert(err, IsNil)
branch, err := w.r.Reference(plumbing.Master, false)
c.Assert(err, IsNil)
c.Assert(branch.Hash(), Equals, commit)
}
func (s *WorktreeSuite) TestStatusAfterCheckout(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err := w.Checkout(&CheckoutOptions{Force: true})
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status.IsClean(), Equals, true)
}
func (s *WorktreeSuite) TestStatusModified(c *C) {
dir, err := ioutil.TempDir("", "status")
c.Assert(err, IsNil)
defer os.RemoveAll(dir)
fs := osfs.New(filepath.Join(dir, "worktree"))
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err = w.Checkout(&CheckoutOptions{})
c.Assert(err, IsNil)
f, err := fs.Create(".gitignore")
c.Assert(err, IsNil)
_, err = f.Write([]byte("foo"))
c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status.IsClean(), Equals, false)
c.Assert(status.File(".gitignore").Worktree, Equals, Modified)
}
func (s *WorktreeSuite) TestStatusIgnored(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
w.Checkout(&CheckoutOptions{})
fs.MkdirAll("another", os.ModePerm)
f, _ := fs.Create("another/file")
f.Close()
fs.MkdirAll("vendor/github.com", os.ModePerm)
f, _ = fs.Create("vendor/github.com/file")
f.Close()
fs.MkdirAll("vendor/gopkg.in", os.ModePerm)
f, _ = fs.Create("vendor/gopkg.in/file")
f.Close()
status, _ := w.Status()
c.Assert(len(status), Equals, 3)
_, ok := status["another/file"]
c.Assert(ok, Equals, true)
_, ok = status["vendor/github.com/file"]
c.Assert(ok, Equals, true)
_, ok = status["vendor/gopkg.in/file"]
c.Assert(ok, Equals, true)
f, _ = fs.Create(".gitignore")
f.Write([]byte("vendor/g*/"))
f.Close()
f, _ = fs.Create("vendor/.gitignore")
f.Write([]byte("!github.com/\n"))
f.Close()
status, _ = w.Status()
c.Assert(len(status), Equals, 4)
_, ok = status[".gitignore"]
c.Assert(ok, Equals, true)
_, ok = status["another/file"]
c.Assert(ok, Equals, true)
_, ok = status["vendor/.gitignore"]
c.Assert(ok, Equals, true)
_, ok = status["vendor/github.com/file"]
c.Assert(ok, Equals, true)
}
func (s *WorktreeSuite) TestStatusUntracked(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err := w.Checkout(&CheckoutOptions{Force: true})
c.Assert(err, IsNil)
f, err := w.Filesystem.Create("foo")
c.Assert(err, IsNil)
c.Assert(f.Close(), IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status.File("foo").Staging, Equals, Untracked)
c.Assert(status.File("foo").Worktree, Equals, Untracked)
}
func (s *WorktreeSuite) TestStatusDeleted(c *C) {
dir, err := ioutil.TempDir("", "status")
c.Assert(err, IsNil)
defer os.RemoveAll(dir)
fs := osfs.New(filepath.Join(dir, "worktree"))
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err = w.Checkout(&CheckoutOptions{})
c.Assert(err, IsNil)
err = fs.Remove(".gitignore")
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status.IsClean(), Equals, false)
c.Assert(status.File(".gitignore").Worktree, Equals, Deleted)
}
func (s *WorktreeSuite) TestSubmodule(c *C) {
path := fixtures.ByTag("submodule").One().Worktree().Root()
r, err := PlainOpen(path)
c.Assert(err, IsNil)
w, err := r.Worktree()
c.Assert(err, IsNil)
m, err := w.Submodule("basic")
c.Assert(err, IsNil)
c.Assert(m.Config().Name, Equals, "basic")
}
func (s *WorktreeSuite) TestSubmodules(c *C) {
path := fixtures.ByTag("submodule").One().Worktree().Root()
r, err := PlainOpen(path)
c.Assert(err, IsNil)
w, err := r.Worktree()
c.Assert(err, IsNil)
l, err := w.Submodules()
c.Assert(err, IsNil)
c.Assert(l, HasLen, 2)
}
func (s *WorktreeSuite) TestAddUntracked(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err := w.Checkout(&CheckoutOptions{Force: true})
c.Assert(err, IsNil)
idx, err := w.r.Storer.Index()
c.Assert(err, IsNil)
c.Assert(idx.Entries, HasLen, 9)
err = util.WriteFile(w.Filesystem, "foo", []byte("FOO"), 0755)
c.Assert(err, IsNil)
hash, err := w.Add("foo")
c.Assert(hash.String(), Equals, "d96c7efbfec2814ae0301ad054dc8d9fc416c9b5")
c.Assert(err, IsNil)
idx, err = w.r.Storer.Index()
c.Assert(err, IsNil)
c.Assert(idx.Entries, HasLen, 10)
e, err := idx.Entry("foo")
c.Assert(err, IsNil)
c.Assert(e.Hash, Equals, hash)
c.Assert(e.Mode, Equals, filemode.Executable)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status, HasLen, 1)
file := status.File("foo")
c.Assert(file.Staging, Equals, Added)
c.Assert(file.Worktree, Equals, Unmodified)
obj, err := w.r.Storer.EncodedObject(plumbing.BlobObject, hash)
c.Assert(err, IsNil)
c.Assert(obj, NotNil)
c.Assert(obj.Size(), Equals, int64(3))
}
func (s *WorktreeSuite) TestIgnored(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
w.Excludes = make([]gitignore.Pattern, 0)
w.Excludes = append(w.Excludes, gitignore.ParsePattern("foo", nil))
err := w.Checkout(&CheckoutOptions{Force: true})
c.Assert(err, IsNil)
idx, err := w.r.Storer.Index()
c.Assert(err, IsNil)
c.Assert(idx.Entries, HasLen, 9)
err = util.WriteFile(w.Filesystem, "foo", []byte("FOO"), 0755)
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status, HasLen, 0)
file := status.File("foo")
c.Assert(file.Staging, Equals, Untracked)
c.Assert(file.Worktree, Equals, Untracked)
}
func (s *WorktreeSuite) TestExcludedNoGitignore(c *C) {
f := fixtures.ByTag("empty").One()
r := s.NewRepository(f)
fs := memfs.New()
w := &Worktree{
r: r,
Filesystem: fs,
}
_, err := fs.Open(".gitignore")
c.Assert(err, Equals, os.ErrNotExist)
w.Excludes = make([]gitignore.Pattern, 0)
w.Excludes = append(w.Excludes, gitignore.ParsePattern("foo", nil))
err = util.WriteFile(w.Filesystem, "foo", []byte("FOO"), 0755)
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status, HasLen, 0)
file := status.File("foo")
c.Assert(file.Staging, Equals, Untracked)
c.Assert(file.Worktree, Equals, Untracked)
}
func (s *WorktreeSuite) TestAddModified(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err := w.Checkout(&CheckoutOptions{Force: true})
c.Assert(err, IsNil)
idx, err := w.r.Storer.Index()
c.Assert(err, IsNil)
c.Assert(idx.Entries, HasLen, 9)
err = util.WriteFile(w.Filesystem, "LICENSE", []byte("FOO"), 0644)
c.Assert(err, IsNil)
hash, err := w.Add("LICENSE")
c.Assert(err, IsNil)
c.Assert(hash.String(), Equals, "d96c7efbfec2814ae0301ad054dc8d9fc416c9b5")
idx, err = w.r.Storer.Index()
c.Assert(err, IsNil)
c.Assert(idx.Entries, HasLen, 9)
e, err := idx.Entry("LICENSE")
c.Assert(err, IsNil)
c.Assert(e.Hash, Equals, hash)
c.Assert(e.Mode, Equals, filemode.Regular)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status, HasLen, 1)
file := status.File("LICENSE")
c.Assert(file.Staging, Equals, Modified)
c.Assert(file.Worktree, Equals, Unmodified)
}
func (s *WorktreeSuite) TestAddUnmodified(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err := w.Checkout(&CheckoutOptions{Force: true})
c.Assert(err, IsNil)
hash, err := w.Add("LICENSE")
c.Assert(hash.String(), Equals, "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f")
c.Assert(err, IsNil)
}
func (s *WorktreeSuite) TestAddRemoved(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err := w.Checkout(&CheckoutOptions{Force: true})
c.Assert(err, IsNil)
idx, err := w.r.Storer.Index()
c.Assert(err, IsNil)
c.Assert(idx.Entries, HasLen, 9)
err = w.Filesystem.Remove("LICENSE")
c.Assert(err, IsNil)
hash, err := w.Add("LICENSE")
c.Assert(err, IsNil)
c.Assert(hash.String(), Equals, "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f")
e, err := idx.Entry("LICENSE")
c.Assert(err, IsNil)
c.Assert(e.Hash, Equals, hash)
c.Assert(e.Mode, Equals, filemode.Regular)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status, HasLen, 1)
file := status.File("LICENSE")
c.Assert(file.Staging, Equals, Deleted)
}
func (s *WorktreeSuite) TestAddSymlink(c *C) {
dir, err := ioutil.TempDir("", "checkout")
c.Assert(err, IsNil)
defer os.RemoveAll(dir)
r, err := PlainInit(dir, false)
c.Assert(err, IsNil)
err = util.WriteFile(r.wt, "foo", []byte("qux"), 0644)
c.Assert(err, IsNil)
err = r.wt.Symlink("foo", "bar")
c.Assert(err, IsNil)
w, err := r.Worktree()
c.Assert(err, IsNil)
h, err := w.Add("foo")
c.Assert(err, IsNil)
c.Assert(h, Not(Equals), plumbing.NewHash("19102815663d23f8b75a47e7a01965dcdc96468c"))
h, err = w.Add("bar")
c.Assert(err, IsNil)
c.Assert(h, Equals, plumbing.NewHash("19102815663d23f8b75a47e7a01965dcdc96468c"))
obj, err := w.r.Storer.EncodedObject(plumbing.BlobObject, h)
c.Assert(err, IsNil)
c.Assert(obj, NotNil)
c.Assert(obj.Size(), Equals, int64(3))
}
func (s *WorktreeSuite) TestAddDirectory(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err := w.Checkout(&CheckoutOptions{Force: true})
c.Assert(err, IsNil)
idx, err := w.r.Storer.Index()
c.Assert(err, IsNil)
c.Assert(idx.Entries, HasLen, 9)
err = util.WriteFile(w.Filesystem, "qux/foo", []byte("FOO"), 0755)
c.Assert(err, IsNil)
err = util.WriteFile(w.Filesystem, "qux/baz/bar", []byte("BAR"), 0755)
c.Assert(err, IsNil)
h, err := w.Add("qux")
c.Assert(err, IsNil)
c.Assert(h.IsZero(), Equals, true)
idx, err = w.r.Storer.Index()
c.Assert(err, IsNil)
c.Assert(idx.Entries, HasLen, 11)
e, err := idx.Entry("qux/foo")
c.Assert(err, IsNil)
c.Assert(e.Mode, Equals, filemode.Executable)
e, err = idx.Entry("qux/baz/bar")
c.Assert(err, IsNil)
c.Assert(e.Mode, Equals, filemode.Executable)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status, HasLen, 2)
file := status.File("qux/foo")
c.Assert(file.Staging, Equals, Added)
c.Assert(file.Worktree, Equals, Unmodified)
file = status.File("qux/baz/bar")
c.Assert(file.Staging, Equals, Added)
c.Assert(file.Worktree, Equals, Unmodified)
}
func (s *WorktreeSuite) TestAddDirectoryErrorNotFound(c *C) {
r, _ := Init(memory.NewStorage(), memfs.New())
w, _ := r.Worktree()
h, err := w.Add("foo")
c.Assert(err, NotNil)
c.Assert(h.IsZero(), Equals, true)
}
func (s *WorktreeSuite) TestAddGlob(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err := w.Checkout(&CheckoutOptions{Force: true})
c.Assert(err, IsNil)
idx, err := w.r.Storer.Index()
c.Assert(err, IsNil)
c.Assert(idx.Entries, HasLen, 9)
err = util.WriteFile(w.Filesystem, "qux/qux", []byte("QUX"), 0755)
c.Assert(err, IsNil)
err = util.WriteFile(w.Filesystem, "qux/baz", []byte("BAZ"), 0755)
c.Assert(err, IsNil)
err = util.WriteFile(w.Filesystem, "qux/bar/baz", []byte("BAZ"), 0755)
c.Assert(err, IsNil)
err = w.AddGlob(w.Filesystem.Join("qux", "b*"))
c.Assert(err, IsNil)
idx, err = w.r.Storer.Index()
c.Assert(err, IsNil)
c.Assert(idx.Entries, HasLen, 11)
e, err := idx.Entry("qux/baz")
c.Assert(err, IsNil)
c.Assert(e.Mode, Equals, filemode.Executable)
e, err = idx.Entry("qux/bar/baz")
c.Assert(err, IsNil)
c.Assert(e.Mode, Equals, filemode.Executable)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status, HasLen, 3)
file := status.File("qux/qux")
c.Assert(file.Staging, Equals, Untracked)
c.Assert(file.Worktree, Equals, Untracked)
file = status.File("qux/baz")
c.Assert(file.Staging, Equals, Added)
c.Assert(file.Worktree, Equals, Unmodified)
file = status.File("qux/bar/baz")
c.Assert(file.Staging, Equals, Added)
c.Assert(file.Worktree, Equals, Unmodified)
}
func (s *WorktreeSuite) TestAddGlobErrorNoMatches(c *C) {
r, _ := Init(memory.NewStorage(), memfs.New())
w, _ := r.Worktree()
err := w.AddGlob("foo")
c.Assert(err, Equals, ErrGlobNoMatches)
}
func (s *WorktreeSuite) TestRemove(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err := w.Checkout(&CheckoutOptions{Force: true})
c.Assert(err, IsNil)
hash, err := w.Remove("LICENSE")
c.Assert(hash.String(), Equals, "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f")
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status, HasLen, 1)
c.Assert(status.File("LICENSE").Staging, Equals, Deleted)
}
func (s *WorktreeSuite) TestRemoveNotExistentEntry(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err := w.Checkout(&CheckoutOptions{Force: true})
c.Assert(err, IsNil)
hash, err := w.Remove("not-exists")
c.Assert(hash.IsZero(), Equals, true)
c.Assert(err, NotNil)
}
func (s *WorktreeSuite) TestRemoveDirectory(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err := w.Checkout(&CheckoutOptions{Force: true})
c.Assert(err, IsNil)
hash, err := w.Remove("json")
c.Assert(hash.IsZero(), Equals, true)
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status, HasLen, 2)
c.Assert(status.File("json/long.json").Staging, Equals, Deleted)
c.Assert(status.File("json/short.json").Staging, Equals, Deleted)
_, err = w.Filesystem.Stat("json")
c.Assert(os.IsNotExist(err), Equals, true)
}
func (s *WorktreeSuite) TestRemoveDirectoryUntracked(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err := w.Checkout(&CheckoutOptions{Force: true})
c.Assert(err, IsNil)
err = util.WriteFile(w.Filesystem, "json/foo", []byte("FOO"), 0755)
c.Assert(err, IsNil)
hash, err := w.Remove("json")
c.Assert(hash.IsZero(), Equals, true)
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status, HasLen, 3)
c.Assert(status.File("json/long.json").Staging, Equals, Deleted)
c.Assert(status.File("json/short.json").Staging, Equals, Deleted)
c.Assert(status.File("json/foo").Staging, Equals, Untracked)
_, err = w.Filesystem.Stat("json")
c.Assert(err, IsNil)
}
func (s *WorktreeSuite) TestRemoveDeletedFromWorktree(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err := w.Checkout(&CheckoutOptions{Force: true})
c.Assert(err, IsNil)
err = fs.Remove("LICENSE")
c.Assert(err, IsNil)
hash, err := w.Remove("LICENSE")
c.Assert(hash.String(), Equals, "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f")
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status, HasLen, 1)
c.Assert(status.File("LICENSE").Staging, Equals, Deleted)
}
func (s *WorktreeSuite) TestRemoveGlob(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err := w.Checkout(&CheckoutOptions{Force: true})
c.Assert(err, IsNil)
err = w.RemoveGlob(w.Filesystem.Join("json", "l*"))
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status, HasLen, 1)
c.Assert(status.File("json/long.json").Staging, Equals, Deleted)
}
func (s *WorktreeSuite) TestRemoveGlobDirectory(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err := w.Checkout(&CheckoutOptions{Force: true})
c.Assert(err, IsNil)
err = w.RemoveGlob("js*")
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status, HasLen, 2)
c.Assert(status.File("json/short.json").Staging, Equals, Deleted)
c.Assert(status.File("json/long.json").Staging, Equals, Deleted)
_, err = w.Filesystem.Stat("json")
c.Assert(os.IsNotExist(err), Equals, true)
}
func (s *WorktreeSuite) TestRemoveGlobDirectoryDeleted(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err := w.Checkout(&CheckoutOptions{Force: true})
c.Assert(err, IsNil)
err = fs.Remove("json/short.json")
c.Assert(err, IsNil)
err = util.WriteFile(w.Filesystem, "json/foo", []byte("FOO"), 0755)
c.Assert(err, IsNil)
err = w.RemoveGlob("js*")
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status, HasLen, 3)
c.Assert(status.File("json/short.json").Staging, Equals, Deleted)
c.Assert(status.File("json/long.json").Staging, Equals, Deleted)
}
func (s *WorktreeSuite) TestMove(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err := w.Checkout(&CheckoutOptions{Force: true})
c.Assert(err, IsNil)
hash, err := w.Move("LICENSE", "foo")
c.Check(hash.String(), Equals, "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f")
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status, HasLen, 2)
c.Assert(status.File("LICENSE").Staging, Equals, Deleted)
c.Assert(status.File("foo").Staging, Equals, Added)
}
func (s *WorktreeSuite) TestMoveNotExistentEntry(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err := w.Checkout(&CheckoutOptions{Force: true})
c.Assert(err, IsNil)
hash, err := w.Move("not-exists", "foo")
c.Assert(hash.IsZero(), Equals, true)
c.Assert(err, NotNil)
}
func (s *WorktreeSuite) TestMoveToExistent(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}
err := w.Checkout(&CheckoutOptions{Force: true})
c.Assert(err, IsNil)
hash, err := w.Move(".gitignore", "LICENSE")
c.Assert(hash.IsZero(), Equals, true)
c.Assert(err, Equals, ErrDestinationExists)
}
func (s *WorktreeSuite) TestClean(c *C) {
fs := fixtures.ByTag("dirty").One().Worktree()
// Open the repo.
fs, err := fs.Chroot("repo")
c.Assert(err, IsNil)
r, err := PlainOpen(fs.Root())
c.Assert(err, IsNil)
wt, err := r.Worktree()
c.Assert(err, IsNil)
// Status before cleaning.
status, err := wt.Status()
c.Assert(len(status), Equals, 2)
err = wt.Clean(&CleanOptions{})
c.Assert(err, IsNil)
// Status after cleaning.
status, err = wt.Status()
c.Assert(err, IsNil)
c.Assert(len(status), Equals, 1)
fi, err := fs.Lstat("pkgA")
c.Assert(err, IsNil)
c.Assert(fi.IsDir(), Equals, true)
// Clean with Dir: true.
err = wt.Clean(&CleanOptions{Dir: true})
c.Assert(err, IsNil)
status, err = wt.Status()
c.Assert(err, IsNil)
c.Assert(len(status), Equals, 0)
// An empty dir should be deleted, as well.
_, err = fs.Lstat("pkgA")
c.Assert(err, ErrorMatches, ".*(no such file or directory.*|.*file does not exist)*.")
}
func (s *WorktreeSuite) TestAlternatesRepo(c *C) {
fs := fixtures.ByTag("alternates").One().Worktree()
// Open 1st repo.
rep1fs, err := fs.Chroot("rep1")
c.Assert(err, IsNil)
rep1, err := PlainOpen(rep1fs.Root())
c.Assert(err, IsNil)
// Open 2nd repo.
rep2fs, err := fs.Chroot("rep2")
c.Assert(err, IsNil)
rep2, err := PlainOpen(rep2fs.Root())
c.Assert(err, IsNil)
// Get the HEAD commit from the main repo.
h, err := rep1.Head()
c.Assert(err, IsNil)
commit1, err := rep1.CommitObject(h.Hash())
c.Assert(err, IsNil)
// Get the HEAD commit from the shared repo.
h, err = rep2.Head()
c.Assert(err, IsNil)
commit2, err := rep2.CommitObject(h.Hash())
c.Assert(err, IsNil)
c.Assert(commit1.String(), Equals, commit2.String())
}
func (s *WorktreeSuite) TestGrep(c *C) {
cases := []struct {
name string
options GrepOptions
wantResult []GrepResult
dontWantResult []GrepResult
wantError error
}{
{
name: "basic word match",
options: GrepOptions{
Patterns: []*regexp.Regexp{regexp.MustCompile("import")},
},
wantResult: []GrepResult{
{
FileName: "go/example.go",
LineNumber: 3,
Content: "import (",
TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
},
{
FileName: "vendor/foo.go",
LineNumber: 3,
Content: "import \"fmt\"",
TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
},
},
}, {
name: "case insensitive match",
options: GrepOptions{
Patterns: []*regexp.Regexp{regexp.MustCompile(`(?i)IMport`)},
},
wantResult: []GrepResult{
{
FileName: "go/example.go",
LineNumber: 3,
Content: "import (",
TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
},
{
FileName: "vendor/foo.go",
LineNumber: 3,
Content: "import \"fmt\"",
TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
},
},
}, {
name: "invert match",
options: GrepOptions{
Patterns: []*regexp.Regexp{regexp.MustCompile("import")},
InvertMatch: true,
},
dontWantResult: []GrepResult{
{
FileName: "go/example.go",
LineNumber: 3,
Content: "import (",
TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
},
{
FileName: "vendor/foo.go",
LineNumber: 3,
Content: "import \"fmt\"",
TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
},
},
}, {
name: "match at a given commit hash",
options: GrepOptions{
Patterns: []*regexp.Regexp{regexp.MustCompile("The MIT License")},
CommitHash: plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"),
},
wantResult: []GrepResult{
{
FileName: "LICENSE",
LineNumber: 1,
Content: "The MIT License (MIT)",
TreeName: "b029517f6300c2da0f4b651b8642506cd6aaf45d",
},
},
dontWantResult: []GrepResult{
{
FileName: "go/example.go",
LineNumber: 3,
Content: "import (",
TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
},
},
}, {
name: "match for a given pathspec",
options: GrepOptions{
Patterns: []*regexp.Regexp{regexp.MustCompile("import")},
PathSpecs: []*regexp.Regexp{regexp.MustCompile("go/")},
},
wantResult: []GrepResult{
{
FileName: "go/example.go",
LineNumber: 3,
Content: "import (",
TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
},
},
dontWantResult: []GrepResult{
{
FileName: "vendor/foo.go",
LineNumber: 3,
Content: "import \"fmt\"",
TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
},
},
}, {
name: "match at a given reference name",
options: GrepOptions{
Patterns: []*regexp.Regexp{regexp.MustCompile("import")},
ReferenceName: "refs/heads/master",
},
wantResult: []GrepResult{
{
FileName: "go/example.go",
LineNumber: 3,
Content: "import (",
TreeName: "refs/heads/master",
},
},
}, {
name: "ambiguous options",
options: GrepOptions{
Patterns: []*regexp.Regexp{regexp.MustCompile("import")},
CommitHash: plumbing.NewHash("2d55a722f3c3ecc36da919dfd8b6de38352f3507"),
ReferenceName: "somereferencename",
},
wantError: ErrHashOrReference,
}, {
name: "multiple patterns",
options: GrepOptions{
Patterns: []*regexp.Regexp{
regexp.MustCompile("import"),
regexp.MustCompile("License"),
},
},
wantResult: []GrepResult{
{
FileName: "go/example.go",
LineNumber: 3,
Content: "import (",
TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
},
{
FileName: "vendor/foo.go",
LineNumber: 3,
Content: "import \"fmt\"",
TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
},
{
FileName: "LICENSE",
LineNumber: 1,
Content: "The MIT License (MIT)",
TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
},
},
}, {
name: "multiple pathspecs",
options: GrepOptions{
Patterns: []*regexp.Regexp{regexp.MustCompile("import")},
PathSpecs: []*regexp.Regexp{
regexp.MustCompile("go/"),
regexp.MustCompile("vendor/"),
},
},
wantResult: []GrepResult{
{
FileName: "go/example.go",
LineNumber: 3,
Content: "import (",
TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
},
{
FileName: "vendor/foo.go",
LineNumber: 3,
Content: "import \"fmt\"",
TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
},
},
},
}
path := fixtures.Basic().ByTag("worktree").One().Worktree().Root()
server, err := PlainClone(c.MkDir(), false, &CloneOptions{
URL: path,
})
c.Assert(err, IsNil)
w, err := server.Worktree()
c.Assert(err, IsNil)
for _, tc := range cases {
gr, err := w.Grep(&tc.options)
if tc.wantError != nil {
c.Assert(err, Equals, tc.wantError)
} else {
c.Assert(err, IsNil)
}
// Iterate through the results and check if the wanted result is present
// in the got result.
for _, wantResult := range tc.wantResult {
found := false
for _, gotResult := range gr {
if wantResult == gotResult {
found = true
break
}
}
if !found {
c.Errorf("unexpected grep results for %q, expected result to contain: %v", tc.name, wantResult)
}
}
// Iterate through the results and check if the not wanted result is
// present in the got result.
for _, dontWantResult := range tc.dontWantResult {
found := false
for _, gotResult := range gr {
if dontWantResult == gotResult {
found = true
break
}
}
if found {
c.Errorf("unexpected grep results for %q, expected result to NOT contain: %v", tc.name, dontWantResult)
}
}
}
}
func (s *WorktreeSuite) TestAddAndCommit(c *C) {
dir, err := ioutil.TempDir("", "plain-repo")
c.Assert(err, IsNil)
defer os.RemoveAll(dir)
repo, err := PlainInit(dir, false)
c.Assert(err, IsNil)
w, err := repo.Worktree()
c.Assert(err, IsNil)
_, err = w.Add(".")
c.Assert(err, IsNil)
w.Commit("Test Add And Commit", &CommitOptions{Author: &object.Signature{
Name: "foo",
Email: "[email protected]",
When: time.Now(),
}})
iter, err := w.r.Log(&LogOptions{})
c.Assert(err, IsNil)
err = iter.ForEach(func(c *object.Commit) error {
files, err := c.Files()
if err != nil {
return err
}
err = files.ForEach(func(f *object.File) error {
return errors.New("Expected no files, got at least 1")
})
return err
})
c.Assert(err, IsNil)
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/andy_f/go-git.git
[email protected]:andy_f/go-git.git
andy_f
go-git
go-git
master

搜索帮助