aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--_examples/README.md1
-rw-r--r--_examples/clone/auth/ssh/main.go52
-rw-r--r--blame_test.go2
-rw-r--r--config/branch_test.go3
-rw-r--r--internal/revision/parser.go8
-rw-r--r--internal/revision/parser_test.go17
-rw-r--r--plumbing/filemode/filemode.go2
-rw-r--r--plumbing/format/commitgraph/commitgraph_test.go5
-rw-r--r--plumbing/format/config/option.go2
-rw-r--r--plumbing/format/config/section.go2
-rw-r--r--plumbing/format/gitignore/dir.go12
-rw-r--r--plumbing/format/gitignore/dir_test.go18
-rw-r--r--plumbing/format/idxfile/encoder_test.go2
-rw-r--r--plumbing/format/idxfile/idxfile_test.go2
-rw-r--r--plumbing/format/idxfile/writer_test.go2
-rw-r--r--plumbing/format/index/decoder.go6
-rw-r--r--plumbing/format/index/decoder_test.go2
-rw-r--r--plumbing/format/index/encoder_test.go3
-rw-r--r--plumbing/format/objfile/common_test.go3
-rw-r--r--plumbing/format/objfile/reader_test.go3
-rw-r--r--plumbing/format/objfile/writer_test.go3
-rw-r--r--plumbing/format/packfile/encoder_advanced_test.go4
-rw-r--r--plumbing/format/packfile/encoder_test.go4
-rw-r--r--plumbing/format/packfile/patch_delta.go3
-rw-r--r--plumbing/memory.go17
-rw-r--r--plumbing/memory_test.go28
-rw-r--r--plumbing/object/change.go2
-rw-r--r--plumbing/object/commit.go24
-rw-r--r--plumbing/object/commit_stats_test.go3
-rw-r--r--plumbing/object/commit_walker_bfs_filtered.go1
-rw-r--r--plumbing/object/commit_walker_path.go3
-rw-r--r--plumbing/object/commitgraph/commitnode_test.go5
-rw-r--r--plumbing/object/commitgraph/commitnode_walker_ctime.go4
-rw-r--r--plumbing/object/file_test.go2
-rw-r--r--plumbing/object/patch.go16
-rw-r--r--plumbing/object/patch_test.go5
-rw-r--r--plumbing/object/rename.go6
-rw-r--r--plumbing/protocol/packp/capability/list.go5
-rw-r--r--plumbing/protocol/packp/ulreq.go32
-rw-r--r--plumbing/protocol/packp/ulreq_decode.go4
-rw-r--r--plumbing/protocol/packp/ulreq_encode.go4
-rw-r--r--plumbing/protocol/packp/updreq.go6
-rw-r--r--plumbing/protocol/packp/updreq_encode.go18
-rw-r--r--plumbing/protocol/packp/uppackresp_test.go2
-rw-r--r--plumbing/storer/object_test.go3
-rw-r--r--plumbing/storer/reference_test.go3
-rw-r--r--plumbing/transport/file/receive_pack_test.go2
-rw-r--r--plumbing/transport/git/common_test.go2
-rw-r--r--plumbing/transport/git/receive_pack_test.go2
-rw-r--r--plumbing/transport/git/upload_pack_test.go2
-rw-r--r--plumbing/transport/http/common_test.go2
-rw-r--r--plumbing/transport/http/receive_pack_test.go2
-rw-r--r--plumbing/transport/http/upload_pack_test.go2
-rw-r--r--plumbing/transport/server/receive_pack_test.go1
-rw-r--r--plumbing/transport/ssh/common_test.go5
-rw-r--r--plumbing/transport/test/upload_pack.go2
-rw-r--r--prune_test.go2
-rw-r--r--references_test.go2
-rw-r--r--remote.go21
-rw-r--r--remote_test.go25
-rw-r--r--repository.go104
-rw-r--r--repository_test.go18
-rw-r--r--storage/filesystem/config_test.go4
-rw-r--r--storage/filesystem/dotgit/dotgit.go77
-rw-r--r--storage/filesystem/dotgit/dotgit_test.go35
-rw-r--r--storage/filesystem/dotgit/writers_test.go2
-rw-r--r--storage/filesystem/object.go31
-rw-r--r--storage/filesystem/object_test.go17
-rw-r--r--storage/memory/storage.go4
-rw-r--r--storage/transactional/config_test.go3
-rw-r--r--storage/transactional/index_test.go3
-rw-r--r--storage/transactional/object_test.go3
-rw-r--r--storage/transactional/reference.go2
-rw-r--r--storage/transactional/reference_test.go3
-rw-r--r--storage/transactional/shallow_test.go3
-rw-r--r--submodule_test.go2
-rw-r--r--utils/binary/read_test.go3
-rw-r--r--utils/diff/diff.go2
-rw-r--r--utils/merkletrie/filesystem/node.go3
-rw-r--r--utils/merkletrie/filesystem/node_test.go7
-rw-r--r--utils/merkletrie/index/node_test.go3
-rw-r--r--worktree.go3
-rw-r--r--worktree_commit.go12
83 files changed, 580 insertions, 190 deletions
diff --git a/_examples/README.md b/_examples/README.md
index 80d4dd5..92b9d4d 100644
--- a/_examples/README.md
+++ b/_examples/README.md
@@ -10,6 +10,7 @@ Here you can find a list of annotated _go-git_ examples:
using a username and password.
- [personal access token](clone/auth/basic/access_token/main.go) - Cloning
a repository using a GitHub personal access token.
+ - [ssh private key](clone/auth/ssh/main.go) - Cloning a repository using a ssh private key.
- [commit](commit/main.go) - Commit changes to the current branch to an existent repository.
- [push](push/main.go) - Push repository to default remote (origin).
- [pull](pull/main.go) - Pull changes from a remote repository.
diff --git a/_examples/clone/auth/ssh/main.go b/_examples/clone/auth/ssh/main.go
new file mode 100644
index 0000000..1e06e44
--- /dev/null
+++ b/_examples/clone/auth/ssh/main.go
@@ -0,0 +1,52 @@
+package main
+
+import (
+ "fmt"
+ "os"
+
+ git "github.com/go-git/go-git/v5"
+ . "github.com/go-git/go-git/v5/_examples"
+ "github.com/go-git/go-git/v5/plumbing/transport/ssh"
+)
+
+func main() {
+ CheckArgs("<url>", "<directory>", "<private_key_file>")
+ url, directory, privateKeyFile := os.Args[1], os.Args[2], os.Args[3]
+ var password string
+ if len(os.Args) == 5 {
+ password = os.Args[4]
+ }
+
+ _, err := os.Stat(privateKeyFile)
+ if err != nil {
+ Warning("read file %s failed %s\n", privateKeyFile, err.Error())
+ return
+ }
+
+ // Clone the given repository to the given directory
+ Info("git clone %s ", url)
+ publicKeys, err := ssh.NewPublicKeysFromFile("git", privateKeyFile, password)
+ if err != nil {
+ Warning("generate publickeys failed: %s\n", err.Error())
+ return
+ }
+
+ r, err := git.PlainClone(directory, false, &git.CloneOptions{
+ // The intended use of a GitHub personal access token is in replace of your password
+ // because access tokens can easily be revoked.
+ // https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/
+ Auth: publicKeys,
+ URL: url,
+ Progress: os.Stdout,
+ })
+ CheckIfError(err)
+
+ // ... retrieving the branch being pointed by HEAD
+ ref, err := r.Head()
+ CheckIfError(err)
+ // ... retrieving the commit object
+ commit, err := r.CommitObject(ref.Hash())
+ CheckIfError(err)
+
+ fmt.Println(commit)
+}
diff --git a/blame_test.go b/blame_test.go
index 398f839..7895b66 100644
--- a/blame_test.go
+++ b/blame_test.go
@@ -4,8 +4,8 @@ import (
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
+ fixtures "github.com/go-git/go-git-fixtures/v4"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git-fixtures/v4"
)
type BlameSuite struct {
diff --git a/config/branch_test.go b/config/branch_test.go
index a2c86cd..ae1fe85 100644
--- a/config/branch_test.go
+++ b/config/branch_test.go
@@ -1,8 +1,9 @@
package config
import (
- . "gopkg.in/check.v1"
"github.com/go-git/go-git/v5/plumbing"
+
+ . "gopkg.in/check.v1"
)
type BranchSuite struct{}
diff --git a/internal/revision/parser.go b/internal/revision/parser.go
index 61de386..8facf17 100644
--- a/internal/revision/parser.go
+++ b/internal/revision/parser.go
@@ -28,7 +28,7 @@ func (e *ErrInvalidRevision) Error() string {
type Revisioner interface {
}
-// Ref represents a reference name : HEAD, master
+// Ref represents a reference name : HEAD, master, <hash>
type Ref string
// TildePath represents ~, ~{n}
@@ -297,7 +297,7 @@ func (p *Parser) parseAt() (Revisioner, error) {
}
if t != cbrace {
- return nil, &ErrInvalidRevision{fmt.Sprintf(`missing "}" in @{-n} structure`)}
+ return nil, &ErrInvalidRevision{s: `missing "}" in @{-n} structure`}
}
return AtCheckout{n}, nil
@@ -419,7 +419,7 @@ func (p *Parser) parseCaretBraces() (Revisioner, error) {
case re == "" && tok == emark && nextTok == minus:
negate = true
case re == "" && tok == emark:
- return nil, &ErrInvalidRevision{fmt.Sprintf(`revision suffix brace component sequences starting with "/!" others than those defined are reserved`)}
+ return nil, &ErrInvalidRevision{s: `revision suffix brace component sequences starting with "/!" others than those defined are reserved`}
case re == "" && tok == slash:
p.unscan()
case tok != slash && start:
@@ -490,7 +490,7 @@ func (p *Parser) parseColonSlash() (Revisioner, error) {
case re == "" && tok == emark && nextTok == minus:
negate = true
case re == "" && tok == emark:
- return nil, &ErrInvalidRevision{fmt.Sprintf(`revision suffix brace component sequences starting with "/!" others than those defined are reserved`)}
+ return nil, &ErrInvalidRevision{s: `revision suffix brace component sequences starting with "/!" others than those defined are reserved`}
case tok == eof:
p.unscan()
reg, err := regexp.Compile(re)
diff --git a/internal/revision/parser_test.go b/internal/revision/parser_test.go
index fe45228..98403cc 100644
--- a/internal/revision/parser_test.go
+++ b/internal/revision/parser_test.go
@@ -96,8 +96,8 @@ func (s *ParserSuite) TestParseWithValidExpression(c *C) {
TildePath{3},
},
"@{2016-12-16T21:42:47Z}": []Revisioner{AtDate{tim}},
- "@{1}": []Revisioner{AtReflog{1}},
- "@{-1}": []Revisioner{AtCheckout{1}},
+ "@{1}": []Revisioner{AtReflog{1}},
+ "@{-1}": []Revisioner{AtCheckout{1}},
"master@{upstream}": []Revisioner{
Ref("master"),
AtUpstream{},
@@ -211,12 +211,12 @@ func (s *ParserSuite) TestParseAtWithValidExpression(c *C) {
tim, _ := time.Parse("2006-01-02T15:04:05Z", "2016-12-16T21:42:47Z")
datas := map[string]Revisioner{
- "": Ref("HEAD"),
- "{1}": AtReflog{1},
- "{-1}": AtCheckout{1},
- "{push}": AtPush{},
- "{upstream}": AtUpstream{},
- "{u}": AtUpstream{},
+ "": Ref("HEAD"),
+ "{1}": AtReflog{1},
+ "{-1}": AtCheckout{1},
+ "{push}": AtPush{},
+ "{upstream}": AtUpstream{},
+ "{u}": AtUpstream{},
"{2016-12-16T21:42:47Z}": AtDate{tim},
}
@@ -354,6 +354,7 @@ func (s *ParserSuite) TestParseRefWithValidName(c *C) {
"refs/remotes/test",
"refs/remotes/origin/HEAD",
"refs/remotes/origin/master",
+ "0123abcd", // short hash
}
for _, d := range datas {
diff --git a/plumbing/filemode/filemode.go b/plumbing/filemode/filemode.go
index 594984f..b848a97 100644
--- a/plumbing/filemode/filemode.go
+++ b/plumbing/filemode/filemode.go
@@ -118,7 +118,7 @@ func isSetSymLink(m os.FileMode) bool {
func (m FileMode) Bytes() []byte {
ret := make([]byte, 4)
binary.LittleEndian.PutUint32(ret, uint32(m))
- return ret[:]
+ return ret
}
// IsMalformed returns if the FileMode should not appear in a git packfile,
diff --git a/plumbing/format/commitgraph/commitgraph_test.go b/plumbing/format/commitgraph/commitgraph_test.go
index 7d7444b..de61ae9 100644
--- a/plumbing/format/commitgraph/commitgraph_test.go
+++ b/plumbing/format/commitgraph/commitgraph_test.go
@@ -6,10 +6,11 @@ import (
"path"
"testing"
- . "gopkg.in/check.v1"
- fixtures "github.com/go-git/go-git-fixtures/v4"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/format/commitgraph"
+
+ fixtures "github.com/go-git/go-git-fixtures/v4"
+ . "gopkg.in/check.v1"
)
func Test(t *testing.T) { TestingT(t) }
diff --git a/plumbing/format/config/option.go b/plumbing/format/config/option.go
index 316ff52..cad3948 100644
--- a/plumbing/format/config/option.go
+++ b/plumbing/format/config/option.go
@@ -19,7 +19,7 @@ type Options []*Option
// IsKey returns true if the given key matches
// this option's key in a case-insensitive comparison.
func (o *Option) IsKey(key string) bool {
- return strings.ToLower(o.Key) == strings.ToLower(key)
+ return strings.EqualFold(o.Key, key)
}
func (opts Options) GoString() string {
diff --git a/plumbing/format/config/section.go b/plumbing/format/config/section.go
index b7a684a..07f72f3 100644
--- a/plumbing/format/config/section.go
+++ b/plumbing/format/config/section.go
@@ -61,7 +61,7 @@ func (s Subsections) GoString() string {
// IsName checks if the name provided is equals to the Section name, case insensitive.
func (s *Section) IsName(name string) bool {
- return strings.ToLower(s.Name) == strings.ToLower(name)
+ return strings.EqualFold(s.Name, name)
}
// Subsection returns a Subsection from the specified Section. If the
diff --git a/plumbing/format/gitignore/dir.go b/plumbing/format/gitignore/dir.go
index f4444bf..4a26325 100644
--- a/plumbing/format/gitignore/dir.go
+++ b/plumbing/format/gitignore/dir.go
@@ -1,6 +1,7 @@
package gitignore
import (
+ "bufio"
"bytes"
"io/ioutil"
"os"
@@ -15,7 +16,6 @@ import (
const (
commentPrefix = "#"
coreSection = "core"
- eol = "\n"
excludesfile = "excludesfile"
gitDir = ".git"
gitignoreFile = ".gitignore"
@@ -29,11 +29,11 @@ func readIgnoreFile(fs billy.Filesystem, path []string, ignoreFile string) (ps [
if err == nil {
defer f.Close()
- if data, err := ioutil.ReadAll(f); err == nil {
- for _, s := range strings.Split(string(data), eol) {
- if !strings.HasPrefix(s, commentPrefix) && len(strings.TrimSpace(s)) > 0 {
- ps = append(ps, ParsePattern(s, path))
- }
+ scanner := bufio.NewScanner(f)
+ for scanner.Scan() {
+ s := scanner.Text()
+ if !strings.HasPrefix(s, commentPrefix) && len(strings.TrimSpace(s)) > 0 {
+ ps = append(ps, ParsePattern(s, path))
}
}
} else if !os.IsNotExist(err) {
diff --git a/plumbing/format/gitignore/dir_test.go b/plumbing/format/gitignore/dir_test.go
index c0301f7..a3e7ba6 100644
--- a/plumbing/format/gitignore/dir_test.go
+++ b/plumbing/format/gitignore/dir_test.go
@@ -15,7 +15,7 @@ type MatcherSuite struct {
RFS billy.Filesystem // root that contains user home
MCFS billy.Filesystem // root that contains user home, but missing ~/.gitconfig
MEFS billy.Filesystem // root that contains user home, but missing excludesfile entry
- MIFS billy.Filesystem // root that contains user home, but missing .gitnignore
+ MIFS billy.Filesystem // root that contains user home, but missing .gitignore
SFS billy.Filesystem // root that contains /etc/gitconfig
}
@@ -29,6 +29,8 @@ func (s *MatcherSuite) SetUpTest(c *C) {
c.Assert(err, IsNil)
_, err = f.Write([]byte("vendor/g*/\n"))
c.Assert(err, IsNil)
+ _, err = f.Write([]byte("ignore.crlf\r\n"))
+ c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
@@ -41,9 +43,14 @@ func (s *MatcherSuite) SetUpTest(c *C) {
err = f.Close()
c.Assert(err, IsNil)
- fs.MkdirAll("another", os.ModePerm)
- fs.MkdirAll("vendor/github.com", os.ModePerm)
- fs.MkdirAll("vendor/gopkg.in", os.ModePerm)
+ err = fs.MkdirAll("another", os.ModePerm)
+ c.Assert(err, IsNil)
+ err = fs.MkdirAll("ignore.crlf", os.ModePerm)
+ c.Assert(err, IsNil)
+ err = fs.MkdirAll("vendor/github.com", os.ModePerm)
+ c.Assert(err, IsNil)
+ err = fs.MkdirAll("vendor/gopkg.in", os.ModePerm)
+ c.Assert(err, IsNil)
s.GFS = fs
@@ -167,9 +174,10 @@ func (s *MatcherSuite) SetUpTest(c *C) {
func (s *MatcherSuite) TestDir_ReadPatterns(c *C) {
ps, err := ReadPatterns(s.GFS, nil)
c.Assert(err, IsNil)
- c.Assert(ps, HasLen, 2)
+ c.Assert(ps, HasLen, 3)
m := NewMatcher(ps)
+ c.Assert(m.Match([]string{"ignore.crlf"}, true), Equals, true)
c.Assert(m.Match([]string{"vendor", "gopkg.in"}, true), Equals, true)
c.Assert(m.Match([]string{"vendor", "github.com"}, true), Equals, false)
}
diff --git a/plumbing/format/idxfile/encoder_test.go b/plumbing/format/idxfile/encoder_test.go
index 81abb3b..32b60f9 100644
--- a/plumbing/format/idxfile/encoder_test.go
+++ b/plumbing/format/idxfile/encoder_test.go
@@ -6,8 +6,8 @@ import (
. "github.com/go-git/go-git/v5/plumbing/format/idxfile"
+ fixtures "github.com/go-git/go-git-fixtures/v4"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git-fixtures/v4"
)
func (s *IdxfileSuite) TestDecodeEncode(c *C) {
diff --git a/plumbing/format/idxfile/idxfile_test.go b/plumbing/format/idxfile/idxfile_test.go
index 5ef73d7..7a3d6bb 100644
--- a/plumbing/format/idxfile/idxfile_test.go
+++ b/plumbing/format/idxfile/idxfile_test.go
@@ -10,8 +10,8 @@ import (
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/format/idxfile"
+ fixtures "github.com/go-git/go-git-fixtures/v4"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git-fixtures/v4"
)
func BenchmarkFindOffset(b *testing.B) {
diff --git a/plumbing/format/idxfile/writer_test.go b/plumbing/format/idxfile/writer_test.go
index f86342f..fba3e42 100644
--- a/plumbing/format/idxfile/writer_test.go
+++ b/plumbing/format/idxfile/writer_test.go
@@ -9,8 +9,8 @@ import (
"github.com/go-git/go-git/v5/plumbing/format/idxfile"
"github.com/go-git/go-git/v5/plumbing/format/packfile"
+ fixtures "github.com/go-git/go-git-fixtures/v4"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git-fixtures/v4"
)
type WriterSuite struct {
diff --git a/plumbing/format/index/decoder.go b/plumbing/format/index/decoder.go
index 79d0b9e..036b636 100644
--- a/plumbing/format/index/decoder.go
+++ b/plumbing/format/index/decoder.go
@@ -188,7 +188,7 @@ func (d *Decoder) doReadEntryNameV4() (string, error) {
func (d *Decoder) doReadEntryName(len uint16) (string, error) {
name := make([]byte, len)
- _, err := io.ReadFull(d.r, name[:])
+ _, err := io.ReadFull(d.r, name)
return string(name), err
}
@@ -390,7 +390,9 @@ func (d *treeExtensionDecoder) readEntry() (*TreeEntry, error) {
e.Trees = i
_, err = io.ReadFull(d.r, e.Hash[:])
-
+ if err != nil {
+ return nil, err
+ }
return e, nil
}
diff --git a/plumbing/format/index/decoder_test.go b/plumbing/format/index/decoder_test.go
index 4e47dde..39ab336 100644
--- a/plumbing/format/index/decoder_test.go
+++ b/plumbing/format/index/decoder_test.go
@@ -6,8 +6,8 @@ import (
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/filemode"
+ fixtures "github.com/go-git/go-git-fixtures/v4"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git-fixtures/v4"
)
func Test(t *testing.T) { TestingT(t) }
diff --git a/plumbing/format/index/encoder_test.go b/plumbing/format/index/encoder_test.go
index 17585a0..b7a73cb 100644
--- a/plumbing/format/index/encoder_test.go
+++ b/plumbing/format/index/encoder_test.go
@@ -5,9 +5,10 @@ import (
"strings"
"time"
+ "github.com/go-git/go-git/v5/plumbing"
+
"github.com/google/go-cmp/cmp"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git/v5/plumbing"
)
func (s *IndexSuite) TestEncode(c *C) {
diff --git a/plumbing/format/objfile/common_test.go b/plumbing/format/objfile/common_test.go
index ec8c280..de76902 100644
--- a/plumbing/format/objfile/common_test.go
+++ b/plumbing/format/objfile/common_test.go
@@ -4,8 +4,9 @@ import (
"encoding/base64"
"testing"
- . "gopkg.in/check.v1"
"github.com/go-git/go-git/v5/plumbing"
+
+ . "gopkg.in/check.v1"
)
type objfileFixture struct {
diff --git a/plumbing/format/objfile/reader_test.go b/plumbing/format/objfile/reader_test.go
index 48e7f1c..d697d54 100644
--- a/plumbing/format/objfile/reader_test.go
+++ b/plumbing/format/objfile/reader_test.go
@@ -7,8 +7,9 @@ import (
"io"
"io/ioutil"
- . "gopkg.in/check.v1"
"github.com/go-git/go-git/v5/plumbing"
+
+ . "gopkg.in/check.v1"
)
type SuiteReader struct{}
diff --git a/plumbing/format/objfile/writer_test.go b/plumbing/format/objfile/writer_test.go
index 73ee662..35a9510 100644
--- a/plumbing/format/objfile/writer_test.go
+++ b/plumbing/format/objfile/writer_test.go
@@ -6,8 +6,9 @@ import (
"fmt"
"io"
- . "gopkg.in/check.v1"
"github.com/go-git/go-git/v5/plumbing"
+
+ . "gopkg.in/check.v1"
)
type SuiteWriter struct{}
diff --git a/plumbing/format/packfile/encoder_advanced_test.go b/plumbing/format/packfile/encoder_advanced_test.go
index 21bf3ae..95db5c0 100644
--- a/plumbing/format/packfile/encoder_advanced_test.go
+++ b/plumbing/format/packfile/encoder_advanced_test.go
@@ -6,7 +6,6 @@ import (
"math/rand"
"testing"
- "github.com/go-git/go-billy/v5/memfs"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/cache"
"github.com/go-git/go-git/v5/plumbing/format/idxfile"
@@ -14,8 +13,9 @@ import (
"github.com/go-git/go-git/v5/plumbing/storer"
"github.com/go-git/go-git/v5/storage/filesystem"
+ "github.com/go-git/go-billy/v5/memfs"
+ fixtures "github.com/go-git/go-git-fixtures/v4"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git-fixtures/v4"
)
type EncoderAdvancedSuite struct {
diff --git a/plumbing/format/packfile/encoder_test.go b/plumbing/format/packfile/encoder_test.go
index 2689762..d2db892 100644
--- a/plumbing/format/packfile/encoder_test.go
+++ b/plumbing/format/packfile/encoder_test.go
@@ -5,13 +5,13 @@ import (
"io"
stdioutil "io/ioutil"
- "github.com/go-git/go-billy/v5/memfs"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/format/idxfile"
"github.com/go-git/go-git/v5/storage/memory"
+ "github.com/go-git/go-billy/v5/memfs"
+ fixtures "github.com/go-git/go-git-fixtures/v4"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git-fixtures/v4"
)
type EncoderSuite struct {
diff --git a/plumbing/format/packfile/patch_delta.go b/plumbing/format/packfile/patch_delta.go
index 1dc8b8b..9e90f30 100644
--- a/plumbing/format/packfile/patch_delta.go
+++ b/plumbing/format/packfile/patch_delta.go
@@ -49,7 +49,6 @@ func ApplyDelta(target, base plumbing.EncodedObject, delta []byte) (err error) {
return err
}
-
target.SetSize(int64(dst.Len()))
b := byteSlicePool.Get().([]byte)
@@ -113,7 +112,7 @@ func patchDelta(dst *bytes.Buffer, src, delta []byte) error {
invalidOffsetSize(offset, sz, srcSz) {
break
}
- dst.Write(src[offset:offset+sz])
+ dst.Write(src[offset : offset+sz])
remainingTargetSz -= sz
} else if isCopyFromDelta(cmd) {
sz := uint(cmd) // cmd is the size itself
diff --git a/plumbing/memory.go b/plumbing/memory.go
index b8e1e1b..21337cc 100644
--- a/plumbing/memory.go
+++ b/plumbing/memory.go
@@ -3,7 +3,6 @@ package plumbing
import (
"bytes"
"io"
- "io/ioutil"
)
// MemoryObject on memory Object implementation
@@ -39,9 +38,11 @@ func (o *MemoryObject) Size() int64 { return o.sz }
// afterwards
func (o *MemoryObject) SetSize(s int64) { o.sz = s }
-// Reader returns a ObjectReader used to read the object's content.
+// Reader returns an io.ReadCloser used to read the object's content.
+//
+// For a MemoryObject, this reader is seekable.
func (o *MemoryObject) Reader() (io.ReadCloser, error) {
- return ioutil.NopCloser(bytes.NewBuffer(o.cont)), nil
+ return nopCloser{bytes.NewReader(o.cont)}, nil
}
// Writer returns a ObjectWriter used to write the object's content.
@@ -59,3 +60,13 @@ func (o *MemoryObject) Write(p []byte) (n int, err error) {
// Close releases any resources consumed by the object when it is acting as a
// ObjectWriter.
func (o *MemoryObject) Close() error { return nil }
+
+// nopCloser exposes the extra methods of bytes.Reader while nopping Close().
+//
+// This allows clients to attempt seeking in a cached Blob's Reader.
+type nopCloser struct {
+ *bytes.Reader
+}
+
+// Close does nothing.
+func (nc nopCloser) Close() error { return nil }
diff --git a/plumbing/memory_test.go b/plumbing/memory_test.go
index 879ed37..2a141f4 100644
--- a/plumbing/memory_test.go
+++ b/plumbing/memory_test.go
@@ -1,6 +1,7 @@
package plumbing
import (
+ "io"
"io/ioutil"
. "gopkg.in/check.v1"
@@ -56,6 +57,33 @@ func (s *MemoryObjectSuite) TestReader(c *C) {
c.Assert(b, DeepEquals, []byte("foo"))
}
+func (s *MemoryObjectSuite) TestSeekableReader(c *C) {
+ const pageSize = 4096
+ const payload = "foo"
+ content := make([]byte, pageSize+len(payload))
+ copy(content[pageSize:], []byte(payload))
+
+ o := &MemoryObject{cont: content}
+
+ reader, err := o.Reader()
+ c.Assert(err, IsNil)
+ defer func() { c.Assert(reader.Close(), IsNil) }()
+
+ rs, ok := reader.(io.ReadSeeker)
+ c.Assert(ok, Equals, true)
+
+ _, err = rs.Seek(pageSize, io.SeekStart)
+ c.Assert(err, IsNil)
+
+ b, err := ioutil.ReadAll(rs)
+ c.Assert(err, IsNil)
+ c.Assert(b, DeepEquals, []byte(payload))
+
+ // Check that our Reader isn't also accidentally writable
+ _, ok = reader.(io.WriteSeeker)
+ c.Assert(ok, Equals, false)
+}
+
func (s *MemoryObjectSuite) TestWriter(c *C) {
o := &MemoryObject{}
diff --git a/plumbing/object/change.go b/plumbing/object/change.go
index c9d1615..8b119bc 100644
--- a/plumbing/object/change.go
+++ b/plumbing/object/change.go
@@ -75,7 +75,7 @@ func (c *Change) Files() (from, to *File, err error) {
func (c *Change) String() string {
action, err := c.Action()
if err != nil {
- return fmt.Sprintf("malformed change")
+ return "malformed change"
}
return fmt.Sprintf("<Action: %s, Path: %s>", action, c.name())
diff --git a/plumbing/object/commit.go b/plumbing/object/commit.go
index 113cb29..98664a1 100644
--- a/plumbing/object/commit.go
+++ b/plumbing/object/commit.go
@@ -243,16 +243,16 @@ func (c *Commit) Decode(o plumbing.EncodedObject) (err error) {
}
// Encode transforms a Commit into a plumbing.EncodedObject.
-func (b *Commit) Encode(o plumbing.EncodedObject) error {
- return b.encode(o, true)
+func (c *Commit) Encode(o plumbing.EncodedObject) error {
+ return c.encode(o, true)
}
// EncodeWithoutSignature export a Commit into a plumbing.EncodedObject without the signature (correspond to the payload of the PGP signature).
-func (b *Commit) EncodeWithoutSignature(o plumbing.EncodedObject) error {
- return b.encode(o, false)
+func (c *Commit) EncodeWithoutSignature(o plumbing.EncodedObject) error {
+ return c.encode(o, false)
}
-func (b *Commit) encode(o plumbing.EncodedObject, includeSig bool) (err error) {
+func (c *Commit) encode(o plumbing.EncodedObject, includeSig bool) (err error) {
o.SetType(plumbing.CommitObject)
w, err := o.Writer()
if err != nil {
@@ -261,11 +261,11 @@ func (b *Commit) encode(o plumbing.EncodedObject, includeSig bool) (err error) {
defer ioutil.CheckClose(w, &err)
- if _, err = fmt.Fprintf(w, "tree %s\n", b.TreeHash.String()); err != nil {
+ if _, err = fmt.Fprintf(w, "tree %s\n", c.TreeHash.String()); err != nil {
return err
}
- for _, parent := range b.ParentHashes {
+ for _, parent := range c.ParentHashes {
if _, err = fmt.Fprintf(w, "parent %s\n", parent.String()); err != nil {
return err
}
@@ -275,7 +275,7 @@ func (b *Commit) encode(o plumbing.EncodedObject, includeSig bool) (err error) {
return err
}
- if err = b.Author.Encode(w); err != nil {
+ if err = c.Author.Encode(w); err != nil {
return err
}
@@ -283,11 +283,11 @@ func (b *Commit) encode(o plumbing.EncodedObject, includeSig bool) (err error) {
return err
}
- if err = b.Committer.Encode(w); err != nil {
+ if err = c.Committer.Encode(w); err != nil {
return err
}
- if b.PGPSignature != "" && includeSig {
+ if c.PGPSignature != "" && includeSig {
if _, err = fmt.Fprint(w, "\n"+headerpgp+" "); err != nil {
return err
}
@@ -296,14 +296,14 @@ func (b *Commit) encode(o plumbing.EncodedObject, includeSig bool) (err error) {
// newline. Use join for this so it's clear that a newline should not be
// added after this section, as it will be added when the message is
// printed.
- signature := strings.TrimSuffix(b.PGPSignature, "\n")
+ signature := strings.TrimSuffix(c.PGPSignature, "\n")
lines := strings.Split(signature, "\n")
if _, err = fmt.Fprint(w, strings.Join(lines, "\n ")); err != nil {
return err
}
}
- if _, err = fmt.Fprintf(w, "\n\n%s", b.Message); err != nil {
+ if _, err = fmt.Fprintf(w, "\n\n%s", c.Message); err != nil {
return err
}
diff --git a/plumbing/object/commit_stats_test.go b/plumbing/object/commit_stats_test.go
index bce2953..4078ce8 100644
--- a/plumbing/object/commit_stats_test.go
+++ b/plumbing/object/commit_stats_test.go
@@ -11,8 +11,9 @@ import (
"github.com/go-git/go-billy/v5/memfs"
"github.com/go-git/go-billy/v5/util"
+
+ fixtures "github.com/go-git/go-git-fixtures/v4"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git-fixtures/v4"
)
type CommitStatsSuite struct {
diff --git a/plumbing/object/commit_walker_bfs_filtered.go b/plumbing/object/commit_walker_bfs_filtered.go
index e87c3db..9d51813 100644
--- a/plumbing/object/commit_walker_bfs_filtered.go
+++ b/plumbing/object/commit_walker_bfs_filtered.go
@@ -173,4 +173,3 @@ func (w *filterCommitIter) addToQueue(
return nil
}
-
diff --git a/plumbing/object/commit_walker_path.go b/plumbing/object/commit_walker_path.go
index af6f745..aa0ca15 100644
--- a/plumbing/object/commit_walker_path.go
+++ b/plumbing/object/commit_walker_path.go
@@ -4,7 +4,6 @@ import (
"io"
"github.com/go-git/go-git/v5/plumbing"
-
"github.com/go-git/go-git/v5/plumbing/storer"
)
@@ -29,7 +28,7 @@ func NewCommitPathIterFromIter(pathFilter func(string) bool, commitIter CommitIt
return iterator
}
-// this function is kept for compatibilty, can be replaced with NewCommitPathIterFromIter
+// NewCommitFileIterFromIter is kept for compatibility, can be replaced with NewCommitPathIterFromIter
func NewCommitFileIterFromIter(fileName string, commitIter CommitIter, checkParent bool) CommitIter {
return NewCommitPathIterFromIter(
func(path string) bool {
diff --git a/plumbing/object/commitgraph/commitnode_test.go b/plumbing/object/commitgraph/commitnode_test.go
index 38d3bce..6c9a643 100644
--- a/plumbing/object/commitgraph/commitnode_test.go
+++ b/plumbing/object/commitgraph/commitnode_test.go
@@ -4,13 +4,14 @@ import (
"path"
"testing"
- . "gopkg.in/check.v1"
- fixtures "github.com/go-git/go-git-fixtures/v4"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/cache"
"github.com/go-git/go-git/v5/plumbing/format/commitgraph"
"github.com/go-git/go-git/v5/plumbing/format/packfile"
"github.com/go-git/go-git/v5/storage/filesystem"
+
+ fixtures "github.com/go-git/go-git-fixtures/v4"
+ . "gopkg.in/check.v1"
)
func Test(t *testing.T) { TestingT(t) }
diff --git a/plumbing/object/commitgraph/commitnode_walker_ctime.go b/plumbing/object/commitgraph/commitnode_walker_ctime.go
index f2ed663..281f10b 100644
--- a/plumbing/object/commitgraph/commitnode_walker_ctime.go
+++ b/plumbing/object/commitgraph/commitnode_walker_ctime.go
@@ -3,10 +3,10 @@ package commitgraph
import (
"io"
- "github.com/emirpasic/gods/trees/binaryheap"
-
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/storer"
+
+ "github.com/emirpasic/gods/trees/binaryheap"
)
type commitNodeIteratorByCTime struct {
diff --git a/plumbing/object/file_test.go b/plumbing/object/file_test.go
index 4dfd950..ada6654 100644
--- a/plumbing/object/file_test.go
+++ b/plumbing/object/file_test.go
@@ -9,8 +9,8 @@ import (
"github.com/go-git/go-git/v5/plumbing/storer"
"github.com/go-git/go-git/v5/storage/filesystem"
+ fixtures "github.com/go-git/go-git-fixtures/v4"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git-fixtures/v4"
)
type FileSuite struct {
diff --git a/plumbing/object/patch.go b/plumbing/object/patch.go
index 1135a40..9b5f438 100644
--- a/plumbing/object/patch.go
+++ b/plumbing/object/patch.go
@@ -121,12 +121,12 @@ type Patch struct {
filePatches []fdiff.FilePatch
}
-func (t *Patch) FilePatches() []fdiff.FilePatch {
- return t.filePatches
+func (p *Patch) FilePatches() []fdiff.FilePatch {
+ return p.filePatches
}
-func (t *Patch) Message() string {
- return t.message
+func (p *Patch) Message() string {
+ return p.message
}
func (p *Patch) Encode(w io.Writer) error {
@@ -198,12 +198,12 @@ func (tf *textFilePatch) Files() (from fdiff.File, to fdiff.File) {
return
}
-func (t *textFilePatch) IsBinary() bool {
- return len(t.chunks) == 0
+func (tf *textFilePatch) IsBinary() bool {
+ return len(tf.chunks) == 0
}
-func (t *textFilePatch) Chunks() []fdiff.Chunk {
- return t.chunks
+func (tf *textFilePatch) Chunks() []fdiff.Chunk {
+ return tf.chunks
}
// textChunk is an implementation of fdiff.Chunk interface
diff --git a/plumbing/object/patch_test.go b/plumbing/object/patch_test.go
index d4b6cd6..2cff795 100644
--- a/plumbing/object/patch_test.go
+++ b/plumbing/object/patch_test.go
@@ -1,11 +1,12 @@
package object
import (
- . "gopkg.in/check.v1"
- fixtures "github.com/go-git/go-git-fixtures/v4"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/cache"
"github.com/go-git/go-git/v5/storage/filesystem"
+
+ fixtures "github.com/go-git/go-git-fixtures/v4"
+ . "gopkg.in/check.v1"
)
type PatchSuite struct {
diff --git a/plumbing/object/rename.go b/plumbing/object/rename.go
index 35af1d6..7fed72c 100644
--- a/plumbing/object/rename.go
+++ b/plumbing/object/rename.go
@@ -536,7 +536,7 @@ var errIndexFull = errors.New("index is full")
// between two files.
// To save space in memory, this index uses a space efficient encoding which
// will not exceed 1MiB per instance. The index starts out at a smaller size
-// (closer to 2KiB), but may grow as more distinct blocks withing the scanned
+// (closer to 2KiB), but may grow as more distinct blocks within the scanned
// file are discovered.
// see: https://github.com/eclipse/jgit/blob/master/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java
type similarityIndex struct {
@@ -709,7 +709,7 @@ func (i *similarityIndex) common(dst *similarityIndex) uint64 {
}
func (i *similarityIndex) add(key int, cnt uint64) error {
- key = int(uint32(key)*0x9e370001 >> 1)
+ key = int(uint32(key) * 0x9e370001 >> 1)
j := i.slot(key)
for {
@@ -769,7 +769,7 @@ func (i *similarityIndex) slot(key int) int {
// We use 31 - hashBits because the upper bit was already forced
// to be 0 and we want the remaining high bits to be used as the
// table slot.
- return int(uint32(key) >> uint(31 - i.hashBits))
+ return int(uint32(key) >> uint(31-i.hashBits))
}
func shouldGrowAt(hashBits int) int {
diff --git a/plumbing/protocol/packp/capability/list.go b/plumbing/protocol/packp/capability/list.go
index 9609211..f41ec79 100644
--- a/plumbing/protocol/packp/capability/list.go
+++ b/plumbing/protocol/packp/capability/list.go
@@ -86,10 +86,7 @@ func (l *List) Get(capability Capability) []string {
// Set sets a capability removing the previous values
func (l *List) Set(capability Capability, values ...string) error {
- if _, ok := l.m[capability]; ok {
- delete(l.m, capability)
- }
-
+ delete(l.m, capability)
return l.Add(capability, values...)
}
diff --git a/plumbing/protocol/packp/ulreq.go b/plumbing/protocol/packp/ulreq.go
index 44db8e4..ddec06e 100644
--- a/plumbing/protocol/packp/ulreq.go
+++ b/plumbing/protocol/packp/ulreq.go
@@ -109,42 +109,42 @@ func NewUploadRequestFromCapabilities(adv *capability.List) *UploadRequest {
// - is a DepthReference is given capability.DeepenNot MUST be present
// - MUST contain only maximum of one of capability.Sideband and capability.Sideband64k
// - MUST contain only maximum of one of capability.MultiACK and capability.MultiACKDetailed
-func (r *UploadRequest) Validate() error {
- if len(r.Wants) == 0 {
+func (req *UploadRequest) Validate() error {
+ if len(req.Wants) == 0 {
return fmt.Errorf("want can't be empty")
}
- if err := r.validateRequiredCapabilities(); err != nil {
+ if err := req.validateRequiredCapabilities(); err != nil {
return err
}
- if err := r.validateConflictCapabilities(); err != nil {
+ if err := req.validateConflictCapabilities(); err != nil {
return err
}
return nil
}
-func (r *UploadRequest) validateRequiredCapabilities() error {
+func (req *UploadRequest) validateRequiredCapabilities() error {
msg := "missing capability %s"
- if len(r.Shallows) != 0 && !r.Capabilities.Supports(capability.Shallow) {
+ if len(req.Shallows) != 0 && !req.Capabilities.Supports(capability.Shallow) {
return fmt.Errorf(msg, capability.Shallow)
}
- switch r.Depth.(type) {
+ switch req.Depth.(type) {
case DepthCommits:
- if r.Depth != DepthCommits(0) {
- if !r.Capabilities.Supports(capability.Shallow) {
+ if req.Depth != DepthCommits(0) {
+ if !req.Capabilities.Supports(capability.Shallow) {
return fmt.Errorf(msg, capability.Shallow)
}
}
case DepthSince:
- if !r.Capabilities.Supports(capability.DeepenSince) {
+ if !req.Capabilities.Supports(capability.DeepenSince) {
return fmt.Errorf(msg, capability.DeepenSince)
}
case DepthReference:
- if !r.Capabilities.Supports(capability.DeepenNot) {
+ if !req.Capabilities.Supports(capability.DeepenNot) {
return fmt.Errorf(msg, capability.DeepenNot)
}
}
@@ -152,15 +152,15 @@ func (r *UploadRequest) validateRequiredCapabilities() error {
return nil
}
-func (r *UploadRequest) validateConflictCapabilities() error {
+func (req *UploadRequest) validateConflictCapabilities() error {
msg := "capabilities %s and %s are mutually exclusive"
- if r.Capabilities.Supports(capability.Sideband) &&
- r.Capabilities.Supports(capability.Sideband64k) {
+ if req.Capabilities.Supports(capability.Sideband) &&
+ req.Capabilities.Supports(capability.Sideband64k) {
return fmt.Errorf(msg, capability.Sideband, capability.Sideband64k)
}
- if r.Capabilities.Supports(capability.MultiACK) &&
- r.Capabilities.Supports(capability.MultiACKDetailed) {
+ if req.Capabilities.Supports(capability.MultiACK) &&
+ req.Capabilities.Supports(capability.MultiACKDetailed) {
return fmt.Errorf(msg, capability.MultiACK, capability.MultiACKDetailed)
}
diff --git a/plumbing/protocol/packp/ulreq_decode.go b/plumbing/protocol/packp/ulreq_decode.go
index 449b729..895a3bf 100644
--- a/plumbing/protocol/packp/ulreq_decode.go
+++ b/plumbing/protocol/packp/ulreq_decode.go
@@ -14,9 +14,9 @@ import (
// Decode reads the next upload-request form its input and
// stores it in the UploadRequest.
-func (u *UploadRequest) Decode(r io.Reader) error {
+func (req *UploadRequest) Decode(r io.Reader) error {
d := newUlReqDecoder(r)
- return d.Decode(u)
+ return d.Decode(req)
}
type ulReqDecoder struct {
diff --git a/plumbing/protocol/packp/ulreq_encode.go b/plumbing/protocol/packp/ulreq_encode.go
index 4863076..c451e23 100644
--- a/plumbing/protocol/packp/ulreq_encode.go
+++ b/plumbing/protocol/packp/ulreq_encode.go
@@ -15,9 +15,9 @@ import (
// All the payloads will end with a newline character. Wants and
// shallows are sorted alphabetically. A depth of 0 means no depth
// request is sent.
-func (u *UploadRequest) Encode(w io.Writer) error {
+func (req *UploadRequest) Encode(w io.Writer) error {
e := newUlReqEncoder(w)
- return e.Encode(u)
+ return e.Encode(req)
}
type ulReqEncoder struct {
diff --git a/plumbing/protocol/packp/updreq.go b/plumbing/protocol/packp/updreq.go
index b63b023..4d927d8 100644
--- a/plumbing/protocol/packp/updreq.go
+++ b/plumbing/protocol/packp/updreq.go
@@ -68,12 +68,12 @@ func NewReferenceUpdateRequestFromCapabilities(adv *capability.List) *ReferenceU
return r
}
-func (r *ReferenceUpdateRequest) validate() error {
- if len(r.Commands) == 0 {
+func (req *ReferenceUpdateRequest) validate() error {
+ if len(req.Commands) == 0 {
return ErrEmptyCommands
}
- for _, c := range r.Commands {
+ for _, c := range req.Commands {
if err := c.validate(); err != nil {
return err
}
diff --git a/plumbing/protocol/packp/updreq_encode.go b/plumbing/protocol/packp/updreq_encode.go
index 6a79653..2545e93 100644
--- a/plumbing/protocol/packp/updreq_encode.go
+++ b/plumbing/protocol/packp/updreq_encode.go
@@ -14,33 +14,33 @@ var (
)
// Encode writes the ReferenceUpdateRequest encoding to the stream.
-func (r *ReferenceUpdateRequest) Encode(w io.Writer) error {
- if err := r.validate(); err != nil {
+func (req *ReferenceUpdateRequest) Encode(w io.Writer) error {
+ if err := req.validate(); err != nil {
return err
}
e := pktline.NewEncoder(w)
- if err := r.encodeShallow(e, r.Shallow); err != nil {
+ if err := req.encodeShallow(e, req.Shallow); err != nil {
return err
}
- if err := r.encodeCommands(e, r.Commands, r.Capabilities); err != nil {
+ if err := req.encodeCommands(e, req.Commands, req.Capabilities); err != nil {
return err
}
- if r.Packfile != nil {
- if _, err := io.Copy(w, r.Packfile); err != nil {
+ if req.Packfile != nil {
+ if _, err := io.Copy(w, req.Packfile); err != nil {
return err
}
- return r.Packfile.Close()
+ return req.Packfile.Close()
}
return nil
}
-func (r *ReferenceUpdateRequest) encodeShallow(e *pktline.Encoder,
+func (req *ReferenceUpdateRequest) encodeShallow(e *pktline.Encoder,
h *plumbing.Hash) error {
if h == nil {
@@ -51,7 +51,7 @@ func (r *ReferenceUpdateRequest) encodeShallow(e *pktline.Encoder,
return e.Encodef("%s%s", shallow, objId)
}
-func (r *ReferenceUpdateRequest) encodeCommands(e *pktline.Encoder,
+func (req *ReferenceUpdateRequest) encodeCommands(e *pktline.Encoder,
cmds []*Command, cap *capability.List) error {
if err := e.Encodef("%s\x00%s",
diff --git a/plumbing/protocol/packp/uppackresp_test.go b/plumbing/protocol/packp/uppackresp_test.go
index 8950fa9..260dc57 100644
--- a/plumbing/protocol/packp/uppackresp_test.go
+++ b/plumbing/protocol/packp/uppackresp_test.go
@@ -4,10 +4,10 @@ import (
"bytes"
"io/ioutil"
+ "github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/protocol/packp/capability"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git/v5/plumbing"
)
type UploadPackResponseSuite struct{}
diff --git a/plumbing/storer/object_test.go b/plumbing/storer/object_test.go
index 8dc3623..30424ff 100644
--- a/plumbing/storer/object_test.go
+++ b/plumbing/storer/object_test.go
@@ -4,8 +4,9 @@ import (
"fmt"
"testing"
- . "gopkg.in/check.v1"
"github.com/go-git/go-git/v5/plumbing"
+
+ . "gopkg.in/check.v1"
)
func Test(t *testing.T) { TestingT(t) }
diff --git a/plumbing/storer/reference_test.go b/plumbing/storer/reference_test.go
index 0660043..7a4d8b4 100644
--- a/plumbing/storer/reference_test.go
+++ b/plumbing/storer/reference_test.go
@@ -4,8 +4,9 @@ import (
"errors"
"io"
- . "gopkg.in/check.v1"
"github.com/go-git/go-git/v5/plumbing"
+
+ . "gopkg.in/check.v1"
)
type ReferenceSuite struct{}
diff --git a/plumbing/transport/file/receive_pack_test.go b/plumbing/transport/file/receive_pack_test.go
index 2ee4b86..686bdcc 100644
--- a/plumbing/transport/file/receive_pack_test.go
+++ b/plumbing/transport/file/receive_pack_test.go
@@ -5,8 +5,8 @@ import (
"github.com/go-git/go-git/v5/plumbing/transport/test"
+ fixtures "github.com/go-git/go-git-fixtures/v4"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git-fixtures/v4"
)
type ReceivePackSuite struct {
diff --git a/plumbing/transport/git/common_test.go b/plumbing/transport/git/common_test.go
index 551b50d..3391aaf 100644
--- a/plumbing/transport/git/common_test.go
+++ b/plumbing/transport/git/common_test.go
@@ -13,8 +13,8 @@ import (
"github.com/go-git/go-git/v5/plumbing/transport"
+ fixtures "github.com/go-git/go-git-fixtures/v4"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git-fixtures/v4"
)
func Test(t *testing.T) { TestingT(t) }
diff --git a/plumbing/transport/git/receive_pack_test.go b/plumbing/transport/git/receive_pack_test.go
index 1f730a4..b661d71 100644
--- a/plumbing/transport/git/receive_pack_test.go
+++ b/plumbing/transport/git/receive_pack_test.go
@@ -3,8 +3,8 @@ package git
import (
"github.com/go-git/go-git/v5/plumbing/transport/test"
+ fixtures "github.com/go-git/go-git-fixtures/v4"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git-fixtures/v4"
)
type ReceivePackSuite struct {
diff --git a/plumbing/transport/git/upload_pack_test.go b/plumbing/transport/git/upload_pack_test.go
index bbfdf58..5200953 100644
--- a/plumbing/transport/git/upload_pack_test.go
+++ b/plumbing/transport/git/upload_pack_test.go
@@ -3,8 +3,8 @@ package git
import (
"github.com/go-git/go-git/v5/plumbing/transport/test"
+ fixtures "github.com/go-git/go-git-fixtures/v4"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git-fixtures/v4"
)
type UploadPackSuite struct {
diff --git a/plumbing/transport/http/common_test.go b/plumbing/transport/http/common_test.go
index 5811139..4122e62 100644
--- a/plumbing/transport/http/common_test.go
+++ b/plumbing/transport/http/common_test.go
@@ -17,8 +17,8 @@ import (
"github.com/go-git/go-git/v5/plumbing/transport"
+ fixtures "github.com/go-git/go-git-fixtures/v4"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git-fixtures/v4"
)
func Test(t *testing.T) { TestingT(t) }
diff --git a/plumbing/transport/http/receive_pack_test.go b/plumbing/transport/http/receive_pack_test.go
index b977908..7e70986 100644
--- a/plumbing/transport/http/receive_pack_test.go
+++ b/plumbing/transport/http/receive_pack_test.go
@@ -3,8 +3,8 @@ package http
import (
"github.com/go-git/go-git/v5/plumbing/transport/test"
+ fixtures "github.com/go-git/go-git-fixtures/v4"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git-fixtures/v4"
)
type ReceivePackSuite struct {
diff --git a/plumbing/transport/http/upload_pack_test.go b/plumbing/transport/http/upload_pack_test.go
index b34441d..6fae443 100644
--- a/plumbing/transport/http/upload_pack_test.go
+++ b/plumbing/transport/http/upload_pack_test.go
@@ -11,8 +11,8 @@ import (
"github.com/go-git/go-git/v5/plumbing/transport"
"github.com/go-git/go-git/v5/plumbing/transport/test"
+ fixtures "github.com/go-git/go-git-fixtures/v4"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git-fixtures/v4"
)
type UploadPackSuite struct {
diff --git a/plumbing/transport/server/receive_pack_test.go b/plumbing/transport/server/receive_pack_test.go
index 2c5b0ae..6c704bd 100644
--- a/plumbing/transport/server/receive_pack_test.go
+++ b/plumbing/transport/server/receive_pack_test.go
@@ -60,4 +60,5 @@ func (s *ReceivePackSuite) TestReceivePackWithNilPackfile(c *C) {
report, err := r.ReceivePack(context.Background(), req)
c.Assert(report, IsNil, comment)
+ c.Assert(err, NotNil, comment)
}
diff --git a/plumbing/transport/ssh/common_test.go b/plumbing/transport/ssh/common_test.go
index 22a8243..87c1148 100644
--- a/plumbing/transport/ssh/common_test.go
+++ b/plumbing/transport/ssh/common_test.go
@@ -3,12 +3,11 @@ package ssh
import (
"testing"
- "github.com/kevinburke/ssh_config"
+ "github.com/go-git/go-git/v5/plumbing/transport"
+ "github.com/kevinburke/ssh_config"
"golang.org/x/crypto/ssh"
-
. "gopkg.in/check.v1"
- "github.com/go-git/go-git/v5/plumbing/transport"
)
func Test(t *testing.T) { TestingT(t) }
diff --git a/plumbing/transport/test/upload_pack.go b/plumbing/transport/test/upload_pack.go
index ee7b067..3ee029d 100644
--- a/plumbing/transport/test/upload_pack.go
+++ b/plumbing/transport/test/upload_pack.go
@@ -13,11 +13,11 @@ import (
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/format/packfile"
"github.com/go-git/go-git/v5/plumbing/protocol/packp"
+ "github.com/go-git/go-git/v5/plumbing/protocol/packp/capability"
"github.com/go-git/go-git/v5/plumbing/transport"
"github.com/go-git/go-git/v5/storage/memory"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git/v5/plumbing/protocol/packp/capability"
)
type UploadPackSuite struct {
diff --git a/prune_test.go b/prune_test.go
index bd5168d..8c726d0 100644
--- a/prune_test.go
+++ b/prune_test.go
@@ -9,8 +9,8 @@ import (
"github.com/go-git/go-git/v5/storage"
"github.com/go-git/go-git/v5/storage/filesystem"
+ fixtures "github.com/go-git/go-git-fixtures/v4"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git-fixtures/v4"
)
type PruneSuite struct {
diff --git a/references_test.go b/references_test.go
index 7c26ce2..28d1bb9 100644
--- a/references_test.go
+++ b/references_test.go
@@ -8,8 +8,8 @@ import (
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/go-git/go-git/v5/storage/memory"
+ fixtures "github.com/go-git/go-git-fixtures/v4"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git-fixtures/v4"
)
type ReferencesSuite struct {
diff --git a/remote.go b/remote.go
index e642c57..89b3051 100644
--- a/remote.go
+++ b/remote.go
@@ -126,7 +126,7 @@ func (r *Remote) PushContext(ctx context.Context, o *PushOptions) (err error) {
if o.Force {
for i := 0; i < len(o.RefSpecs); i++ {
rs := &o.RefSpecs[i]
- if !rs.IsForceUpdate() {
+ if !rs.IsForceUpdate() && !rs.IsDelete() {
o.RefSpecs[i] = config.RefSpec("+" + rs.String())
}
}
@@ -218,9 +218,9 @@ func (r *Remote) newReferenceUpdateRequest(
if o.Progress != nil {
req.Progress = o.Progress
if ar.Capabilities.Supports(capability.Sideband64k) {
- req.Capabilities.Set(capability.Sideband64k)
+ _ = req.Capabilities.Set(capability.Sideband64k)
} else if ar.Capabilities.Supports(capability.Sideband) {
- req.Capabilities.Set(capability.Sideband)
+ _ = req.Capabilities.Set(capability.Sideband)
}
}
@@ -498,10 +498,8 @@ func (r *Remote) deleteReferences(rs config.RefSpec,
if _, ok := refsDict[rs.Dst(ref.Name()).String()]; ok {
return nil
}
- } else {
- if rs.Dst("") != ref.Name() {
- return nil
- }
+ } else if rs.Dst("") != ref.Name() {
+ return nil
}
cmd := &packp.Command{
@@ -1037,21 +1035,22 @@ func (r *Remote) List(o *ListOptions) (rfs []*plumbing.Reference, err error) {
}
var resultRefs []*plumbing.Reference
- refs.ForEach(func(ref *plumbing.Reference) error {
+ err = refs.ForEach(func(ref *plumbing.Reference) error {
resultRefs = append(resultRefs, ref)
return nil
})
-
+ if err != nil {
+ return nil, err
+ }
return resultRefs, nil
}
func objectsToPush(commands []*packp.Command) []plumbing.Hash {
- var objects []plumbing.Hash
+ objects := make([]plumbing.Hash, 0, len(commands))
for _, cmd := range commands {
if cmd.New == plumbing.ZeroHash {
continue
}
-
objects = append(objects, cmd.New)
}
return objects
diff --git a/remote_test.go b/remote_test.go
index ce46390..c6ea9ea 100644
--- a/remote_test.go
+++ b/remote_test.go
@@ -558,6 +558,31 @@ func (s *RemoteSuite) TestPushDeleteReference(c *C) {
c.Assert(err, Equals, plumbing.ErrReferenceNotFound)
}
+func (s *RemoteSuite) TestForcePushDeleteReference(c *C) {
+ fs := fixtures.Basic().One().DotGit()
+ sto := filesystem.NewStorage(fs, cache.NewObjectLRUDefault())
+
+ r, err := PlainClone(c.MkDir(), true, &CloneOptions{
+ URL: fs.Root(),
+ })
+ c.Assert(err, IsNil)
+
+ remote, err := r.Remote(DefaultRemoteName)
+ c.Assert(err, IsNil)
+
+ err = remote.Push(&PushOptions{
+ RefSpecs: []config.RefSpec{":refs/heads/branch"},
+ Force: true,
+ })
+ c.Assert(err, IsNil)
+
+ _, err = sto.Reference(plumbing.ReferenceName("refs/heads/branch"))
+ c.Assert(err, Equals, plumbing.ErrReferenceNotFound)
+
+ _, err = r.Storer.Reference(plumbing.ReferenceName("refs/heads/branch"))
+ c.Assert(err, Equals, plumbing.ErrReferenceNotFound)
+}
+
func (s *RemoteSuite) TestPushRejectNonFastForward(c *C) {
fs := fixtures.Basic().One().DotGit()
server := filesystem.NewStorage(fs, cache.NewObjectLRUDefault())
diff --git a/repository.go b/repository.go
index 1f6de76..36fc1f5 100644
--- a/repository.go
+++ b/repository.go
@@ -3,6 +3,7 @@ package git
import (
"bytes"
"context"
+ "encoding/hex"
"errors"
"fmt"
"io"
@@ -92,7 +93,7 @@ func Init(s storage.Storer, worktree billy.Filesystem) (*Repository, error) {
}
if worktree == nil {
- r.setIsBare(true)
+ _ = r.setIsBare(true)
return r, nil
}
@@ -277,6 +278,14 @@ func dotGitToOSFilesystems(path string, detect bool) (dot, wt billy.Filesystem,
if path, err = filepath.Abs(path); err != nil {
return nil, nil, err
}
+
+ pathinfo, err := os.Stat(path)
+ if !os.IsNotExist(err) {
+ if !pathinfo.IsDir() && detect {
+ path = filepath.Dir(path)
+ }
+ }
+
var fs billy.Filesystem
var fi os.FileInfo
for {
@@ -408,7 +417,7 @@ func PlainCloneContext(ctx context.Context, path string, isBare bool, o *CloneOp
err = r.clone(ctx, o)
if err != nil && err != ErrRepositoryAlreadyExists {
if cleanup {
- cleanUpDir(path, cleanupParent)
+ _ = cleanUpDir(path, cleanupParent)
}
}
@@ -1426,7 +1435,7 @@ func (r *Repository) Worktree() (*Worktree, error) {
// resolve to a commit hash, not a tree or annotated tag.
//
// Implemented resolvers : HEAD, branch, tag, heads/branch, refs/heads/branch,
-// refs/tags/tag, refs/remotes/origin/branch, refs/remotes/origin/HEAD, tilde and caret (HEAD~1, master~^, tag~2, ref/heads/master~1, ...), selection by text (HEAD^{/fix nasty bug})
+// refs/tags/tag, refs/remotes/origin/branch, refs/remotes/origin/HEAD, tilde and caret (HEAD~1, master~^, tag~2, ref/heads/master~1, ...), selection by text (HEAD^{/fix nasty bug}), hash (prefix and full)
func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, error) {
p := revision.NewParserFromString(string(rev))
@@ -1439,17 +1448,13 @@ func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, err
var commit *object.Commit
for _, item := range items {
- switch item.(type) {
+ switch item := item.(type) {
case revision.Ref:
- revisionRef := item.(revision.Ref)
+ revisionRef := item
var tryHashes []plumbing.Hash
- maybeHash := plumbing.NewHash(string(revisionRef))
-
- if !maybeHash.IsZero() {
- tryHashes = append(tryHashes, maybeHash)
- }
+ tryHashes = append(tryHashes, r.resolveHashPrefix(string(revisionRef))...)
for _, rule := range append([]string{"%s"}, plumbing.RefRevParseRules...) {
ref, err := storer.ResolveReference(r.Storer, plumbing.ReferenceName(fmt.Sprintf(rule, revisionRef)))
@@ -1494,7 +1499,7 @@ func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, err
}
case revision.CaretPath:
- depth := item.(revision.CaretPath).Depth
+ depth := item.Depth
if depth == 0 {
break
@@ -1522,7 +1527,7 @@ func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, err
commit = c
case revision.TildePath:
- for i := 0; i < item.(revision.TildePath).Depth; i++ {
+ for i := 0; i < item.Depth; i++ {
c, err := commit.Parents().Next()
if err != nil {
@@ -1534,8 +1539,8 @@ func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, err
case revision.CaretReg:
history := object.NewCommitPreorderIter(commit, nil, nil)
- re := item.(revision.CaretReg).Regexp
- negate := item.(revision.CaretReg).Negate
+ re := item.Regexp
+ negate := item.Negate
var c *object.Commit
@@ -1567,6 +1572,49 @@ func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, err
return &commit.Hash, nil
}
+// resolveHashPrefix returns a list of potential hashes that the given string
+// is a prefix of. It quietly swallows errors, returning nil.
+func (r *Repository) resolveHashPrefix(hashStr string) []plumbing.Hash {
+ // Handle complete and partial hashes.
+ // plumbing.NewHash forces args into a full 20 byte hash, which isn't suitable
+ // for partial hashes since they will become zero-filled.
+
+ if hashStr == "" {
+ return nil
+ }
+ if len(hashStr) == len(plumbing.ZeroHash)*2 {
+ // Only a full hash is possible.
+ hexb, err := hex.DecodeString(hashStr)
+ if err != nil {
+ return nil
+ }
+ var h plumbing.Hash
+ copy(h[:], hexb)
+ return []plumbing.Hash{h}
+ }
+
+ // Partial hash.
+ // hex.DecodeString only decodes to complete bytes, so only works with pairs of hex digits.
+ evenHex := hashStr[:len(hashStr)&^1]
+ hexb, err := hex.DecodeString(evenHex)
+ if err != nil {
+ return nil
+ }
+ candidates := expandPartialHash(r.Storer, hexb)
+ if len(evenHex) == len(hashStr) {
+ // The prefix was an exact number of bytes.
+ return candidates
+ }
+ // Do another prefix check to ensure the dangling nybble is correct.
+ var hashes []plumbing.Hash
+ for _, h := range candidates {
+ if strings.HasPrefix(h.String(), hashStr) {
+ hashes = append(hashes, h)
+ }
+ }
+ return hashes
+}
+
type RepackConfig struct {
// UseRefDeltas configures whether packfile encoder will use reference deltas.
// By default OFSDeltaObject is used.
@@ -1659,3 +1707,31 @@ func (r *Repository) createNewObjectPack(cfg *RepackConfig) (h plumbing.Hash, er
return h, err
}
+
+func expandPartialHash(st storer.EncodedObjectStorer, prefix []byte) (hashes []plumbing.Hash) {
+ // The fast version is implemented by storage/filesystem.ObjectStorage.
+ type fastIter interface {
+ HashesWithPrefix(prefix []byte) ([]plumbing.Hash, error)
+ }
+ if fi, ok := st.(fastIter); ok {
+ h, err := fi.HashesWithPrefix(prefix)
+ if err != nil {
+ return nil
+ }
+ return h
+ }
+
+ // Slow path.
+ iter, err := st.IterEncodedObjects(plumbing.AnyObject)
+ if err != nil {
+ return nil
+ }
+ iter.ForEach(func(obj plumbing.EncodedObject) error {
+ h := obj.Hash()
+ if bytes.HasPrefix(h[:], prefix) {
+ hashes = append(hashes, h)
+ }
+ return nil
+ })
+ return
+}
diff --git a/repository_test.go b/repository_test.go
index d1af7b6..7d4ddce 100644
--- a/repository_test.go
+++ b/repository_test.go
@@ -569,6 +569,11 @@ func (s *RepositorySuite) TestPlainOpenDetectDotGit(c *C) {
err = os.MkdirAll(subdir, 0755)
c.Assert(err, IsNil)
+ file := filepath.Join(subdir, "file.txt")
+ f, err := os.Create(file)
+ c.Assert(err, IsNil)
+ f.Close()
+
r, err := PlainInit(dir, false)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
@@ -577,6 +582,15 @@ func (s *RepositorySuite) TestPlainOpenDetectDotGit(c *C) {
r, err = PlainOpenWithOptions(subdir, opt)
c.Assert(err, IsNil)
c.Assert(r, NotNil)
+
+ r, err = PlainOpenWithOptions(file, opt)
+ c.Assert(err, IsNil)
+ c.Assert(r, NotNil)
+
+ optnodetect := &PlainOpenOptions{DetectDotGit: false}
+ r, err = PlainOpenWithOptions(file, optnodetect)
+ c.Assert(err, NotNil)
+ c.Assert(r, IsNil)
}
func (s *RepositorySuite) TestPlainOpenNotExistsDetectDotGit(c *C) {
@@ -713,7 +727,7 @@ func (s *RepositorySuite) TestPlainCloneContextNonExistentWithNotEmptyDir(c *C)
c.Assert(err, IsNil)
dummyFile := filepath.Join(repoDirPath, "dummyFile")
- err = ioutil.WriteFile(dummyFile, []byte(fmt.Sprint("dummyContent")), 0644)
+ err = ioutil.WriteFile(dummyFile, []byte("dummyContent"), 0644)
c.Assert(err, IsNil)
r, err := PlainCloneContext(ctx, repoDirPath, false, &CloneOptions{
@@ -1875,6 +1889,7 @@ func (s *RepositorySuite) TestConfigScoped(c *C) {
err := r.clone(context.Background(), &CloneOptions{
URL: s.GetBasicLocalRepositoryURL(),
})
+ c.Assert(err, IsNil)
cfg, err := r.ConfigScoped(config.LocalScope)
c.Assert(err, IsNil)
@@ -2641,6 +2656,7 @@ func (s *RepositorySuite) TestResolveRevision(c *C) {
"v1.0.0~1": "918c48b83bd081e863dbe1b80f8998f058cd8294",
"master~1": "918c48b83bd081e863dbe1b80f8998f058cd8294",
"918c48b83bd081e863dbe1b80f8998f058cd8294": "918c48b83bd081e863dbe1b80f8998f058cd8294",
+ "918c48b": "918c48b83bd081e863dbe1b80f8998f058cd8294", // odd number of hex digits
}
for rev, hash := range datas {
diff --git a/storage/filesystem/config_test.go b/storage/filesystem/config_test.go
index fe84698..c092d14 100644
--- a/storage/filesystem/config_test.go
+++ b/storage/filesystem/config_test.go
@@ -4,12 +4,12 @@ import (
"io/ioutil"
"os"
+ "github.com/go-git/go-billy/v5/osfs"
"github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/storage/filesystem/dotgit"
- "github.com/go-git/go-billy/v5/osfs"
+ fixtures "github.com/go-git/go-git-fixtures/v4"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git-fixtures/v4"
)
type ConfigSuite struct {
diff --git a/storage/filesystem/dotgit/dotgit.go b/storage/filesystem/dotgit/dotgit.go
index 3840ea7..6c386f7 100644
--- a/storage/filesystem/dotgit/dotgit.go
+++ b/storage/filesystem/dotgit/dotgit.go
@@ -3,12 +3,14 @@ package dotgit
import (
"bufio"
+ "bytes"
"errors"
"fmt"
"io"
stdioutil "io/ioutil"
"os"
"path/filepath"
+ "sort"
"strings"
"time"
@@ -88,7 +90,7 @@ type DotGit struct {
incomingChecked bool
incomingDirName string
- objectList []plumbing.Hash
+ objectList []plumbing.Hash // sorted
objectMap map[plumbing.Hash]struct{}
packList []plumbing.Hash
packMap map[plumbing.Hash]struct{}
@@ -336,6 +338,53 @@ func (d *DotGit) NewObject() (*ObjectWriter, error) {
return newObjectWriter(d.fs)
}
+// ObjectsWithPrefix returns the hashes of objects that have the given prefix.
+func (d *DotGit) ObjectsWithPrefix(prefix []byte) ([]plumbing.Hash, error) {
+ // Handle edge cases.
+ if len(prefix) < 1 {
+ return d.Objects()
+ } else if len(prefix) > len(plumbing.ZeroHash) {
+ return nil, nil
+ }
+
+ if d.options.ExclusiveAccess {
+ err := d.genObjectList()
+ if err != nil {
+ return nil, err
+ }
+
+ // Rely on d.objectList being sorted.
+ // Figure out the half-open interval defined by the prefix.
+ first := sort.Search(len(d.objectList), func(i int) bool {
+ // Same as plumbing.HashSlice.Less.
+ return bytes.Compare(d.objectList[i][:], prefix) >= 0
+ })
+ lim := len(d.objectList)
+ if limPrefix, overflow := incBytes(prefix); !overflow {
+ lim = sort.Search(len(d.objectList), func(i int) bool {
+ // Same as plumbing.HashSlice.Less.
+ return bytes.Compare(d.objectList[i][:], limPrefix) >= 0
+ })
+ }
+ return d.objectList[first:lim], nil
+ }
+
+ // This is the slow path.
+ var objects []plumbing.Hash
+ var n int
+ err := d.ForEachObjectHash(func(hash plumbing.Hash) error {
+ n++
+ if bytes.HasPrefix(hash[:], prefix) {
+ objects = append(objects, hash)
+ }
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+ return objects, nil
+}
+
// Objects returns a slice with the hashes of objects found under the
// .git/objects/ directory.
func (d *DotGit) Objects() ([]plumbing.Hash, error) {
@@ -427,12 +476,17 @@ func (d *DotGit) genObjectList() error {
}
d.objectMap = make(map[plumbing.Hash]struct{})
- return d.forEachObjectHash(func(h plumbing.Hash) error {
+ populate := func(h plumbing.Hash) error {
d.objectList = append(d.objectList, h)
d.objectMap[h] = struct{}{}
return nil
- })
+ }
+ if err := d.forEachObjectHash(populate); err != nil {
+ return err
+ }
+ plumbing.HashesSort(d.objectList)
+ return nil
}
func (d *DotGit) hasObject(h plumbing.Hash) error {
@@ -1115,3 +1169,20 @@ func isNum(b byte) bool {
func isHexAlpha(b byte) bool {
return b >= 'a' && b <= 'f' || b >= 'A' && b <= 'F'
}
+
+// incBytes increments a byte slice, which involves incrementing the
+// right-most byte, and following carry leftward.
+// It makes a copy so that the provided slice's underlying array is not modified.
+// If the overall operation overflows (e.g. incBytes(0xff, 0xff)), the second return parameter indicates that.
+func incBytes(in []byte) (out []byte, overflow bool) {
+ out = make([]byte, len(in))
+ copy(out, in)
+ for i := len(out) - 1; i >= 0; i-- {
+ out[i]++
+ if out[i] != 0 {
+ return // Didn't overflow.
+ }
+ }
+ overflow = true
+ return
+}
diff --git a/storage/filesystem/dotgit/dotgit_test.go b/storage/filesystem/dotgit/dotgit_test.go
index 0a72aa6..237605f 100644
--- a/storage/filesystem/dotgit/dotgit_test.go
+++ b/storage/filesystem/dotgit/dotgit_test.go
@@ -2,6 +2,7 @@ package dotgit
import (
"bufio"
+ "encoding/hex"
"io/ioutil"
"os"
"path/filepath"
@@ -591,6 +592,7 @@ func (s *SuiteDotGit) TestObjects(c *C) {
dir := New(fs)
testObjects(c, fs, dir)
+ testObjectsWithPrefix(c, fs, dir)
}
func (s *SuiteDotGit) TestObjectsExclusive(c *C) {
@@ -598,6 +600,7 @@ func (s *SuiteDotGit) TestObjectsExclusive(c *C) {
dir := NewWithOptions(fs, Options{ExclusiveAccess: true})
testObjects(c, fs, dir)
+ testObjectsWithPrefix(c, fs, dir)
}
func testObjects(c *C, fs billy.Filesystem, dir *DotGit) {
@@ -609,6 +612,20 @@ func testObjects(c *C, fs billy.Filesystem, dir *DotGit) {
c.Assert(hashes[2].String(), Equals, "03db8e1fbe133a480f2867aac478fd866686d69e")
}
+func testObjectsWithPrefix(c *C, fs billy.Filesystem, dir *DotGit) {
+ prefix, _ := hex.DecodeString("01d5")
+ hashes, err := dir.ObjectsWithPrefix(prefix)
+ c.Assert(err, IsNil)
+ c.Assert(hashes, HasLen, 1)
+ c.Assert(hashes[0].String(), Equals, "01d5fa556c33743006de7e76e67a2dfcd994ca04")
+
+ // Empty prefix should yield all objects.
+ // (subset of testObjects)
+ hashes, err = dir.ObjectsWithPrefix(nil)
+ c.Assert(err, IsNil)
+ c.Assert(hashes, HasLen, 187)
+}
+
func (s *SuiteDotGit) TestObjectsNoFolder(c *C) {
tmp, err := ioutil.TempDir("", "dot-git")
c.Assert(err, IsNil)
@@ -835,3 +852,21 @@ type norwfs struct {
func (f *norwfs) Capabilities() billy.Capability {
return billy.Capabilities(f.Filesystem) &^ billy.ReadAndWriteCapability
}
+
+func (s *SuiteDotGit) TestIncBytes(c *C) {
+ tests := []struct {
+ in []byte
+ out []byte
+ overflow bool
+ }{
+ {[]byte{0}, []byte{1}, false},
+ {[]byte{0xff}, []byte{0}, true},
+ {[]byte{7, 0xff}, []byte{8, 0}, false},
+ {[]byte{0xff, 0xff}, []byte{0, 0}, true},
+ }
+ for _, test := range tests {
+ out, overflow := incBytes(test.in)
+ c.Assert(out, DeepEquals, test.out)
+ c.Assert(overflow, Equals, test.overflow)
+ }
+}
diff --git a/storage/filesystem/dotgit/writers_test.go b/storage/filesystem/dotgit/writers_test.go
index 246d310..7147aec 100644
--- a/storage/filesystem/dotgit/writers_test.go
+++ b/storage/filesystem/dotgit/writers_test.go
@@ -13,8 +13,8 @@ import (
"github.com/go-git/go-git/v5/plumbing/format/packfile"
"github.com/go-git/go-billy/v5/osfs"
+ fixtures "github.com/go-git/go-git-fixtures/v4"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git-fixtures/v4"
)
func (s *SuiteDotGit) TestNewObjectPack(c *C) {
diff --git a/storage/filesystem/object.go b/storage/filesystem/object.go
index 7437174..0c25dad 100644
--- a/storage/filesystem/object.go
+++ b/storage/filesystem/object.go
@@ -1,6 +1,7 @@
package filesystem
import (
+ "bytes"
"io"
"os"
"time"
@@ -518,6 +519,36 @@ func (s *ObjectStorage) findObjectInPackfile(h plumbing.Hash) (plumbing.Hash, pl
return plumbing.ZeroHash, plumbing.ZeroHash, -1
}
+func (s *ObjectStorage) HashesWithPrefix(prefix []byte) ([]plumbing.Hash, error) {
+ hashes, err := s.dir.ObjectsWithPrefix(prefix)
+ if err != nil {
+ return nil, err
+ }
+
+ // TODO: This could be faster with some idxfile changes,
+ // or diving into the packfile.
+ for _, index := range s.index {
+ ei, err := index.Entries()
+ if err != nil {
+ return nil, err
+ }
+ for {
+ e, err := ei.Next()
+ if err == io.EOF {
+ break
+ } else if err != nil {
+ return nil, err
+ }
+ if bytes.HasPrefix(e.Hash[:], prefix) {
+ hashes = append(hashes, e.Hash)
+ }
+ }
+ ei.Close()
+ }
+
+ return hashes, nil
+}
+
// IterEncodedObjects returns an iterator for all the objects in the packfile
// with the given type.
func (s *ObjectStorage) IterEncodedObjects(t plumbing.ObjectType) (storer.EncodedObjectIter, error) {
diff --git a/storage/filesystem/object_test.go b/storage/filesystem/object_test.go
index 2d6f568..036420f 100644
--- a/storage/filesystem/object_test.go
+++ b/storage/filesystem/object_test.go
@@ -1,6 +1,7 @@
package filesystem
import (
+ "encoding/hex"
"fmt"
"io"
"io/ioutil"
@@ -332,6 +333,22 @@ func (s *FsSuite) TestGetFromObjectFileSharedCache(c *C) {
c.Assert(err, Equals, plumbing.ErrObjectNotFound)
}
+func (s *FsSuite) TestHashesWithPrefix(c *C) {
+ // Same setup as TestGetFromObjectFile.
+ fs := fixtures.ByTag(".git").ByTag("unpacked").One().DotGit()
+ o := NewObjectStorage(dotgit.New(fs), cache.NewObjectLRUDefault())
+ expected := plumbing.NewHash("f3dfe29d268303fc6e1bbce268605fc99573406e")
+ obj, err := o.EncodedObject(plumbing.AnyObject, expected)
+ c.Assert(err, IsNil)
+ c.Assert(obj.Hash(), Equals, expected)
+
+ prefix, _ := hex.DecodeString("f3dfe2")
+ hashes, err := o.HashesWithPrefix(prefix)
+ c.Assert(err, IsNil)
+ c.Assert(hashes, HasLen, 1)
+ c.Assert(hashes[0].String(), Equals, "f3dfe29d268303fc6e1bbce268605fc99573406e")
+}
+
func BenchmarkPackfileIter(b *testing.B) {
defer fixtures.Clean()
diff --git a/storage/memory/storage.go b/storage/memory/storage.go
index fdf8fcf..a8e5669 100644
--- a/storage/memory/storage.go
+++ b/storage/memory/storage.go
@@ -195,10 +195,10 @@ func (o *ObjectStorage) DeleteOldObjectPackAndIndex(plumbing.Hash, time.Time) er
var errNotSupported = fmt.Errorf("Not supported")
-func (s *ObjectStorage) LooseObjectTime(hash plumbing.Hash) (time.Time, error) {
+func (o *ObjectStorage) LooseObjectTime(hash plumbing.Hash) (time.Time, error) {
return time.Time{}, errNotSupported
}
-func (s *ObjectStorage) DeleteLooseObject(plumbing.Hash) error {
+func (o *ObjectStorage) DeleteLooseObject(plumbing.Hash) error {
return errNotSupported
}
diff --git a/storage/transactional/config_test.go b/storage/transactional/config_test.go
index ec7ae89..1f3a572 100644
--- a/storage/transactional/config_test.go
+++ b/storage/transactional/config_test.go
@@ -1,9 +1,10 @@
package transactional
import (
- . "gopkg.in/check.v1"
"github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/storage/memory"
+
+ . "gopkg.in/check.v1"
)
var _ = Suite(&ConfigSuite{})
diff --git a/storage/transactional/index_test.go b/storage/transactional/index_test.go
index 88fa1f5..0028c0e 100644
--- a/storage/transactional/index_test.go
+++ b/storage/transactional/index_test.go
@@ -1,9 +1,10 @@
package transactional
import (
- . "gopkg.in/check.v1"
"github.com/go-git/go-git/v5/plumbing/format/index"
"github.com/go-git/go-git/v5/storage/memory"
+
+ . "gopkg.in/check.v1"
)
var _ = Suite(&IndexSuite{})
diff --git a/storage/transactional/object_test.go b/storage/transactional/object_test.go
index e634409..df277c4 100644
--- a/storage/transactional/object_test.go
+++ b/storage/transactional/object_test.go
@@ -1,9 +1,10 @@
package transactional
import (
- . "gopkg.in/check.v1"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/storage/memory"
+
+ . "gopkg.in/check.v1"
)
var _ = Suite(&ObjectSuite{})
diff --git a/storage/transactional/reference.go b/storage/transactional/reference.go
index c3a727c..3b009e2 100644
--- a/storage/transactional/reference.go
+++ b/storage/transactional/reference.go
@@ -27,7 +27,7 @@ func NewReferenceStorage(base, temporal storer.ReferenceStorer) *ReferenceStorag
ReferenceStorer: base,
temporal: temporal,
- deleted: make(map[plumbing.ReferenceName]struct{}, 0),
+ deleted: make(map[plumbing.ReferenceName]struct{}),
}
}
diff --git a/storage/transactional/reference_test.go b/storage/transactional/reference_test.go
index a6bd1ce..05a4fcf 100644
--- a/storage/transactional/reference_test.go
+++ b/storage/transactional/reference_test.go
@@ -1,9 +1,10 @@
package transactional
import (
- . "gopkg.in/check.v1"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/storage/memory"
+
+ . "gopkg.in/check.v1"
)
var _ = Suite(&ReferenceSuite{})
diff --git a/storage/transactional/shallow_test.go b/storage/transactional/shallow_test.go
index 1209fe6..15d423c 100644
--- a/storage/transactional/shallow_test.go
+++ b/storage/transactional/shallow_test.go
@@ -1,9 +1,10 @@
package transactional
import (
- . "gopkg.in/check.v1"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/storage/memory"
+
+ . "gopkg.in/check.v1"
)
var _ = Suite(&ShallowSuite{})
diff --git a/submodule_test.go b/submodule_test.go
index 3d81965..418b3ee 100644
--- a/submodule_test.go
+++ b/submodule_test.go
@@ -9,8 +9,8 @@ import (
"github.com/go-git/go-git/v5/plumbing"
+ fixtures "github.com/go-git/go-git-fixtures/v4"
. "gopkg.in/check.v1"
- "github.com/go-git/go-git-fixtures/v4"
)
type SubmoduleSuite struct {
diff --git a/utils/binary/read_test.go b/utils/binary/read_test.go
index 3749258..bcd9dee 100644
--- a/utils/binary/read_test.go
+++ b/utils/binary/read_test.go
@@ -6,8 +6,9 @@ import (
"encoding/binary"
"testing"
- . "gopkg.in/check.v1"
"github.com/go-git/go-git/v5/plumbing"
+
+ . "gopkg.in/check.v1"
)
func Test(t *testing.T) { TestingT(t) }
diff --git a/utils/diff/diff.go b/utils/diff/diff.go
index 6142ed0..7005494 100644
--- a/utils/diff/diff.go
+++ b/utils/diff/diff.go
@@ -29,7 +29,7 @@ func Do(src, dst string) (diffs []diffmatchpatch.Diff) {
// a bulk delete+insert and the half-baked suboptimal result is returned at once.
// The underlying algorithm is Meyers, its complexity is O(N*d) where N is
// min(lines(src), lines(dst)) and d is the size of the diff.
-func DoWithTimeout (src, dst string, timeout time.Duration) (diffs []diffmatchpatch.Diff) {
+func DoWithTimeout(src, dst string, timeout time.Duration) (diffs []diffmatchpatch.Diff) {
dmp := diffmatchpatch.New()
dmp.DiffTimeout = timeout
wSrc, wDst, warray := dmp.DiffLinesToRunes(src, dst)
diff --git a/utils/merkletrie/filesystem/node.go b/utils/merkletrie/filesystem/node.go
index 165bd42..2fc3d7a 100644
--- a/utils/merkletrie/filesystem/node.go
+++ b/utils/merkletrie/filesystem/node.go
@@ -91,8 +91,7 @@ func (n *node) calculateChildren() error {
if os.IsNotExist(err) {
return nil
}
-
- return nil
+ return err
}
for _, file := range files {
diff --git a/utils/merkletrie/filesystem/node_test.go b/utils/merkletrie/filesystem/node_test.go
index 0f6ebe0..159e63d 100644
--- a/utils/merkletrie/filesystem/node_test.go
+++ b/utils/merkletrie/filesystem/node_test.go
@@ -7,12 +7,13 @@ import (
"path"
"testing"
- "github.com/go-git/go-billy/v5"
- "github.com/go-git/go-billy/v5/memfs"
- . "gopkg.in/check.v1"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/utils/merkletrie"
"github.com/go-git/go-git/v5/utils/merkletrie/noder"
+
+ "github.com/go-git/go-billy/v5"
+ "github.com/go-git/go-billy/v5/memfs"
+ . "gopkg.in/check.v1"
)
func Test(t *testing.T) { TestingT(t) }
diff --git a/utils/merkletrie/index/node_test.go b/utils/merkletrie/index/node_test.go
index 4fa6c63..cc5600d 100644
--- a/utils/merkletrie/index/node_test.go
+++ b/utils/merkletrie/index/node_test.go
@@ -5,11 +5,12 @@ import (
"path/filepath"
"testing"
- . "gopkg.in/check.v1"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/format/index"
"github.com/go-git/go-git/v5/utils/merkletrie"
"github.com/go-git/go-git/v5/utils/merkletrie/noder"
+
+ . "gopkg.in/check.v1"
)
func Test(t *testing.T) { TestingT(t) }
diff --git a/worktree.go b/worktree.go
index d272373..62ad03b 100644
--- a/worktree.go
+++ b/worktree.go
@@ -93,7 +93,7 @@ func (w *Worktree) PullContext(ctx context.Context, o *PullOptions) error {
head, err := w.r.Head()
if err == nil {
- headAheadOfRef,err := isFastForward(w.r.Storer, ref.Hash(), head.Hash())
+ headAheadOfRef, err := isFastForward(w.r.Storer, ref.Hash(), head.Hash())
if err != nil {
return err
}
@@ -102,7 +102,6 @@ func (w *Worktree) PullContext(ctx context.Context, o *PullOptions) error {
return NoErrAlreadyUpToDate
}
-
ff, err := isFastForward(w.r.Storer, head.Hash(), ref.Hash())
if err != nil {
return err
diff --git a/worktree_commit.go b/worktree_commit.go
index 63eb2e8..a9d0e04 100644
--- a/worktree_commit.go
+++ b/worktree_commit.go
@@ -6,7 +6,6 @@ import (
"sort"
"strings"
- "golang.org/x/crypto/openpgp"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/filemode"
"github.com/go-git/go-git/v5/plumbing/format/index"
@@ -14,6 +13,7 @@ import (
"github.com/go-git/go-git/v5/storage"
"github.com/go-git/go-billy/v5"
+ "golang.org/x/crypto/openpgp"
)
// Commit stores the current contents of the index in a new commit along with
@@ -58,17 +58,23 @@ func (w *Worktree) autoAddModifiedAndDeleted() error {
return err
}
+ idx, err := w.r.Storer.Index()
+ if err != nil {
+ return err
+ }
+
for path, fs := range s {
if fs.Worktree != Modified && fs.Worktree != Deleted {
continue
}
- if _, err := w.Add(path); err != nil {
+ if _, _, err := w.doAddFile(idx, s, path, nil); err != nil {
return err
}
+
}
- return nil
+ return w.r.Storer.SetIndex(idx)
}
func (w *Worktree) updateHEAD(commit plumbing.Hash) error {