aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--_examples/README.md1
-rw-r--r--_examples/tag-create-push/main.go148
-rw-r--r--blame_test.go2
-rw-r--r--config/branch_test.go3
-rw-r--r--config/config_test.go37
-rw-r--r--go.mod2
-rw-r--r--go.sum2
-rw-r--r--internal/revision/parser_test.go16
-rw-r--r--options.go64
-rw-r--r--options_test.go84
-rw-r--r--plumbing/format/commitgraph/commitgraph_test.go5
-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.go4
-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/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/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--repository.go49
-rw-r--r--repository_test.go11
-rw-r--r--storage/filesystem/config_test.go4
-rw-r--r--storage/filesystem/dotgit/dotgit.go6
-rw-r--r--storage/filesystem/dotgit/repository_filesystem.go111
-rw-r--r--storage/filesystem/dotgit/repository_filesystem_test.go124
-rw-r--r--storage/filesystem/dotgit/writers_test.go2
-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_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.go7
-rw-r--r--worktree_commit.go2
-rw-r--r--worktree_status.go120
-rw-r--r--worktree_test.go143
76 files changed, 1003 insertions, 181 deletions
diff --git a/_examples/README.md b/_examples/README.md
index 1d82fbd..80d4dd5 100644
--- a/_examples/README.md
+++ b/_examples/README.md
@@ -17,6 +17,7 @@ Here you can find a list of annotated _go-git_ examples:
- [log](log/main.go) - Emulate `git log` command output iterating all the commit history from HEAD reference.
- [branch](branch/main.go) - How to create and remove branches or any other kind of reference.
- [tag](tag/main.go) - List/print repository tags.
+- [tag create and push](tag-create-push/main.go) - Create and push a new tag.
- [remotes](remotes/main.go) - Working with remotes: adding, removing, etc.
- [progress](progress/main.go) - Printing the progress information from the sideband.
- [revision](revision/main.go) - Solve a revision into a commit.
diff --git a/_examples/tag-create-push/main.go b/_examples/tag-create-push/main.go
new file mode 100644
index 0000000..c443641
--- /dev/null
+++ b/_examples/tag-create-push/main.go
@@ -0,0 +1,148 @@
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+
+ "github.com/go-git/go-git/v5"
+ . "github.com/go-git/go-git/v5/_examples"
+ "github.com/go-git/go-git/v5/config"
+ "github.com/go-git/go-git/v5/plumbing/object"
+ "github.com/go-git/go-git/v5/plumbing/transport/ssh"
+)
+
+// Example of how create a tag and push it to a remote.
+func main() {
+ CheckArgs("<ssh-url>", "<directory>", "<tag>", "<name>", "<email>", "<public-key>")
+ url := os.Args[1]
+ directory := os.Args[2]
+ tag := os.Args[3]
+ key := os.Args[6]
+
+ r, err := cloneRepo(url, directory, key)
+
+ if err != nil {
+ log.Printf("clone repo error: %s", err)
+ return
+ }
+
+ created, err := setTag(r, tag)
+ if err != nil {
+ log.Printf("create tag error: %s", err)
+ return
+ }
+
+ if created {
+ err = pushTags(r, key)
+ if err != nil {
+ log.Printf("push tag error: %s", err)
+ return
+ }
+ }
+}
+
+func cloneRepo(url, dir, publicKeyPath string) (*git.Repository, error) {
+ log.Printf("cloning %s into %s", url, dir)
+ auth, keyErr := publicKey(publicKeyPath)
+ if keyErr != nil {
+ return nil, keyErr
+ }
+
+ Info("git clone %s", url)
+ r, err := git.PlainClone(dir, false, &git.CloneOptions{
+ Progress: os.Stdout,
+ URL: url,
+ Auth: auth,
+ })
+
+ if err != nil {
+ log.Printf("clone git repo error: %s", err)
+ return nil, err
+ }
+
+ return r, nil
+}
+
+func publicKey(filePath string) (*ssh.PublicKeys, error) {
+ var publicKey *ssh.PublicKeys
+ sshKey, _ := ioutil.ReadFile(filePath)
+ publicKey, err := ssh.NewPublicKeys("git", []byte(sshKey), "")
+ if err != nil {
+ return nil, err
+ }
+ return publicKey, err
+}
+
+func tagExists(tag string, r *git.Repository) bool {
+ tagFoundErr := "tag was found"
+ Info("git show-ref --tag")
+ tags, err := r.TagObjects()
+ if err != nil {
+ log.Printf("get tags error: %s", err)
+ return false
+ }
+ res := false
+ err = tags.ForEach(func(t *object.Tag) error {
+ if t.Name == tag {
+ res = true
+ return fmt.Errorf(tagFoundErr)
+ }
+ return nil
+ })
+ if err != nil && err.Error() != tagFoundErr {
+ log.Printf("iterate tags error: %s", err)
+ return false
+ }
+ return res
+}
+
+func setTag(r *git.Repository, tag string) (bool, error) {
+ if tagExists(tag, r) {
+ log.Printf("tag %s already exists", tag)
+ return false, nil
+ }
+ log.Printf("Set tag %s", tag)
+ h, err := r.Head()
+ if err != nil {
+ log.Printf("get HEAD error: %s", err)
+ return false, err
+ }
+ Info("git tag -a %s %s -m \"%s\"", tag, h.Hash(), tag)
+ _, err = r.CreateTag(tag, h.Hash(), &git.CreateTagOptions{
+ Message: tag,
+ })
+
+ if err != nil {
+ log.Printf("create tag error: %s", err)
+ return false, err
+ }
+
+ return true, nil
+}
+
+func pushTags(r *git.Repository, publicKeyPath string) error {
+
+ auth, _ := publicKey(publicKeyPath)
+
+ po := &git.PushOptions{
+ RemoteName: "origin",
+ Progress: os.Stdout,
+ RefSpecs: []config.RefSpec{config.RefSpec("refs/tags/*:refs/tags/*")},
+ Auth: auth,
+ }
+ Info("git push --tags")
+ err := r.Push(po)
+
+ if err != nil {
+ if err == git.NoErrAlreadyUpToDate {
+ log.Print("origin remote was up to date, no push done")
+ return nil
+ }
+ log.Printf("push to remote origin error: %s", err)
+ return err
+ }
+
+ return nil
+}
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/config/config_test.go b/config/config_test.go
index e68626b..5a88c19 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -1,6 +1,10 @@
package config
import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
"github.com/go-git/go-git/v5/plumbing"
. "gopkg.in/check.v1"
)
@@ -172,8 +176,39 @@ func (s *ConfigSuite) TestUnmarshalMarshal(c *C) {
func (s *ConfigSuite) TestLoadConfig(c *C) {
cfg, err := LoadConfig(GlobalScope)
- c.Assert(err, IsNil)
c.Assert(cfg.User.Email, Not(Equals), "")
+ c.Assert(err, IsNil)
+
+}
+
+func (s *ConfigSuite) TestLoadConfigXDG(c *C) {
+ cfg := NewConfig()
+ cfg.User.Name = "foo"
+ cfg.User.Email = "foo@foo.com"
+
+ tmp, err := ioutil.TempDir("", "test-commit-options")
+ c.Assert(err, IsNil)
+ defer os.RemoveAll(tmp)
+
+ err = os.Mkdir(filepath.Join(tmp, "git"), 0777)
+ c.Assert(err, IsNil)
+
+ os.Setenv("XDG_CONFIG_HOME", tmp)
+ defer func() {
+ os.Setenv("XDG_CONFIG_HOME", "")
+ }()
+
+ content, err := cfg.Marshal()
+ c.Assert(err, IsNil)
+
+ cfgFile := filepath.Join(tmp, "git/config")
+ err = ioutil.WriteFile(cfgFile, content, 0777)
+ c.Assert(err, IsNil)
+
+ cfg, err = LoadConfig(GlobalScope)
+ c.Assert(err, IsNil)
+
+ c.Assert(cfg.User.Email, Equals, "foo@foo.com")
}
func (s *ConfigSuite) TestValidateConfig(c *C) {
diff --git a/go.mod b/go.mod
index 0c9cfd2..81bbaa8 100644
--- a/go.mod
+++ b/go.mod
@@ -8,7 +8,7 @@ require (
github.com/gliderlabs/ssh v0.2.2
github.com/go-git/gcfg v1.5.0
github.com/go-git/go-billy/v5 v5.0.0
- github.com/go-git/go-git-fixtures/v4 v4.0.1
+ github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12
github.com/google/go-cmp v0.3.0
github.com/imdario/mergo v0.3.9
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99
diff --git a/go.sum b/go.sum
index e14e29a..9af1b06 100644
--- a/go.sum
+++ b/go.sum
@@ -20,6 +20,8 @@ github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agR
github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
github.com/go-git/go-git-fixtures/v4 v4.0.1 h1:q+IFMfLx200Q3scvt2hN79JsEzy4AmBTp/pqnefH+Bc=
github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
+github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbKy9zOy4aAKrJ5pibIRpVO2BXnK1Tlcg+caKI7Ox5M=
+github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
diff --git a/internal/revision/parser_test.go b/internal/revision/parser_test.go
index fe45228..4bb007f 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},
}
diff --git a/options.go b/options.go
index 5367031..2f93631 100644
--- a/options.go
+++ b/options.go
@@ -2,6 +2,7 @@ package git
import (
"errors"
+ "fmt"
"regexp"
"strings"
"time"
@@ -373,6 +374,30 @@ var (
ErrMissingAuthor = errors.New("author field is required")
)
+// AddOptions describes how a add operation should be performed
+type AddOptions struct {
+ // All equivalent to `git add -A`, update the index not only where the
+ // working tree has a file matching `Path` but also where the index already
+ // has an entry. This adds, modifies, and removes index entries to match the
+ // working tree. If no `Path` nor `Glob` is given when `All` option is
+ // used, all files in the entire working tree are updated.
+ All bool
+ // Path is the exact filepath to a the file or directory to be added.
+ Path string
+ // Glob adds all paths, matching pattern, to the index. If pattern matches a
+ // directory path, all directory contents are added to the index recursively.
+ Glob string
+}
+
+// Validate validates the fields and sets the default values.
+func (o *AddOptions) Validate(r *Repository) error {
+ if o.Path != "" && o.Glob != "" {
+ return fmt.Errorf("fields Path and Glob are mutual exclusive")
+ }
+
+ return nil
+}
+
// CommitOptions describes how a commit operation should be performed.
type CommitOptions struct {
// All automatically stage files that have been modified and deleted, but
@@ -464,7 +489,8 @@ var (
// CreateTagOptions describes how a tag object should be created.
type CreateTagOptions struct {
- // Tagger defines the signature of the tag creator.
+ // Tagger defines the signature of the tag creator. If Tagger is empty the
+ // Name and Email is read from the config, and time.Now it's used as When.
Tagger *object.Signature
// Message defines the annotation of the tag. It is canonicalized during
// validation into the format expected by git - no leading whitespace and
@@ -478,7 +504,9 @@ type CreateTagOptions struct {
// Validate validates the fields and sets the default values.
func (o *CreateTagOptions) Validate(r *Repository, hash plumbing.Hash) error {
if o.Tagger == nil {
- return ErrMissingTagger
+ if err := o.loadConfigTagger(r); err != nil {
+ return err
+ }
}
if o.Message == "" {
@@ -491,6 +519,35 @@ func (o *CreateTagOptions) Validate(r *Repository, hash plumbing.Hash) error {
return nil
}
+func (o *CreateTagOptions) loadConfigTagger(r *Repository) error {
+ cfg, err := r.ConfigScoped(config.SystemScope)
+ if err != nil {
+ return err
+ }
+
+ if o.Tagger == nil && cfg.Author.Email != "" && cfg.Author.Name != "" {
+ o.Tagger = &object.Signature{
+ Name: cfg.Author.Name,
+ Email: cfg.Author.Email,
+ When: time.Now(),
+ }
+ }
+
+ if o.Tagger == nil && cfg.User.Email != "" && cfg.User.Name != "" {
+ o.Tagger = &object.Signature{
+ Name: cfg.User.Name,
+ Email: cfg.User.Email,
+ When: time.Now(),
+ }
+ }
+
+ if o.Tagger == nil {
+ return ErrMissingTagger
+ }
+
+ return nil
+}
+
// ListOptions describes how a remote list should be performed.
type ListOptions struct {
// Auth credentials, if required, to use with the remote repository.
@@ -545,6 +602,9 @@ type PlainOpenOptions struct {
// DetectDotGit defines whether parent directories should be
// walked until a .git directory or file is found.
DetectDotGit bool
+ // Enable .git/commondir support (see https://git-scm.com/docs/gitrepository-layout#Documentation/gitrepository-layout.txt).
+ // NOTE: This option will only work with the filesystem storage.
+ EnableDotGitCommonDir bool
}
// Validate validates the fields and sets the default values.
diff --git a/options_test.go b/options_test.go
index aa36dab..86d725a 100644
--- a/options_test.go
+++ b/options_test.go
@@ -1,6 +1,12 @@
package git
import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
+ "github.com/go-git/go-git/v5/config"
+ "github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
. "gopkg.in/check.v1"
)
@@ -27,3 +33,81 @@ func (s *OptionsSuite) TestCommitOptionsCommitter(c *C) {
c.Assert(o.Committer, Equals, o.Author)
}
+
+func (s *OptionsSuite) TestCommitOptionsLoadGlobalConfigUser(c *C) {
+ cfg := config.NewConfig()
+ cfg.User.Name = "foo"
+ cfg.User.Email = "foo@foo.com"
+
+ s.writeGlobalConfig(c, cfg)
+ defer s.clearGlobalConfig(c)
+
+ o := CommitOptions{}
+ err := o.Validate(s.Repository)
+ c.Assert(err, IsNil)
+
+ c.Assert(o.Author.Name, Equals, "foo")
+ c.Assert(o.Author.Email, Equals, "foo@foo.com")
+ c.Assert(o.Committer.Name, Equals, "foo")
+ c.Assert(o.Committer.Email, Equals, "foo@foo.com")
+}
+
+func (s *OptionsSuite) TestCommitOptionsLoadGlobalCommitter(c *C) {
+ cfg := config.NewConfig()
+ cfg.User.Name = "foo"
+ cfg.User.Email = "foo@foo.com"
+ cfg.Committer.Name = "bar"
+ cfg.Committer.Email = "bar@bar.com"
+
+ s.writeGlobalConfig(c, cfg)
+ defer s.clearGlobalConfig(c)
+
+ o := CommitOptions{}
+ err := o.Validate(s.Repository)
+ c.Assert(err, IsNil)
+
+ c.Assert(o.Author.Name, Equals, "foo")
+ c.Assert(o.Author.Email, Equals, "foo@foo.com")
+ c.Assert(o.Committer.Name, Equals, "bar")
+ c.Assert(o.Committer.Email, Equals, "bar@bar.com")
+}
+
+func (s *OptionsSuite) TestCreateTagOptionsLoadGlobal(c *C) {
+ cfg := config.NewConfig()
+ cfg.User.Name = "foo"
+ cfg.User.Email = "foo@foo.com"
+
+ s.writeGlobalConfig(c, cfg)
+ defer s.clearGlobalConfig(c)
+
+ o := CreateTagOptions{
+ Message: "foo",
+ }
+
+ err := o.Validate(s.Repository, plumbing.ZeroHash)
+ c.Assert(err, IsNil)
+
+ c.Assert(o.Tagger.Name, Equals, "foo")
+ c.Assert(o.Tagger.Email, Equals, "foo@foo.com")
+}
+
+func (s *OptionsSuite) writeGlobalConfig(c *C, cfg *config.Config) {
+ tmp, err := ioutil.TempDir("", "test-options")
+ c.Assert(err, IsNil)
+
+ err = os.Mkdir(filepath.Join(tmp, "git"), 0777)
+ c.Assert(err, IsNil)
+
+ os.Setenv("XDG_CONFIG_HOME", tmp)
+
+ content, err := cfg.Marshal()
+ c.Assert(err, IsNil)
+
+ cfgFile := filepath.Join(tmp, "git/config")
+ err = ioutil.WriteFile(cfgFile, content, 0777)
+ c.Assert(err, IsNil)
+}
+
+func (s *OptionsSuite) clearGlobalConfig(c *C) {
+ os.Setenv("XDG_CONFIG_HOME", "")
+}
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/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..d341d59 100644
--- a/plumbing/format/index/decoder.go
+++ b/plumbing/format/index/decoder.go
@@ -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/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/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/repository.go b/repository.go
index 47318d1..1f6de76 100644
--- a/repository.go
+++ b/repository.go
@@ -13,6 +13,8 @@ import (
"strings"
"time"
+ "github.com/go-git/go-git/v5/storage/filesystem/dotgit"
+
"github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/internal/revision"
"github.com/go-git/go-git/v5/plumbing"
@@ -47,6 +49,7 @@ var (
ErrInvalidReference = errors.New("invalid reference, should be a tag or a branch")
ErrRepositoryNotExists = errors.New("repository does not exist")
+ ErrRepositoryIncomplete = errors.New("repository's commondir path does not exist")
ErrRepositoryAlreadyExists = errors.New("repository already exists")
ErrRemoteNotFound = errors.New("remote not found")
ErrRemoteExists = errors.New("remote already exists")
@@ -253,7 +256,19 @@ func PlainOpenWithOptions(path string, o *PlainOpenOptions) (*Repository, error)
return nil, err
}
- s := filesystem.NewStorage(dot, cache.NewObjectLRUDefault())
+ var repositoryFs billy.Filesystem
+
+ if o.EnableDotGitCommonDir {
+ dotGitCommon, err := dotGitCommonDirectory(dot)
+ if err != nil {
+ return nil, err
+ }
+ repositoryFs = dotgit.NewRepositoryFilesystem(dot, dotGitCommon)
+ } else {
+ repositoryFs = dot
+ }
+
+ s := filesystem.NewStorage(repositoryFs, cache.NewObjectLRUDefault())
return Open(s, wt)
}
@@ -328,6 +343,38 @@ func dotGitFileToOSFilesystem(path string, fs billy.Filesystem) (bfs billy.Files
return osfs.New(fs.Join(path, gitdir)), nil
}
+func dotGitCommonDirectory(fs billy.Filesystem) (commonDir billy.Filesystem, err error) {
+ f, err := fs.Open("commondir")
+ if os.IsNotExist(err) {
+ return nil, nil
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ b, err := stdioutil.ReadAll(f)
+ if err != nil {
+ return nil, err
+ }
+ if len(b) > 0 {
+ path := strings.TrimSpace(string(b))
+ if filepath.IsAbs(path) {
+ commonDir = osfs.New(path)
+ } else {
+ commonDir = osfs.New(filepath.Join(fs.Root(), path))
+ }
+ if _, err := commonDir.Stat(""); err != nil {
+ if os.IsNotExist(err) {
+ return nil, ErrRepositoryIncomplete
+ }
+
+ return nil, err
+ }
+ }
+
+ return commonDir, nil
+}
+
// PlainClone a repository into the path with the given options, isBare defines
// if the new repository will be bare or normal. If the path is not empty
// ErrRepositoryAlreadyExists is returned.
diff --git a/repository_test.go b/repository_test.go
index 37cd914..bbed604 100644
--- a/repository_test.go
+++ b/repository_test.go
@@ -1875,6 +1875,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)
@@ -2103,15 +2104,7 @@ func (s *RepositorySuite) TestCreateTagAnnotatedBadOpts(c *C) {
expectedHash := h.Hash()
- ref, err := r.CreateTag("foobar", expectedHash, &CreateTagOptions{
- Message: "foo bar baz qux",
- })
- c.Assert(ref, IsNil)
- c.Assert(err, Equals, ErrMissingTagger)
-
- ref, err = r.CreateTag("foobar", expectedHash, &CreateTagOptions{
- Tagger: defaultSignature(),
- })
+ ref, err := r.CreateTag("foobar", expectedHash, &CreateTagOptions{})
c.Assert(ref, IsNil)
c.Assert(err, Equals, ErrMissingMessage)
}
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 83c7683..3840ea7 100644
--- a/storage/filesystem/dotgit/dotgit.go
+++ b/storage/filesystem/dotgit/dotgit.go
@@ -30,6 +30,12 @@ const (
objectsPath = "objects"
packPath = "pack"
refsPath = "refs"
+ branchesPath = "branches"
+ hooksPath = "hooks"
+ infoPath = "info"
+ remotesPath = "remotes"
+ logsPath = "logs"
+ worktreesPath = "worktrees"
tmpPackedRefsPrefix = "._packed-refs"
diff --git a/storage/filesystem/dotgit/repository_filesystem.go b/storage/filesystem/dotgit/repository_filesystem.go
new file mode 100644
index 0000000..8d243ef
--- /dev/null
+++ b/storage/filesystem/dotgit/repository_filesystem.go
@@ -0,0 +1,111 @@
+package dotgit
+
+import (
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/go-git/go-billy/v5"
+)
+
+// RepositoryFilesystem is a billy.Filesystem compatible object wrapper
+// which handles dot-git filesystem operations and supports commondir according to git scm layout:
+// https://github.com/git/git/blob/master/Documentation/gitrepository-layout.txt
+type RepositoryFilesystem struct {
+ dotGitFs billy.Filesystem
+ commonDotGitFs billy.Filesystem
+}
+
+func NewRepositoryFilesystem(dotGitFs, commonDotGitFs billy.Filesystem) *RepositoryFilesystem {
+ return &RepositoryFilesystem{
+ dotGitFs: dotGitFs,
+ commonDotGitFs: commonDotGitFs,
+ }
+}
+
+func (fs *RepositoryFilesystem) mapToRepositoryFsByPath(path string) billy.Filesystem {
+ // Nothing to decide if commondir not defined
+ if fs.commonDotGitFs == nil {
+ return fs.dotGitFs
+ }
+
+ cleanPath := filepath.Clean(path)
+
+ // Check exceptions for commondir (https://git-scm.com/docs/gitrepository-layout#Documentation/gitrepository-layout.txt)
+ switch cleanPath {
+ case fs.dotGitFs.Join(logsPath, "HEAD"):
+ return fs.dotGitFs
+ case fs.dotGitFs.Join(refsPath, "bisect"), fs.dotGitFs.Join(refsPath, "rewritten"), fs.dotGitFs.Join(refsPath, "worktree"):
+ return fs.dotGitFs
+ }
+
+ // Determine dot-git root by first path element.
+ // There are some elements which should always use commondir when commondir defined.
+ // Usual dot-git root will be used for the rest of files.
+ switch strings.Split(cleanPath, string(filepath.Separator))[0] {
+ case objectsPath, refsPath, packedRefsPath, configPath, branchesPath, hooksPath, infoPath, remotesPath, logsPath, shallowPath, worktreesPath:
+ return fs.commonDotGitFs
+ default:
+ return fs.dotGitFs
+ }
+}
+
+func (fs *RepositoryFilesystem) Create(filename string) (billy.File, error) {
+ return fs.mapToRepositoryFsByPath(filename).Create(filename)
+}
+
+func (fs *RepositoryFilesystem) Open(filename string) (billy.File, error) {
+ return fs.mapToRepositoryFsByPath(filename).Open(filename)
+}
+
+func (fs *RepositoryFilesystem) OpenFile(filename string, flag int, perm os.FileMode) (billy.File, error) {
+ return fs.mapToRepositoryFsByPath(filename).OpenFile(filename, flag, perm)
+}
+
+func (fs *RepositoryFilesystem) Stat(filename string) (os.FileInfo, error) {
+ return fs.mapToRepositoryFsByPath(filename).Stat(filename)
+}
+
+func (fs *RepositoryFilesystem) Rename(oldpath, newpath string) error {
+ return fs.mapToRepositoryFsByPath(oldpath).Rename(oldpath, newpath)
+}
+
+func (fs *RepositoryFilesystem) Remove(filename string) error {
+ return fs.mapToRepositoryFsByPath(filename).Remove(filename)
+}
+
+func (fs *RepositoryFilesystem) Join(elem ...string) string {
+ return fs.dotGitFs.Join(elem...)
+}
+
+func (fs *RepositoryFilesystem) TempFile(dir, prefix string) (billy.File, error) {
+ return fs.mapToRepositoryFsByPath(dir).TempFile(dir, prefix)
+}
+
+func (fs *RepositoryFilesystem) ReadDir(path string) ([]os.FileInfo, error) {
+ return fs.mapToRepositoryFsByPath(path).ReadDir(path)
+}
+
+func (fs *RepositoryFilesystem) MkdirAll(filename string, perm os.FileMode) error {
+ return fs.mapToRepositoryFsByPath(filename).MkdirAll(filename, perm)
+}
+
+func (fs *RepositoryFilesystem) Lstat(filename string) (os.FileInfo, error) {
+ return fs.mapToRepositoryFsByPath(filename).Lstat(filename)
+}
+
+func (fs *RepositoryFilesystem) Symlink(target, link string) error {
+ return fs.mapToRepositoryFsByPath(target).Symlink(target, link)
+}
+
+func (fs *RepositoryFilesystem) Readlink(link string) (string, error) {
+ return fs.mapToRepositoryFsByPath(link).Readlink(link)
+}
+
+func (fs *RepositoryFilesystem) Chroot(path string) (billy.Filesystem, error) {
+ return fs.mapToRepositoryFsByPath(path).Chroot(path)
+}
+
+func (fs *RepositoryFilesystem) Root() string {
+ return fs.dotGitFs.Root()
+}
diff --git a/storage/filesystem/dotgit/repository_filesystem_test.go b/storage/filesystem/dotgit/repository_filesystem_test.go
new file mode 100644
index 0000000..880ec0d
--- /dev/null
+++ b/storage/filesystem/dotgit/repository_filesystem_test.go
@@ -0,0 +1,124 @@
+package dotgit
+
+import (
+ "io/ioutil"
+ "log"
+ "os"
+
+ "github.com/go-git/go-billy/v5/osfs"
+
+ . "gopkg.in/check.v1"
+)
+
+func (s *SuiteDotGit) TestRepositoryFilesystem(c *C) {
+ dir, err := ioutil.TempDir("", "repository_filesystem")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+
+ fs := osfs.New(dir)
+
+ err = fs.MkdirAll("dotGit", 0777)
+ c.Assert(err, IsNil)
+ dotGitFs, err := fs.Chroot("dotGit")
+ c.Assert(err, IsNil)
+
+ err = fs.MkdirAll("commonDotGit", 0777)
+ c.Assert(err, IsNil)
+ commonDotGitFs, err := fs.Chroot("commonDotGit")
+ c.Assert(err, IsNil)
+
+ repositoryFs := NewRepositoryFilesystem(dotGitFs, commonDotGitFs)
+ c.Assert(repositoryFs.Root(), Equals, dotGitFs.Root())
+
+ somedir, err := repositoryFs.Chroot("somedir")
+ c.Assert(err, IsNil)
+ c.Assert(somedir.Root(), Equals, repositoryFs.Join(dotGitFs.Root(), "somedir"))
+
+ _, err = repositoryFs.Create("somefile")
+ c.Assert(err, IsNil)
+
+ _, err = repositoryFs.Stat("somefile")
+ c.Assert(err, IsNil)
+
+ file, err := repositoryFs.Open("somefile")
+ c.Assert(err, IsNil)
+ err = file.Close()
+ c.Assert(err, IsNil)
+
+ file, err = repositoryFs.OpenFile("somefile", os.O_RDONLY, 0666)
+ c.Assert(err, IsNil)
+ err = file.Close()
+ c.Assert(err, IsNil)
+
+ file, err = repositoryFs.Create("somefile2")
+ c.Assert(err, IsNil)
+ err = file.Close()
+ c.Assert(err, IsNil)
+ _, err = repositoryFs.Stat("somefile2")
+ c.Assert(err, IsNil)
+ err = repositoryFs.Rename("somefile2", "newfile")
+ c.Assert(err, IsNil)
+
+ tempDir, err := repositoryFs.TempFile("tmp", "myprefix")
+ c.Assert(err, IsNil)
+ c.Assert(repositoryFs.Join(repositoryFs.Root(), "tmp", tempDir.Name()), Equals, repositoryFs.Join(dotGitFs.Root(), "tmp", tempDir.Name()))
+
+ err = repositoryFs.Symlink("newfile", "somelink")
+ c.Assert(err, IsNil)
+
+ _, err = repositoryFs.Lstat("somelink")
+ c.Assert(err, IsNil)
+
+ link, err := repositoryFs.Readlink("somelink")
+ c.Assert(err, IsNil)
+ c.Assert(link, Equals, "newfile")
+
+ err = repositoryFs.Remove("somelink")
+ c.Assert(err, IsNil)
+
+ _, err = repositoryFs.Stat("somelink")
+ c.Assert(os.IsNotExist(err), Equals, true)
+
+ dirs := []string{objectsPath, refsPath, packedRefsPath, configPath, branchesPath, hooksPath, infoPath, remotesPath, logsPath, shallowPath, worktreesPath}
+ for _, dir := range dirs {
+ err := repositoryFs.MkdirAll(dir, 0777)
+ c.Assert(err, IsNil)
+ _, err = commonDotGitFs.Stat(dir)
+ c.Assert(err, IsNil)
+ _, err = dotGitFs.Stat(dir)
+ c.Assert(os.IsNotExist(err), Equals, true)
+ }
+
+ exceptionsPaths := []string{repositoryFs.Join(logsPath, "HEAD"), repositoryFs.Join(refsPath, "bisect"), repositoryFs.Join(refsPath, "rewritten"), repositoryFs.Join(refsPath, "worktree")}
+ for _, path := range exceptionsPaths {
+ _, err := repositoryFs.Create(path)
+ c.Assert(err, IsNil)
+ _, err = commonDotGitFs.Stat(path)
+ c.Assert(os.IsNotExist(err), Equals, true)
+ _, err = dotGitFs.Stat(path)
+ c.Assert(err, IsNil)
+ }
+
+ err = repositoryFs.MkdirAll("refs/heads", 0777)
+ c.Assert(err, IsNil)
+ _, err = commonDotGitFs.Stat("refs/heads")
+ c.Assert(err, IsNil)
+ _, err = dotGitFs.Stat("refs/heads")
+ c.Assert(os.IsNotExist(err), Equals, true)
+
+ err = repositoryFs.MkdirAll("objects/pack", 0777)
+ c.Assert(err, IsNil)
+ _, err = commonDotGitFs.Stat("objects/pack")
+ c.Assert(err, IsNil)
+ _, err = dotGitFs.Stat("objects/pack")
+ c.Assert(os.IsNotExist(err), Equals, true)
+
+ err = repositoryFs.MkdirAll("a/b/c", 0777)
+ c.Assert(err, IsNil)
+ _, err = commonDotGitFs.Stat("a/b/c")
+ c.Assert(os.IsNotExist(err), Equals, true)
+ _, err = dotGitFs.Stat("a/b/c")
+ c.Assert(err, IsNil)
+}
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/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_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 7f394d4..62ad03b 100644
--- a/worktree.go
+++ b/worktree.go
@@ -93,7 +93,12 @@ func (w *Worktree) PullContext(ctx context.Context, o *PullOptions) error {
head, err := w.r.Head()
if err == nil {
- if !updated && head.Hash() == ref.Hash() {
+ headAheadOfRef, err := isFastForward(w.r.Storer, ref.Hash(), head.Hash())
+ if err != nil {
+ return err
+ }
+
+ if !updated && headAheadOfRef {
return NoErrAlreadyUpToDate
}
diff --git a/worktree_commit.go b/worktree_commit.go
index 63eb2e8..167f2e0 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
diff --git a/worktree_status.go b/worktree_status.go
index 1542f5e..c639f13 100644
--- a/worktree_status.go
+++ b/worktree_status.go
@@ -7,6 +7,7 @@ import (
"os"
"path"
"path/filepath"
+ "strings"
"github.com/go-git/go-billy/v5/util"
"github.com/go-git/go-git/v5/plumbing"
@@ -264,43 +265,23 @@ func diffTreeIsEquals(a, b noder.Hasher) bool {
// the worktree to the index. If any of the files is already staged in the index
// no error is returned. When path is a file, the blob.Hash is returned.
func (w *Worktree) Add(path string) (plumbing.Hash, error) {
- // TODO(mcuadros): remove plumbing.Hash from signature at v5.
- s, err := w.Status()
- if err != nil {
- return plumbing.ZeroHash, err
- }
-
- idx, err := w.r.Storer.Index()
- if err != nil {
- return plumbing.ZeroHash, err
- }
-
- var h plumbing.Hash
- var added bool
-
- fi, err := w.Filesystem.Lstat(path)
- if err != nil || !fi.IsDir() {
- added, h, err = w.doAddFile(idx, s, path)
- } else {
- added, err = w.doAddDirectory(idx, s, path)
- }
-
- if err != nil {
- return h, err
- }
-
- if !added {
- return h, nil
- }
-
- return h, w.r.Storer.SetIndex(idx)
+ // TODO(mcuadros): deprecate in favor of AddWithOption in v6.
+ return w.doAdd(path, make([]gitignore.Pattern, 0))
}
-func (w *Worktree) doAddDirectory(idx *index.Index, s Status, directory string) (added bool, err error) {
+func (w *Worktree) doAddDirectory(idx *index.Index, s Status, directory string, ignorePattern []gitignore.Pattern) (added bool, err error) {
files, err := w.Filesystem.ReadDir(directory)
if err != nil {
return false, err
}
+ if len(ignorePattern) > 0 {
+ m := gitignore.NewMatcher(ignorePattern)
+ matchPath := strings.Split(directory, string(os.PathSeparator))
+ if m.Match(matchPath, true) {
+ // ignore
+ return false, nil
+ }
+ }
for _, file := range files {
name := path.Join(directory, file.Name())
@@ -311,9 +292,9 @@ func (w *Worktree) doAddDirectory(idx *index.Index, s Status, directory string)
// ignore special git directory
continue
}
- a, err = w.doAddDirectory(idx, s, name)
+ a, err = w.doAddDirectory(idx, s, name, ignorePattern)
} else {
- a, _, err = w.doAddFile(idx, s, name)
+ a, _, err = w.doAddFile(idx, s, name, ignorePattern)
}
if err != nil {
@@ -328,10 +309,69 @@ func (w *Worktree) doAddDirectory(idx *index.Index, s Status, directory string)
return
}
+// AddWithOptions file contents to the index, updates the index using the
+// current content found in the working tree, to prepare the content staged for
+// the next commit.
+//
+// It typically adds the current content of existing paths as a whole, but with
+// some options it can also be used to add content with only part of the changes
+// made to the working tree files applied, or remove paths that do not exist in
+// the working tree anymore.
+func (w *Worktree) AddWithOptions(opts *AddOptions) error {
+ if err := opts.Validate(w.r); err != nil {
+ return err
+ }
+
+ if opts.All {
+ _, err := w.doAdd(".", w.Excludes)
+ return err
+ }
+
+ if opts.Glob != "" {
+ return w.AddGlob(opts.Glob)
+ }
+
+ _, err := w.Add(opts.Path)
+ return err
+}
+
+func (w *Worktree) doAdd(path string, ignorePattern []gitignore.Pattern) (plumbing.Hash, error) {
+ s, err := w.Status()
+ if err != nil {
+ return plumbing.ZeroHash, err
+ }
+
+ idx, err := w.r.Storer.Index()
+ if err != nil {
+ return plumbing.ZeroHash, err
+ }
+
+ var h plumbing.Hash
+ var added bool
+
+ fi, err := w.Filesystem.Lstat(path)
+ if err != nil || !fi.IsDir() {
+ added, h, err = w.doAddFile(idx, s, path, ignorePattern)
+ } else {
+ added, err = w.doAddDirectory(idx, s, path, ignorePattern)
+ }
+
+ if err != nil {
+ return h, err
+ }
+
+ if !added {
+ return h, nil
+ }
+
+ return h, w.r.Storer.SetIndex(idx)
+}
+
// AddGlob adds all paths, matching pattern, to the index. If pattern matches a
// directory path, all directory contents are added to the index recursively. No
// error is returned if all matching paths are already staged in index.
func (w *Worktree) AddGlob(pattern string) error {
+ // TODO(mcuadros): deprecate in favor of AddWithOption in v6.
files, err := util.Glob(w.Filesystem, pattern)
if err != nil {
return err
@@ -360,9 +400,9 @@ func (w *Worktree) AddGlob(pattern string) error {
var added bool
if fi.IsDir() {
- added, err = w.doAddDirectory(idx, s, file)
+ added, err = w.doAddDirectory(idx, s, file, make([]gitignore.Pattern, 0))
} else {
- added, _, err = w.doAddFile(idx, s, file)
+ added, _, err = w.doAddFile(idx, s, file, make([]gitignore.Pattern, 0))
}
if err != nil {
@@ -383,10 +423,18 @@ func (w *Worktree) AddGlob(pattern string) error {
// doAddFile create a new blob from path and update the index, added is true if
// the file added is different from the index.
-func (w *Worktree) doAddFile(idx *index.Index, s Status, path string) (added bool, h plumbing.Hash, err error) {
+func (w *Worktree) doAddFile(idx *index.Index, s Status, path string, ignorePattern []gitignore.Pattern) (added bool, h plumbing.Hash, err error) {
if s.File(path).Worktree == Unmodified {
return false, h, nil
}
+ if len(ignorePattern) > 0 {
+ m := gitignore.NewMatcher(ignorePattern)
+ matchPath := strings.Split(path, string(os.PathSeparator))
+ if m.Match(matchPath, true) {
+ // ignore
+ return false, h, nil
+ }
+ }
h, err = w.copyFileToStorage(path)
if err != nil {
diff --git a/worktree_test.go b/worktree_test.go
index 24a65eb..59c80af 100644
--- a/worktree_test.go
+++ b/worktree_test.go
@@ -265,6 +265,26 @@ func (s *RepositorySuite) TestPullAdd(c *C) {
c.Assert(branch.Hash().String(), Not(Equals), "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
}
+func (s *WorktreeSuite) TestPullAlreadyUptodate(c *C) {
+ path := fixtures.Basic().ByTag("worktree").One().Worktree().Root()
+
+ r, err := Clone(memory.NewStorage(), memfs.New(), &CloneOptions{
+ URL: filepath.Join(path, ".git"),
+ })
+
+ c.Assert(err, IsNil)
+
+ w, err := r.Worktree()
+ c.Assert(err, IsNil)
+ err = ioutil.WriteFile(filepath.Join(path, "bar"), []byte("bar"), 0755)
+ c.Assert(err, IsNil)
+ _, err = w.Commit("bar", &CommitOptions{Author: defaultSignature()})
+ c.Assert(err, IsNil)
+
+ err = w.Pull(&PullOptions{})
+ c.Assert(err, Equals, NoErrAlreadyUpToDate)
+}
+
func (s *WorktreeSuite) TestCheckout(c *C) {
fs := memfs.New()
w := &Worktree{
@@ -1370,6 +1390,52 @@ func (s *WorktreeSuite) TestAddDirectoryErrorNotFound(c *C) {
c.Assert(h.IsZero(), Equals, true)
}
+func (s *WorktreeSuite) TestAddAll(c *C) {
+ fs := memfs.New()
+ w := &Worktree{
+ r: s.Repository,
+ Filesystem: fs,
+ }
+
+ err := w.Checkout(&CheckoutOptions{Force: true})
+ c.Assert(err, IsNil)
+
+ idx, err := w.r.Storer.Index()
+ c.Assert(err, IsNil)
+ c.Assert(idx.Entries, HasLen, 9)
+
+ err = util.WriteFile(w.Filesystem, "file1", []byte("file1"), 0644)
+ c.Assert(err, IsNil)
+
+ err = util.WriteFile(w.Filesystem, "file2", []byte("file2"), 0644)
+ c.Assert(err, IsNil)
+
+ err = util.WriteFile(w.Filesystem, "file3", []byte("ignore me"), 0644)
+ c.Assert(err, IsNil)
+
+ w.Excludes = make([]gitignore.Pattern, 0)
+ w.Excludes = append(w.Excludes, gitignore.ParsePattern("file3", nil))
+
+ err = w.AddWithOptions(&AddOptions{All: true})
+ c.Assert(err, IsNil)
+
+ idx, err = w.r.Storer.Index()
+ c.Assert(err, IsNil)
+ c.Assert(idx.Entries, HasLen, 11)
+
+ status, err := w.Status()
+ c.Assert(err, IsNil)
+ c.Assert(status, HasLen, 2)
+
+ file1 := status.File("file1")
+ c.Assert(file1.Staging, Equals, Added)
+ file2 := status.File("file2")
+ c.Assert(file2.Staging, Equals, Added)
+ file3 := status.File("file3")
+ c.Assert(file3.Staging, Equals, Untracked)
+ c.Assert(file3.Worktree, Equals, Untracked)
+}
+
func (s *WorktreeSuite) TestAddGlob(c *C) {
fs := memfs.New()
w := &Worktree{
@@ -1391,7 +1457,7 @@ func (s *WorktreeSuite) TestAddGlob(c *C) {
err = util.WriteFile(w.Filesystem, "qux/bar/baz", []byte("BAZ"), 0755)
c.Assert(err, IsNil)
- err = w.AddGlob(w.Filesystem.Join("qux", "b*"))
+ err = w.AddWithOptions(&AddOptions{Glob: w.Filesystem.Join("qux", "b*")})
c.Assert(err, IsNil)
idx, err = w.r.Storer.Index()
@@ -2006,3 +2072,78 @@ func (s *WorktreeSuite) TestAddAndCommit(c *C) {
})
c.Assert(err, IsNil)
}
+
+func (s *WorktreeSuite) TestLinkedWorktree(c *C) {
+ fs := fixtures.ByTag("linked-worktree").One().Worktree()
+
+ // Open main repo.
+ {
+ fs, err := fs.Chroot("main")
+ c.Assert(err, IsNil)
+ repo, err := PlainOpenWithOptions(fs.Root(), &PlainOpenOptions{EnableDotGitCommonDir: true})
+ c.Assert(err, IsNil)
+
+ wt, err := repo.Worktree()
+ c.Assert(err, IsNil)
+
+ status, err := wt.Status()
+ c.Assert(err, IsNil)
+ c.Assert(len(status), Equals, 2) // 2 files
+
+ head, err := repo.Head()
+ c.Assert(err, IsNil)
+ c.Assert(string(head.Name()), Equals, "refs/heads/master")
+ }
+
+ // Open linked-worktree #1.
+ {
+ fs, err := fs.Chroot("linked-worktree-1")
+ c.Assert(err, IsNil)
+ repo, err := PlainOpenWithOptions(fs.Root(), &PlainOpenOptions{EnableDotGitCommonDir: true})
+ c.Assert(err, IsNil)
+
+ wt, err := repo.Worktree()
+ c.Assert(err, IsNil)
+
+ status, err := wt.Status()
+ c.Assert(err, IsNil)
+ c.Assert(len(status), Equals, 3) // 3 files
+
+ _, ok := status["linked-worktree-1-unique-file.txt"]
+ c.Assert(ok, Equals, true)
+
+ head, err := repo.Head()
+ c.Assert(err, IsNil)
+ c.Assert(string(head.Name()), Equals, "refs/heads/linked-worktree-1")
+ }
+
+ // Open linked-worktree #2.
+ {
+ fs, err := fs.Chroot("linked-worktree-2")
+ c.Assert(err, IsNil)
+ repo, err := PlainOpenWithOptions(fs.Root(), &PlainOpenOptions{EnableDotGitCommonDir: true})
+ c.Assert(err, IsNil)
+
+ wt, err := repo.Worktree()
+ c.Assert(err, IsNil)
+
+ status, err := wt.Status()
+ c.Assert(err, IsNil)
+ c.Assert(len(status), Equals, 3) // 3 files
+
+ _, ok := status["linked-worktree-2-unique-file.txt"]
+ c.Assert(ok, Equals, true)
+
+ head, err := repo.Head()
+ c.Assert(err, IsNil)
+ c.Assert(string(head.Name()), Equals, "refs/heads/branch-with-different-name")
+ }
+
+ // Open linked-worktree #2.
+ {
+ fs, err := fs.Chroot("linked-worktree-invalid-commondir")
+ c.Assert(err, IsNil)
+ _, err = PlainOpenWithOptions(fs.Root(), &PlainOpenOptions{EnableDotGitCommonDir: true})
+ c.Assert(err, Equals, ErrRepositoryIncomplete)
+ }
+}