aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plumbing/format/config/encoder.go8
-rw-r--r--plumbing/format/packfile/delta_test.go24
-rw-r--r--plumbing/format/packfile/patch_delta.go77
-rw-r--r--plumbing/object/commit_walker.go48
-rw-r--r--plumbing/object/commit_walker_test.go57
-rw-r--r--plumbing/revlist/revlist.go39
-rw-r--r--plumbing/transport/git/receive_pack_test.go4
-rw-r--r--plumbing/transport/server/loader.go2
-rw-r--r--remote.go12
-rw-r--r--repository.go6
-rw-r--r--repository_test.go45
-rw-r--r--storage/filesystem/internal/dotgit/dotgit.go16
-rw-r--r--storage/filesystem/internal/dotgit/dotgit_test.go1
-rw-r--r--utils/merkletrie/filesystem/node.go6
-rw-r--r--utils/merkletrie/filesystem/node_test.go10
-rw-r--r--utils/merkletrie/index/node.go18
-rw-r--r--utils/merkletrie/index/node_test.go29
-rw-r--r--worktree.go5
-rw-r--r--worktree_commit.go26
-rw-r--r--worktree_linux.go1
-rw-r--r--worktree_windows.go20
21 files changed, 346 insertions, 108 deletions
diff --git a/plumbing/format/config/encoder.go b/plumbing/format/config/encoder.go
index 88bdf65..6d17a5a 100644
--- a/plumbing/format/config/encoder.go
+++ b/plumbing/format/config/encoder.go
@@ -3,6 +3,7 @@ package config
import (
"fmt"
"io"
+ "strings"
)
// An Encoder writes config files to an output stream.
@@ -61,7 +62,12 @@ func (e *Encoder) encodeSubsection(sectionName string, s *Subsection) error {
func (e *Encoder) encodeOptions(opts Options) error {
for _, o := range opts {
- if err := e.printf("\t%s = %s\n", o.Key, o.Value); err != nil {
+ pattern := "\t%s = %s\n"
+ if strings.Index(o.Value, "\\") != -1 {
+ pattern = "\t%s = %q\n"
+ }
+
+ if err := e.printf(pattern, o.Key, o.Value); err != nil {
return err
}
}
diff --git a/plumbing/format/packfile/delta_test.go b/plumbing/format/packfile/delta_test.go
index 9ee3499..42b777a 100644
--- a/plumbing/format/packfile/delta_test.go
+++ b/plumbing/format/packfile/delta_test.go
@@ -1,7 +1,6 @@
package packfile
import (
- "fmt"
"math/rand"
. "gopkg.in/check.v1"
@@ -86,9 +85,28 @@ func (s *DeltaSuite) TestAddDelta(c *C) {
baseBuf := genBytes(t.base)
targetBuf := genBytes(t.target)
delta := DiffDelta(baseBuf, targetBuf)
- result := PatchDelta(baseBuf, delta)
+ result, err := PatchDelta(baseBuf, delta)
- c.Log(fmt.Printf("Executing test case: %s\n", t.description))
+ c.Log("Executing test case:", t.description)
+ c.Assert(err, IsNil)
c.Assert(result, DeepEquals, targetBuf)
}
}
+
+func (s *DeltaSuite) TestIncompleteDelta(c *C) {
+ for _, t := range s.testCases {
+ c.Log("Incomplete delta on:", t.description)
+ baseBuf := genBytes(t.base)
+ targetBuf := genBytes(t.target)
+ delta := DiffDelta(baseBuf, targetBuf)
+ delta = delta[:len(delta)-2]
+ result, err := PatchDelta(baseBuf, delta)
+ c.Assert(err, NotNil)
+ c.Assert(result, IsNil)
+ }
+
+ // check nil input too
+ result, err := PatchDelta(nil, nil)
+ c.Assert(err, NotNil)
+ c.Assert(result, IsNil)
+}
diff --git a/plumbing/format/packfile/patch_delta.go b/plumbing/format/packfile/patch_delta.go
index 840f840..976cabc 100644
--- a/plumbing/format/packfile/patch_delta.go
+++ b/plumbing/format/packfile/patch_delta.go
@@ -1,6 +1,7 @@
package packfile
import (
+ "errors"
"io/ioutil"
"gopkg.in/src-d/go-git.v4/plumbing"
@@ -30,7 +31,11 @@ func ApplyDelta(target, base plumbing.EncodedObject, delta []byte) error {
return err
}
- dst := PatchDelta(src, delta)
+ dst, err := PatchDelta(src, delta)
+ if err != nil {
+ return err
+ }
+
target.SetSize(int64(len(dst)))
if _, err := w.Write(dst); err != nil {
@@ -40,15 +45,22 @@ func ApplyDelta(target, base plumbing.EncodedObject, delta []byte) error {
return nil
}
+var (
+ ErrInvalidDelta = errors.New("invalid delta")
+ ErrDeltaCmd = errors.New("wrong delta command")
+)
+
// PatchDelta returns the result of applying the modification deltas in delta to src.
-func PatchDelta(src, delta []byte) []byte {
+// An error will be returned if delta is corrupted (ErrDeltaLen) or an action command
+// is not copy from source or copy from delta (ErrDeltaCmd).
+func PatchDelta(src, delta []byte) ([]byte, error) {
if len(delta) < deltaSizeMin {
- return nil
+ return nil, ErrInvalidDelta
}
srcSz, delta := decodeLEB128(delta)
if srcSz != uint(len(src)) {
- return nil
+ return nil, ErrInvalidDelta
}
targetSz, delta := decodeLEB128(delta)
@@ -57,12 +69,25 @@ func PatchDelta(src, delta []byte) []byte {
var dest []byte
var cmd byte
for {
+ if len(delta) == 0 {
+ return nil, ErrInvalidDelta
+ }
+
cmd = delta[0]
delta = delta[1:]
if isCopyFromSrc(cmd) {
var offset, sz uint
- offset, delta = decodeOffset(cmd, delta)
- sz, delta = decodeSize(cmd, delta)
+ var err error
+ offset, delta, err = decodeOffset(cmd, delta)
+ if err != nil {
+ return nil, err
+ }
+
+ sz, delta, err = decodeSize(cmd, delta)
+ if err != nil {
+ return nil, err
+ }
+
if invalidSize(sz, targetSz) ||
invalidOffsetSize(offset, sz, srcSz) {
break
@@ -72,13 +97,18 @@ func PatchDelta(src, delta []byte) []byte {
} else if isCopyFromDelta(cmd) {
sz := uint(cmd) // cmd is the size itself
if invalidSize(sz, targetSz) {
- break
+ return nil, ErrInvalidDelta
+ }
+
+ if uint(len(delta)) < sz {
+ return nil, ErrInvalidDelta
}
+
dest = append(dest, delta[0:sz]...)
remainingTargetSz -= sz
delta = delta[sz:]
} else {
- return nil
+ return nil, ErrDeltaCmd
}
if remainingTargetSz <= 0 {
@@ -86,7 +116,7 @@ func PatchDelta(src, delta []byte) []byte {
}
}
- return dest
+ return dest, nil
}
// Decodes a number encoded as an unsigned LEB128 at the start of some
@@ -124,39 +154,60 @@ func isCopyFromDelta(cmd byte) bool {
return (cmd&0x80) == 0 && cmd != 0
}
-func decodeOffset(cmd byte, delta []byte) (uint, []byte) {
+func decodeOffset(cmd byte, delta []byte) (uint, []byte, error) {
var offset uint
if (cmd & 0x01) != 0 {
+ if len(delta) == 0 {
+ return 0, nil, ErrInvalidDelta
+ }
offset = uint(delta[0])
delta = delta[1:]
}
if (cmd & 0x02) != 0 {
+ if len(delta) == 0 {
+ return 0, nil, ErrInvalidDelta
+ }
offset |= uint(delta[0]) << 8
delta = delta[1:]
}
if (cmd & 0x04) != 0 {
+ if len(delta) == 0 {
+ return 0, nil, ErrInvalidDelta
+ }
offset |= uint(delta[0]) << 16
delta = delta[1:]
}
if (cmd & 0x08) != 0 {
+ if len(delta) == 0 {
+ return 0, nil, ErrInvalidDelta
+ }
offset |= uint(delta[0]) << 24
delta = delta[1:]
}
- return offset, delta
+ return offset, delta, nil
}
-func decodeSize(cmd byte, delta []byte) (uint, []byte) {
+func decodeSize(cmd byte, delta []byte) (uint, []byte, error) {
var sz uint
if (cmd & 0x10) != 0 {
+ if len(delta) == 0 {
+ return 0, nil, ErrInvalidDelta
+ }
sz = uint(delta[0])
delta = delta[1:]
}
if (cmd & 0x20) != 0 {
+ if len(delta) == 0 {
+ return 0, nil, ErrInvalidDelta
+ }
sz |= uint(delta[0]) << 8
delta = delta[1:]
}
if (cmd & 0x40) != 0 {
+ if len(delta) == 0 {
+ return 0, nil, ErrInvalidDelta
+ }
sz |= uint(delta[0]) << 16
delta = delta[1:]
}
@@ -164,7 +215,7 @@ func decodeSize(cmd byte, delta []byte) (uint, []byte) {
sz = 0x10000
}
- return sz, delta
+ return sz, delta, nil
}
func invalidSize(sz, targetSz uint) bool {
diff --git a/plumbing/object/commit_walker.go b/plumbing/object/commit_walker.go
index 8d2c6e8..797c17a 100644
--- a/plumbing/object/commit_walker.go
+++ b/plumbing/object/commit_walker.go
@@ -18,10 +18,16 @@ type commitPreIterator struct {
// The given callback will be called for each visited commit. Each commit will
// be visited only once. If the callback returns an error, walking will stop
// and will return the error. Other errors might be returned if the history
-// cannot be traversed (e.g. missing objects).
-func NewCommitPreorderIter(c *Commit) CommitIter {
+// cannot be traversed (e.g. missing objects). Ignore allows to skip some
+// commits from being iterated.
+func NewCommitPreorderIter(c *Commit, ignore []plumbing.Hash) CommitIter {
+ seen := make(map[plumbing.Hash]bool)
+ for _, h := range ignore {
+ seen[h] = true
+ }
+
return &commitPreIterator{
- seen: make(map[plumbing.Hash]bool),
+ seen: seen,
stack: make([]CommitIter, 0),
start: c,
}
@@ -51,20 +57,33 @@ func (w *commitPreIterator) Next() (*Commit, error) {
}
}
- // check and update seen
if w.seen[c.Hash] {
continue
}
w.seen[c.Hash] = true
+
if c.NumParents() > 0 {
- w.stack = append(w.stack, c.Parents())
+ w.stack = append(w.stack, filteredParentIter(c, w.seen))
}
return c, nil
}
}
+func filteredParentIter(c *Commit, seen map[plumbing.Hash]bool) CommitIter {
+ var hashes []plumbing.Hash
+ for _, h := range c.ParentHashes {
+ if !seen[h] {
+ hashes = append(hashes, h)
+ }
+ }
+
+ return NewCommitIter(c.s,
+ storer.NewEncodedObjectLookupIter(c.s, plumbing.CommitObject, hashes),
+ )
+}
+
func (w *commitPreIterator) ForEach(cb func(*Commit) error) error {
for {
c, err := w.Next()
@@ -98,11 +117,16 @@ type commitPostIterator struct {
// history like WalkCommitHistory but in post-order. This means that after
// walking a merge commit, the merged commit will be walked before the base
// it was merged on. This can be useful if you wish to see the history in
-// chronological order.
-func NewCommitPostorderIter(c *Commit) CommitIter {
+// chronological order. Ignore allows to skip some commits from being iterated.
+func NewCommitPostorderIter(c *Commit, ignore []plumbing.Hash) CommitIter {
+ seen := make(map[plumbing.Hash]bool)
+ for _, h := range ignore {
+ seen[h] = true
+ }
+
return &commitPostIterator{
stack: []*Commit{c},
- seen: make(map[plumbing.Hash]bool),
+ seen: seen,
}
}
@@ -114,17 +138,17 @@ func (w *commitPostIterator) Next() (*Commit, error) {
c := w.stack[len(w.stack)-1]
w.stack = w.stack[:len(w.stack)-1]
+
if w.seen[c.Hash] {
continue
}
+
w.seen[c.Hash] = true
- err := c.Parents().ForEach(func(pcm *Commit) error {
- w.stack = append(w.stack, pcm)
+ return c, c.Parents().ForEach(func(p *Commit) error {
+ w.stack = append(w.stack, p)
return nil
})
-
- return c, err
}
}
diff --git a/plumbing/object/commit_walker_test.go b/plumbing/object/commit_walker_test.go
index 2a03057..48b504d 100644
--- a/plumbing/object/commit_walker_test.go
+++ b/plumbing/object/commit_walker_test.go
@@ -1,6 +1,10 @@
package object
-import . "gopkg.in/check.v1"
+import (
+ "gopkg.in/src-d/go-git.v4/plumbing"
+
+ . "gopkg.in/check.v1"
+)
type CommitWalkerSuite struct {
BaseObjectsSuite
@@ -12,8 +16,7 @@ func (s *CommitWalkerSuite) TestCommitPreIterator(c *C) {
commit := s.commit(c, s.Fixture.Head)
var commits []*Commit
- wIter := NewCommitPreorderIter(commit)
- wIter.ForEach(func(c *Commit) error {
+ NewCommitPreorderIter(commit, nil).ForEach(func(c *Commit) error {
commits = append(commits, c)
return nil
})
@@ -35,12 +38,33 @@ func (s *CommitWalkerSuite) TestCommitPreIterator(c *C) {
}
}
+func (s *CommitWalkerSuite) TestCommitPreIteratorWithIgnore(c *C) {
+ commit := s.commit(c, s.Fixture.Head)
+
+ var commits []*Commit
+ NewCommitPreorderIter(commit, []plumbing.Hash{
+ plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"),
+ }).ForEach(func(c *Commit) error {
+ commits = append(commits, c)
+ return nil
+ })
+
+ c.Assert(commits, HasLen, 2)
+
+ expected := []string{
+ "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
+ "918c48b83bd081e863dbe1b80f8998f058cd8294",
+ }
+ for i, commit := range commits {
+ c.Assert(commit.Hash.String(), Equals, expected[i])
+ }
+}
+
func (s *CommitWalkerSuite) TestCommitPostIterator(c *C) {
commit := s.commit(c, s.Fixture.Head)
var commits []*Commit
- wIter := NewCommitPostorderIter(commit)
- wIter.ForEach(func(c *Commit) error {
+ NewCommitPostorderIter(commit, nil).ForEach(func(c *Commit) error {
commits = append(commits, c)
return nil
})
@@ -57,6 +81,29 @@ func (s *CommitWalkerSuite) TestCommitPostIterator(c *C) {
"b029517f6300c2da0f4b651b8642506cd6aaf45d",
"35e85108805c84807bc66a02d91535e1e24b38b9",
}
+
+ for i, commit := range commits {
+ c.Assert(commit.Hash.String(), Equals, expected[i])
+ }
+}
+
+func (s *CommitWalkerSuite) TestCommitPostIteratorWithIgnore(c *C) {
+ commit := s.commit(c, s.Fixture.Head)
+
+ var commits []*Commit
+ NewCommitPostorderIter(commit, []plumbing.Hash{
+ plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"),
+ }).ForEach(func(c *Commit) error {
+ commits = append(commits, c)
+ return nil
+ })
+
+ c.Assert(commits, HasLen, 2)
+
+ expected := []string{
+ "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
+ "918c48b83bd081e863dbe1b80f8998f058cd8294",
+ }
for i, commit := range commits {
c.Assert(commit.Hash.String(), Equals, expected[i])
}
diff --git a/plumbing/revlist/revlist.go b/plumbing/revlist/revlist.go
index 20bc99d..1bda2fa 100644
--- a/plumbing/revlist/revlist.go
+++ b/plumbing/revlist/revlist.go
@@ -16,11 +16,7 @@ import (
// the reachable objects from the given objects. Ignore param are object hashes
// that we want to ignore on the result. All that objects must be accessible
// from the object storer.
-func Objects(
- s storer.EncodedObjectStorer,
- objects []plumbing.Hash,
- ignore []plumbing.Hash) ([]plumbing.Hash, error) {
-
+func Objects(s storer.EncodedObjectStorer, objects, ignore []plumbing.Hash) ([]plumbing.Hash, error) {
seen := hashListToSet(ignore)
result := make(map[plumbing.Hash]bool)
@@ -32,7 +28,7 @@ func Objects(
}
for _, h := range objects {
- if err := processObject(s, h, seen, walkerFunc); err != nil {
+ if err := processObject(s, h, seen, ignore, walkerFunc); err != nil {
return nil, err
}
}
@@ -45,6 +41,7 @@ func processObject(
s storer.EncodedObjectStorer,
h plumbing.Hash,
seen map[plumbing.Hash]bool,
+ ignore []plumbing.Hash,
walkerFunc func(h plumbing.Hash),
) error {
o, err := s.EncodedObject(plumbing.AnyObject, h)
@@ -59,12 +56,12 @@ func processObject(
switch do := do.(type) {
case *object.Commit:
- return reachableObjects(do, seen, walkerFunc)
+ return reachableObjects(do, seen, ignore, walkerFunc)
case *object.Tree:
return iterateCommitTrees(seen, do, walkerFunc)
case *object.Tag:
walkerFunc(do.Hash)
- return processObject(s, do.Target, seen, walkerFunc)
+ return processObject(s, do.Target, seen, ignore, walkerFunc)
case *object.Blob:
walkerFunc(do.Hash)
default:
@@ -82,22 +79,24 @@ func processObject(
func reachableObjects(
commit *object.Commit,
seen map[plumbing.Hash]bool,
+ ignore []plumbing.Hash,
cb func(h plumbing.Hash)) error {
- return object.NewCommitPreorderIter(commit).
- ForEach(func(commit *object.Commit) error {
- if seen[commit.Hash] {
- return nil
- }
- cb(commit.Hash)
+ i := object.NewCommitPreorderIter(commit, ignore)
+ return i.ForEach(func(commit *object.Commit) error {
+ if seen[commit.Hash] {
+ return nil
+ }
+
+ cb(commit.Hash)
- tree, err := commit.Tree()
- if err != nil {
- return err
- }
+ tree, err := commit.Tree()
+ if err != nil {
+ return err
+ }
- return iterateCommitTrees(seen, tree, cb)
- })
+ return iterateCommitTrees(seen, tree, cb)
+ })
}
// iterateCommitTrees iterate all reachable trees from the given commit
diff --git a/plumbing/transport/git/receive_pack_test.go b/plumbing/transport/git/receive_pack_test.go
index 326ef1b..f9afede 100644
--- a/plumbing/transport/git/receive_pack_test.go
+++ b/plumbing/transport/git/receive_pack_test.go
@@ -99,9 +99,11 @@ func (s *ReceivePackSuite) SetUpTest(c *C) {
}
func (s *ReceivePackSuite) TearDownTest(c *C) {
- err := s.daemon.Process.Signal(os.Interrupt)
+ err := s.daemon.Process.Signal(os.Kill)
c.Assert(err, IsNil)
+
_ = s.daemon.Wait()
+
err = os.RemoveAll(s.base)
c.Assert(err, IsNil)
}
diff --git a/plumbing/transport/server/loader.go b/plumbing/transport/server/loader.go
index d4eccd4..028ead4 100644
--- a/plumbing/transport/server/loader.go
+++ b/plumbing/transport/server/loader.go
@@ -10,7 +10,7 @@ import (
)
// DefaultLoader is a filesystem loader ignoring host and resolving paths to /.
-var DefaultLoader = NewFilesystemLoader(osfs.New("/"))
+var DefaultLoader = NewFilesystemLoader(osfs.New(""))
// Loader loads repository's storer.Storer based on an optional host and a path.
type Loader interface {
diff --git a/remote.go b/remote.go
index 8f1da2f..fa984cf 100644
--- a/remote.go
+++ b/remote.go
@@ -104,6 +104,7 @@ func (r *Remote) Push(o *PushOptions) (err error) {
req := packp.NewReferenceUpdateRequestFromCapabilities(ar.Capabilities)
if err := r.addReferencesToUpdate(o.RefSpecs, remoteRefs, req); err != nil {
+
return err
}
@@ -121,6 +122,15 @@ func (r *Remote) Push(o *PushOptions) (err error) {
return err
}
+ stop, err := r.s.Shallow()
+ if err != nil {
+ return err
+ }
+
+ // if we have shallow we should include this as part of the objects that
+ // we are aware.
+ haves = append(haves, stop...)
+
hashesToPush, err := revlist.Objects(r.s, objects, haves)
if err != nil {
return err
@@ -486,7 +496,7 @@ func isFastForward(s storer.EncodedObjectStorer, old, new plumbing.Hash) (bool,
}
found := false
- iter := object.NewCommitPreorderIter(c)
+ iter := object.NewCommitPreorderIter(c, nil)
return found, iter.ForEach(func(c *object.Commit) error {
if c.Hash != old {
return nil
diff --git a/repository.go b/repository.go
index 17f0dff..ec9f254 100644
--- a/repository.go
+++ b/repository.go
@@ -689,7 +689,7 @@ func (r *Repository) Log(o *LogOptions) (object.CommitIter, error) {
return nil, err
}
- return object.NewCommitPreorderIter(commit), nil
+ return object.NewCommitPreorderIter(commit, nil), nil
}
// Tags returns all the References from Tags. This method returns all the tag
@@ -918,7 +918,7 @@ func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, err
commit = c
}
case revision.CaretReg:
- history := object.NewCommitPreorderIter(commit)
+ history := object.NewCommitPreorderIter(commit, nil)
re := item.(revision.CaretReg).Regexp
negate := item.(revision.CaretReg).Negate
@@ -948,7 +948,7 @@ func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, err
commit = c
case revision.AtDate:
- history := object.NewCommitPreorderIter(commit)
+ history := object.NewCommitPreorderIter(commit, nil)
date := item.(revision.AtDate).Date
diff --git a/repository_test.go b/repository_test.go
index f622007..f31cd1d 100644
--- a/repository_test.go
+++ b/repository_test.go
@@ -20,6 +20,7 @@ import (
. "gopkg.in/check.v1"
"gopkg.in/src-d/go-billy.v3/memfs"
"gopkg.in/src-d/go-billy.v3/osfs"
+ "gopkg.in/src-d/go-billy.v3/util"
)
type RepositorySuite struct {
@@ -767,6 +768,50 @@ func (s *RepositorySuite) TestPushToEmptyRepository(c *C) {
c.Assert(err, IsNil)
}
+func (s *RepositorySuite) TestPushDepth(c *C) {
+ dir, err := ioutil.TempDir("", "push-depth")
+ defer os.RemoveAll(dir)
+
+ origin, err := PlainClone(c.MkDir(), true, &CloneOptions{
+ URL: fixtures.Basic().One().DotGit().Root(),
+ })
+
+ c.Assert(err, IsNil)
+ fs := origin.Storer.(*filesystem.Storage).Filesystem()
+
+ r, err := Clone(memory.NewStorage(), memfs.New(), &CloneOptions{
+ URL: fs.Root(),
+ 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)
+
+ remote, err := origin.Head()
+ c.Assert(err, IsNil)
+ c.Assert(remote.Hash(), Equals, hash)
+
+ local, err := r.Head()
+ c.Assert(err, IsNil)
+ c.Assert(local.Hash(), Equals, remote.Hash())
+}
+
func (s *RepositorySuite) TestPushNonExistentRemote(c *C) {
srcFs := fixtures.Basic().One().DotGit()
sto, err := filesystem.NewStorage(srcFs)
diff --git a/storage/filesystem/internal/dotgit/dotgit.go b/storage/filesystem/internal/dotgit/dotgit.go
index 9bbf4e8..e2ff51b 100644
--- a/storage/filesystem/internal/dotgit/dotgit.go
+++ b/storage/filesystem/internal/dotgit/dotgit.go
@@ -348,7 +348,6 @@ func (d *DotGit) rewritePackedRefsWithoutRef(name plumbing.ReferenceName) (err e
return err
}
- defer ioutil.CheckClose(f, &err)
// Creating the temp file in the same directory as the target file
// improves our chances for rename operation to be atomic.
@@ -357,10 +356,6 @@ func (d *DotGit) rewritePackedRefsWithoutRef(name plumbing.ReferenceName) (err e
return err
}
- tmpPath := tmp.Name()
- defer ioutil.CheckClose(tmp, &err)
- defer d.fs.Remove(tmpPath)
-
s := bufio.NewScanner(f)
found := false
for s.Scan() {
@@ -388,7 +383,16 @@ func (d *DotGit) rewritePackedRefsWithoutRef(name plumbing.ReferenceName) (err e
return nil
}
- return d.fs.Rename(tmpPath, packedRefsPath)
+ if err := f.Close(); err != nil {
+ ioutil.CheckClose(tmp, &err)
+ return err
+ }
+
+ if err := tmp.Close(); err != nil {
+ return err
+ }
+
+ return d.fs.Rename(tmp.Name(), packedRefsPath)
}
// process lines from a packed-refs file
diff --git a/storage/filesystem/internal/dotgit/dotgit_test.go b/storage/filesystem/internal/dotgit/dotgit_test.go
index d4cda0e..d935ec5 100644
--- a/storage/filesystem/internal/dotgit/dotgit_test.go
+++ b/storage/filesystem/internal/dotgit/dotgit_test.go
@@ -373,6 +373,7 @@ func (s *SuiteDotGit) TestObjectPackIdx(c *C) {
idx, err := dir.ObjectPackIdx(f.PackfileHash)
c.Assert(err, IsNil)
c.Assert(filepath.Ext(idx.Name()), Equals, ".idx")
+ c.Assert(idx.Close(), IsNil)
}
func (s *SuiteDotGit) TestObjectPackNotFound(c *C) {
diff --git a/utils/merkletrie/filesystem/node.go b/utils/merkletrie/filesystem/node.go
index a8f3b86..f763e08 100644
--- a/utils/merkletrie/filesystem/node.go
+++ b/utils/merkletrie/filesystem/node.go
@@ -3,7 +3,7 @@ package filesystem
import (
"io"
"os"
- "path/filepath"
+ "path"
"gopkg.in/src-d/go-billy.v3"
"gopkg.in/src-d/go-git.v4/plumbing"
@@ -53,7 +53,7 @@ func (n *node) Hash() []byte {
}
func (n *node) Name() string {
- return filepath.Base(n.path)
+ return path.Base(n.path)
}
func (n *node) IsDir() bool {
@@ -107,7 +107,7 @@ func (n *node) calculateChildren() error {
}
func (n *node) newChildNode(file os.FileInfo) (*node, error) {
- path := filepath.Join(n.path, file.Name())
+ path := path.Join(n.path, file.Name())
hash, err := n.calculateHash(path, file)
if err != nil {
diff --git a/utils/merkletrie/filesystem/node_test.go b/utils/merkletrie/filesystem/node_test.go
index bf1178a..42dd82e 100644
--- a/utils/merkletrie/filesystem/node_test.go
+++ b/utils/merkletrie/filesystem/node_test.go
@@ -4,6 +4,7 @@ import (
"bytes"
"io"
"os"
+ "path"
"testing"
. "gopkg.in/check.v1"
@@ -133,18 +134,19 @@ func (s *NoderSuite) TestDiffChangeModeNotRelevant(c *C) {
}
func (s *NoderSuite) TestDiffDirectory(c *C) {
+ dir := path.Join("qux", "bar")
fsA := memfs.New()
- fsA.MkdirAll("qux/bar", 0644)
+ fsA.MkdirAll(dir, 0644)
fsB := memfs.New()
- fsB.MkdirAll("qux/bar", 0644)
+ fsB.MkdirAll(dir, 0644)
ch, err := merkletrie.DiffTree(
NewRootNode(fsA, map[string]plumbing.Hash{
- "qux/bar": plumbing.NewHash("aa102815663d23f8b75a47e7a01965dcdc96468c"),
+ dir: plumbing.NewHash("aa102815663d23f8b75a47e7a01965dcdc96468c"),
}),
NewRootNode(fsB, map[string]plumbing.Hash{
- "qux/bar": plumbing.NewHash("19102815663d23f8b75a47e7a01965dcdc96468c"),
+ dir: plumbing.NewHash("19102815663d23f8b75a47e7a01965dcdc96468c"),
}),
IsEquals,
)
diff --git a/utils/merkletrie/index/node.go b/utils/merkletrie/index/node.go
index 859c097..9622622 100644
--- a/utils/merkletrie/index/node.go
+++ b/utils/merkletrie/index/node.go
@@ -1,7 +1,7 @@
package index
import (
- "path/filepath"
+ "path"
"strings"
"gopkg.in/src-d/go-git.v4/plumbing/format/index"
@@ -28,19 +28,19 @@ func NewRootNode(idx *index.Index) noder.Noder {
m := map[string]*node{rootNode: {isDir: true}}
for _, e := range idx.Entries {
- parts := strings.Split(e.Name, string(filepath.Separator))
+ parts := strings.Split(e.Name, string("/"))
- var path string
+ var fullpath string
for _, part := range parts {
- parent := path
- path = filepath.Join(path, part)
+ parent := fullpath
+ fullpath = path.Join(fullpath, part)
- if _, ok := m[path]; ok {
+ if _, ok := m[fullpath]; ok {
continue
}
- n := &node{path: path}
- if path == e.Name {
+ n := &node{path: fullpath}
+ if fullpath == e.Name {
n.entry = e
} else {
n.isDir = true
@@ -74,7 +74,7 @@ func (n *node) Hash() []byte {
}
func (n *node) Name() string {
- return filepath.Base(n.path)
+ return path.Base(n.path)
}
func (n *node) IsDir() bool {
diff --git a/utils/merkletrie/index/node_test.go b/utils/merkletrie/index/node_test.go
index 00da8da..283ca74 100644
--- a/utils/merkletrie/index/node_test.go
+++ b/utils/merkletrie/index/node_test.go
@@ -2,6 +2,7 @@ package index
import (
"bytes"
+ "path/filepath"
"testing"
. "gopkg.in/check.v1"
@@ -43,15 +44,17 @@ func (s *NoderSuite) TestDiff(c *C) {
func (s *NoderSuite) TestDiffChange(c *C) {
indexA := &index.Index{
- Entries: []*index.Entry{
- {Name: "bar/baz/bar", Hash: plumbing.NewHash("8ab686eafeb1f44702738c8b0f24f2567c36da6d")},
- },
+ Entries: []*index.Entry{{
+ Name: filepath.Join("bar", "baz", "bar"),
+ Hash: plumbing.NewHash("8ab686eafeb1f44702738c8b0f24f2567c36da6d"),
+ }},
}
indexB := &index.Index{
- Entries: []*index.Entry{
- {Name: "bar/baz/foo", Hash: plumbing.NewHash("8ab686eafeb1f44702738c8b0f24f2567c36da6d")},
- },
+ Entries: []*index.Entry{{
+ Name: filepath.Join("bar", "baz", "foo"),
+ Hash: plumbing.NewHash("8ab686eafeb1f44702738c8b0f24f2567c36da6d"),
+ }},
}
ch, err := merkletrie.DiffTree(NewRootNode(indexA), NewRootNode(indexB), isEquals)
@@ -61,15 +64,17 @@ func (s *NoderSuite) TestDiffChange(c *C) {
func (s *NoderSuite) TestDiffDir(c *C) {
indexA := &index.Index{
- Entries: []*index.Entry{
- {Name: "foo", Hash: plumbing.NewHash("8ab686eafeb1f44702738c8b0f24f2567c36da6d")},
- },
+ Entries: []*index.Entry{{
+ Name: "foo",
+ Hash: plumbing.NewHash("8ab686eafeb1f44702738c8b0f24f2567c36da6d"),
+ }},
}
indexB := &index.Index{
- Entries: []*index.Entry{
- {Name: "foo/bar", Hash: plumbing.NewHash("8ab686eafeb1f44702738c8b0f24f2567c36da6d")},
- },
+ Entries: []*index.Entry{{
+ Name: filepath.Join("foo", "bar"),
+ Hash: plumbing.NewHash("8ab686eafeb1f44702738c8b0f24f2567c36da6d"),
+ }},
}
ch, err := merkletrie.DiffTree(NewRootNode(indexA), NewRootNode(indexB), isEquals)
diff --git a/worktree.go b/worktree.go
index e0f5fdf..13b2497 100644
--- a/worktree.go
+++ b/worktree.go
@@ -496,6 +496,10 @@ func (w *Worktree) Submodules() (Submodules, error) {
}
c, err := w.r.Config()
+ if err != nil {
+ return nil, err
+ }
+
for _, s := range m.Submodules {
l = append(l, w.newSubmodule(s, c.Submodules[s.Name]))
}
@@ -527,6 +531,7 @@ func (w *Worktree) readGitmodulesFile() (*config.Modules, error) {
return nil, err
}
+ defer f.Close()
input, err := stdioutil.ReadAll(f)
if err != nil {
return nil, err
diff --git a/worktree_commit.go b/worktree_commit.go
index a342240..02a5d03 100644
--- a/worktree_commit.go
+++ b/worktree_commit.go
@@ -1,7 +1,7 @@
package git
import (
- "path/filepath"
+ "path"
"strings"
"gopkg.in/src-d/go-git.v4/plumbing"
@@ -128,36 +128,36 @@ func (h *buildTreeHelper) BuildTree(idx *index.Index) (plumbing.Hash, error) {
}
func (h *buildTreeHelper) commitIndexEntry(e *index.Entry) error {
- parts := strings.Split(e.Name, string(filepath.Separator))
+ parts := strings.Split(e.Name, "/")
- var path string
+ var fullpath string
for _, part := range parts {
- parent := path
- path = filepath.Join(path, part)
+ parent := fullpath
+ fullpath = path.Join(fullpath, part)
- h.doBuildTree(e, parent, path)
+ h.doBuildTree(e, parent, fullpath)
}
return nil
}
-func (h *buildTreeHelper) doBuildTree(e *index.Entry, parent, path string) {
- if _, ok := h.trees[path]; ok {
+func (h *buildTreeHelper) doBuildTree(e *index.Entry, parent, fullpath string) {
+ if _, ok := h.trees[fullpath]; ok {
return
}
- if _, ok := h.entries[path]; ok {
+ if _, ok := h.entries[fullpath]; ok {
return
}
- te := object.TreeEntry{Name: filepath.Base(path)}
+ te := object.TreeEntry{Name: path.Base(fullpath)}
- if path == e.Name {
+ if fullpath == e.Name {
te.Mode = e.Mode
te.Hash = e.Hash
} else {
te.Mode = filemode.Dir
- h.trees[path] = &object.Tree{}
+ h.trees[fullpath] = &object.Tree{}
}
h.trees[parent].Entries = append(h.trees[parent].Entries, te)
@@ -169,7 +169,7 @@ func (h *buildTreeHelper) copyTreeToStorageRecursive(parent string, t *object.Tr
continue
}
- path := filepath.Join(parent, e.Name)
+ path := path.Join(parent, e.Name)
var err error
e.Hash, err = h.copyTreeToStorageRecursive(path, h.trees[path])
diff --git a/worktree_linux.go b/worktree_linux.go
index 7209d7d..a33cd2f 100644
--- a/worktree_linux.go
+++ b/worktree_linux.go
@@ -12,7 +12,6 @@ import (
func init() {
fillSystemInfo = func(e *index.Entry, sys interface{}) {
if os, ok := sys.(*syscall.Stat_t); ok {
-
e.CreatedAt = time.Unix(int64(os.Ctim.Sec), int64(os.Ctim.Nsec))
e.Dev = uint32(os.Dev)
e.Inode = uint32(os.Ino)
diff --git a/worktree_windows.go b/worktree_windows.go
new file mode 100644
index 0000000..d59448e
--- /dev/null
+++ b/worktree_windows.go
@@ -0,0 +1,20 @@
+// +build windows
+
+package git
+
+import (
+ "syscall"
+ "time"
+
+ "gopkg.in/src-d/go-git.v4/plumbing/format/index"
+)
+
+func init() {
+ fillSystemInfo = func(e *index.Entry, sys interface{}) {
+ if os, ok := sys.(*syscall.Win32FileAttributeData); ok {
+ seconds := os.CreationTime.Nanoseconds() / 1000000000
+ nanoseconds := os.CreationTime.Nanoseconds() - seconds*1000000000
+ e.CreatedAt = time.Unix(seconds, nanoseconds)
+ }
+ }
+}