aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--_examples/remotes/main.go2
-rw-r--r--config/config.go51
-rw-r--r--config/config_test.go29
-rw-r--r--example_test.go2
-rw-r--r--plumbing/format/config/decoder_test.go5
-rw-r--r--plumbing/format/config/fixtures_test.go14
-rw-r--r--plumbing/format/config/option.go51
-rw-r--r--plumbing/format/config/section.go27
-rw-r--r--plumbing/format/config/section_test.go19
-rw-r--r--plumbing/reference.go40
-rw-r--r--plumbing/reference_test.go8
-rw-r--r--plumbing/transport/file/receive_pack_test.go2
-rw-r--r--plumbing/transport/test/receive_pack.go1
-rw-r--r--remote.go15
-rw-r--r--remote_test.go57
-rw-r--r--repository.go41
-rw-r--r--repository_test.go54
-rw-r--r--storage/filesystem/config_test.go6
-rw-r--r--storage/test/storage_suite.go2
-rw-r--r--submodule.go2
-rw-r--r--utils/merkletrie/noder/path.go8
-rw-r--r--utils/merkletrie/noder/path_test.go12
-rw-r--r--worktree.go6
-rw-r--r--worktree_test.go66
24 files changed, 376 insertions, 144 deletions
diff --git a/_examples/remotes/main.go b/_examples/remotes/main.go
index 90817dc..7cae8bb 100644
--- a/_examples/remotes/main.go
+++ b/_examples/remotes/main.go
@@ -27,7 +27,7 @@ func main() {
Info("git remote add example https://github.com/git-fixtures/basic.git")
_, err = r.CreateRemote(&config.RemoteConfig{
Name: "example",
- URL: "https://github.com/git-fixtures/basic.git",
+ URLs: []string{"https://github.com/git-fixtures/basic.git"},
})
CheckIfError(err)
diff --git a/config/config.go b/config/config.go
index bcea63e..cb10738 100644
--- a/config/config.go
+++ b/config/config.go
@@ -159,13 +159,22 @@ func (c *Config) marshalCore() {
func (c *Config) marshalRemotes() {
s := c.Raw.Section(remoteSection)
- s.Subsections = make(format.Subsections, len(c.Remotes))
+ newSubsections := make(format.Subsections, 0, len(c.Remotes))
+ added := make(map[string]bool)
+ for _, subsection := range s.Subsections {
+ if remote, ok := c.Remotes[subsection.Name]; ok {
+ newSubsections = append(newSubsections, remote.marshal())
+ added[subsection.Name] = true
+ }
+ }
- var i int
- for _, r := range c.Remotes {
- s.Subsections[i] = r.marshal()
- i++
+ for name, remote := range c.Remotes {
+ if !added[name] {
+ newSubsections = append(newSubsections, remote.marshal())
+ }
}
+
+ s.Subsections = newSubsections
}
func (c *Config) marshalSubmodules() {
@@ -187,8 +196,9 @@ func (c *Config) marshalSubmodules() {
type RemoteConfig struct {
// Name of the remote
Name string
- // URL the URL of a remote repository
- URL string
+ // URLs the URLs of a remote repository. It must be non-empty. Fetch will
+ // always use the first URL, while push will use all of them.
+ URLs []string
// Fetch the default set of "refspec" for fetch operation
Fetch []RefSpec
@@ -203,7 +213,7 @@ func (c *RemoteConfig) Validate() error {
return ErrRemoteConfigEmptyName
}
- if c.URL == "" {
+ if len(c.URLs) == 0 {
return ErrRemoteConfigEmptyURL
}
@@ -233,8 +243,13 @@ func (c *RemoteConfig) unmarshal(s *format.Subsection) error {
fetch = append(fetch, rs)
}
+ var urls []string
+ for _, f := range c.raw.Options.GetAll(urlKey) {
+ urls = append(urls, f)
+ }
+
c.Name = c.raw.Name
- c.URL = c.raw.Option(urlKey)
+ c.URLs = urls
c.Fetch = fetch
return nil
@@ -246,9 +261,21 @@ func (c *RemoteConfig) marshal() *format.Subsection {
}
c.raw.Name = c.Name
- c.raw.SetOption(urlKey, c.URL)
- for _, rs := range c.Fetch {
- c.raw.SetOption(fetchKey, rs.String())
+ if len(c.URLs) == 0 {
+ c.raw.RemoveOption(urlKey)
+ } else {
+ c.raw.SetOption(urlKey, c.URLs...)
+ }
+
+ if len(c.Fetch) == 0 {
+ c.raw.RemoveOption(fetchKey)
+ } else {
+ var values []string
+ for _, rs := range c.Fetch {
+ values = append(values, rs.String())
+ }
+
+ c.raw.SetOption(fetchKey, values...)
}
return c.raw
diff --git a/config/config_test.go b/config/config_test.go
index cfab36d..97f4bbf 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -13,6 +13,11 @@ func (s *ConfigSuite) TestUnmarshall(c *C) {
[remote "origin"]
url = git@github.com:mcuadros/go-git.git
fetch = +refs/heads/*:refs/remotes/origin/*
+[remote "alt"]
+ url = git@github.com:mcuadros/go-git.git
+ url = git@github.com:src-d/go-git.git
+ fetch = +refs/heads/*:refs/remotes/origin/*
+ fetch = +refs/pull/*:refs/remotes/origin/pull/*
[submodule "qux"]
path = qux
url = https://github.com/foo/qux.git
@@ -28,10 +33,13 @@ func (s *ConfigSuite) TestUnmarshall(c *C) {
c.Assert(cfg.Core.IsBare, Equals, true)
c.Assert(cfg.Core.Worktree, Equals, "foo")
- c.Assert(cfg.Remotes, HasLen, 1)
+ c.Assert(cfg.Remotes, HasLen, 2)
c.Assert(cfg.Remotes["origin"].Name, Equals, "origin")
- c.Assert(cfg.Remotes["origin"].URL, Equals, "git@github.com:mcuadros/go-git.git")
+ c.Assert(cfg.Remotes["origin"].URLs, DeepEquals, []string{"git@github.com:mcuadros/go-git.git"})
c.Assert(cfg.Remotes["origin"].Fetch, DeepEquals, []RefSpec{"+refs/heads/*:refs/remotes/origin/*"})
+ c.Assert(cfg.Remotes["alt"].Name, Equals, "alt")
+ c.Assert(cfg.Remotes["alt"].URLs, DeepEquals, []string{"git@github.com:mcuadros/go-git.git", "git@github.com:src-d/go-git.git"})
+ c.Assert(cfg.Remotes["alt"].Fetch, DeepEquals, []RefSpec{"+refs/heads/*:refs/remotes/origin/*", "+refs/pull/*:refs/remotes/origin/pull/*"})
c.Assert(cfg.Submodules, HasLen, 1)
c.Assert(cfg.Submodules["qux"].Name, Equals, "qux")
c.Assert(cfg.Submodules["qux"].URL, Equals, "https://github.com/foo/qux.git")
@@ -45,6 +53,11 @@ func (s *ConfigSuite) TestMarshall(c *C) {
worktree = bar
[remote "origin"]
url = git@github.com:mcuadros/go-git.git
+[remote "alt"]
+ url = git@github.com:mcuadros/go-git.git
+ url = git@github.com:src-d/go-git.git
+ fetch = +refs/heads/*:refs/remotes/origin/*
+ fetch = +refs/pull/*:refs/remotes/origin/pull/*
[submodule "qux"]
url = https://github.com/foo/qux.git
`)
@@ -54,7 +67,13 @@ func (s *ConfigSuite) TestMarshall(c *C) {
cfg.Core.Worktree = "bar"
cfg.Remotes["origin"] = &RemoteConfig{
Name: "origin",
- URL: "git@github.com:mcuadros/go-git.git",
+ URLs: []string{"git@github.com:mcuadros/go-git.git"},
+ }
+
+ cfg.Remotes["alt"] = &RemoteConfig{
+ Name: "alt",
+ URLs: []string{"git@github.com:mcuadros/go-git.git", "git@github.com:src-d/go-git.git"},
+ Fetch: []RefSpec{"+refs/heads/*:refs/remotes/origin/*", "+refs/pull/*:refs/remotes/origin/pull/*"},
}
cfg.Submodules["qux"] = &Submodule{
@@ -88,7 +107,7 @@ func (s *ConfigSuite) TestUnmarshallMarshall(c *C) {
output, err := cfg.Marshal()
c.Assert(err, IsNil)
- c.Assert(output, DeepEquals, input)
+ c.Assert(string(output), DeepEquals, string(input))
}
func (s *ConfigSuite) TestValidateInvalidRemote(c *C) {
@@ -122,7 +141,7 @@ func (s *ConfigSuite) TestRemoteConfigValidateMissingName(c *C) {
}
func (s *ConfigSuite) TestRemoteConfigValidateDefault(c *C) {
- config := &RemoteConfig{Name: "foo", URL: "http://foo/bar"}
+ config := &RemoteConfig{Name: "foo", URLs: []string{"http://foo/bar"}}
c.Assert(config.Validate(), IsNil)
fetch := config.Fetch
diff --git a/example_test.go b/example_test.go
index 585b38a..1b369ba 100644
--- a/example_test.go
+++ b/example_test.go
@@ -91,7 +91,7 @@ func ExampleRepository_CreateRemote() {
// Add a new remote, with the default fetch refspec
_, err := r.CreateRemote(&config.RemoteConfig{
Name: "example",
- URL: "https://github.com/git-fixtures/basic.git",
+ URLs: []string{"https://github.com/git-fixtures/basic.git"},
})
if err != nil {
diff --git a/plumbing/format/config/decoder_test.go b/plumbing/format/config/decoder_test.go
index 412549f..0a8e92c 100644
--- a/plumbing/format/config/decoder_test.go
+++ b/plumbing/format/config/decoder_test.go
@@ -17,7 +17,10 @@ func (s *DecoderSuite) TestDecode(c *C) {
cfg := &Config{}
err := d.Decode(cfg)
c.Assert(err, IsNil, Commentf("decoder error for fixture: %d", idx))
- c.Assert(cfg, DeepEquals, fixture.Config, Commentf("bad result for fixture: %d", idx))
+ buf := bytes.NewBuffer(nil)
+ e := NewEncoder(buf)
+ _ = e.Encode(cfg)
+ c.Assert(cfg, DeepEquals, fixture.Config, Commentf("bad result for fixture: %d, %s", idx, buf.String()))
}
}
diff --git a/plumbing/format/config/fixtures_test.go b/plumbing/format/config/fixtures_test.go
index 12ff288..f3533df 100644
--- a/plumbing/format/config/fixtures_test.go
+++ b/plumbing/format/config/fixtures_test.go
@@ -87,4 +87,18 @@ var fixtures = []*Fixture{
AddOption("sect1", "subsect1", "opt2", "value2b").
AddOption("sect1", "subsect2", "opt2", "value2"),
},
+ {
+ Raw: `
+ [sect1]
+ opt1 = value1
+ opt1 = value2
+ `,
+ Text: `[sect1]
+ opt1 = value1
+ opt1 = value2
+`,
+ Config: New().
+ AddOption("sect1", "", "opt1", "value1").
+ AddOption("sect1", "", "opt1", "value2"),
+ },
}
diff --git a/plumbing/format/config/option.go b/plumbing/format/config/option.go
index 3c391c6..d4775e4 100644
--- a/plumbing/format/config/option.go
+++ b/plumbing/format/config/option.go
@@ -1,6 +1,7 @@
package config
import (
+ "fmt"
"strings"
)
@@ -21,6 +22,15 @@ func (o *Option) IsKey(key string) bool {
return strings.ToLower(o.Key) == strings.ToLower(key)
}
+func (opts Options) GoString() string {
+ var strs []string
+ for _, opt := range opts {
+ strs = append(strs, fmt.Sprintf("%#v", opt))
+ }
+
+ return strings.Join(strs, ", ")
+}
+
// Get gets the value for the given key if set,
// otherwise it returns the empty string.
//
@@ -69,16 +79,39 @@ func (opts Options) withAddedOption(key string, value string) Options {
return append(opts, &Option{key, value})
}
-func (opts Options) withSettedOption(key string, value string) Options {
- for i := len(opts) - 1; i >= 0; i-- {
- o := opts[i]
- if o.IsKey(key) {
- result := make(Options, len(opts))
- copy(result, opts)
- result[i] = &Option{key, value}
- return result
+func (opts Options) withSettedOption(key string, values ...string) Options {
+ var result Options
+ var added []string
+ for _, o := range opts {
+ if !o.IsKey(key) {
+ result = append(result, o)
+ continue
+ }
+
+ if contains(values, o.Value) {
+ added = append(added, o.Value)
+ result = append(result, o)
+ continue
+ }
+ }
+
+ for _, value := range values {
+ if contains(added, value) {
+ continue
+ }
+
+ result = result.withAddedOption(key, value)
+ }
+
+ return result
+}
+
+func contains(haystack []string, needle string) bool {
+ for _, s := range haystack {
+ if s == needle {
+ return true
}
}
- return opts.withAddedOption(key, value)
+ return false
}
diff --git a/plumbing/format/config/section.go b/plumbing/format/config/section.go
index 547da1e..4a17e3b 100644
--- a/plumbing/format/config/section.go
+++ b/plumbing/format/config/section.go
@@ -1,6 +1,9 @@
package config
-import "strings"
+import (
+ "fmt"
+ "strings"
+)
// Section is the representation of a section inside git configuration files.
// Each Section contains Options that are used by both the Git plumbing
@@ -36,8 +39,26 @@ type Subsection struct {
type Sections []*Section
+func (s Sections) GoString() string {
+ var strs []string
+ for _, ss := range s {
+ strs = append(strs, fmt.Sprintf("%#v", ss))
+ }
+
+ return strings.Join(strs, ", ")
+}
+
type Subsections []*Subsection
+func (s Subsections) GoString() string {
+ var strs []string
+ for _, ss := range s {
+ strs = append(strs, fmt.Sprintf("%#v", ss))
+ }
+
+ return strings.Join(strs, ", ")
+}
+
// 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)
@@ -113,8 +134,8 @@ func (s *Subsection) AddOption(key string, value string) *Subsection {
// SetOption adds a new Option to the Subsection. If the option already exists, is replaced.
// The updated Subsection is returned.
-func (s *Subsection) SetOption(key string, value string) *Subsection {
- s.Options = s.Options.withSettedOption(key, value)
+func (s *Subsection) SetOption(key string, value ...string) *Subsection {
+ s.Options = s.Options.withSettedOption(key, value...)
return s
}
diff --git a/plumbing/format/config/section_test.go b/plumbing/format/config/section_test.go
index cfd9f3f..0290386 100644
--- a/plumbing/format/config/section_test.go
+++ b/plumbing/format/config/section_test.go
@@ -69,3 +69,22 @@ func (s *SectionSuite) TestSubsection_RemoveOption(c *C) {
}
c.Assert(sect.RemoveOption("key1"), DeepEquals, expected)
}
+
+func (s *SectionSuite) TestSubsection_SetOption(c *C) {
+ sect := &Subsection{
+ Options: []*Option{
+ {Key: "key1", Value: "value1"},
+ {Key: "key2", Value: "value2"},
+ {Key: "key1", Value: "value3"},
+ },
+ }
+
+ expected := &Subsection{
+ Options: []*Option{
+ {Key: "key1", Value: "value1"},
+ {Key: "key2", Value: "value2"},
+ {Key: "key1", Value: "value4"},
+ },
+ }
+ c.Assert(sect.SetOption("key1", "value1", "value4"), DeepEquals, expected)
+}
diff --git a/plumbing/reference.go b/plumbing/reference.go
index 5d477b9..2c30fe0 100644
--- a/plumbing/reference.go
+++ b/plumbing/reference.go
@@ -55,6 +55,26 @@ func (r ReferenceType) String() string {
// ReferenceName reference name's
type ReferenceName string
+// IsBranch check if a reference is a branch
+func (r ReferenceName) IsBranch() bool {
+ return strings.HasPrefix(string(r), refHeadPrefix)
+}
+
+// IsNote check if a reference is a note
+func (r ReferenceName) IsNote() bool {
+ return strings.HasPrefix(string(r), refNotePrefix)
+}
+
+// IsRemote check if a reference is a remote
+func (r ReferenceName) IsRemote() bool {
+ return strings.HasPrefix(string(r), refRemotePrefix)
+}
+
+// IsTag check if a reference is a tag
+func (r ReferenceName) IsTag() bool {
+ return strings.HasPrefix(string(r), refTagPrefix)
+}
+
func (r ReferenceName) String() string {
return string(r)
}
@@ -138,26 +158,6 @@ func (r *Reference) Target() ReferenceName {
return r.target
}
-// IsBranch check if a reference is a branch
-func (r *Reference) IsBranch() bool {
- return strings.HasPrefix(string(r.n), refHeadPrefix)
-}
-
-// IsNote check if a reference is a note
-func (r *Reference) IsNote() bool {
- return strings.HasPrefix(string(r.n), refNotePrefix)
-}
-
-// IsRemote check if a reference is a remote
-func (r *Reference) IsRemote() bool {
- return strings.HasPrefix(string(r.n), refRemotePrefix)
-}
-
-// IsTag check if a reference is a tag
-func (r *Reference) IsTag() bool {
- return strings.HasPrefix(string(r.n), refTagPrefix)
-}
-
// Strings dump a reference as a [2]string
func (r *Reference) Strings() [2]string {
var o [2]string
diff --git a/plumbing/reference_test.go b/plumbing/reference_test.go
index 97c8772..47919ef 100644
--- a/plumbing/reference_test.go
+++ b/plumbing/reference_test.go
@@ -55,21 +55,21 @@ func (s *ReferenceSuite) TestNewHashReference(c *C) {
}
func (s *ReferenceSuite) TestIsBranch(c *C) {
- r := NewHashReference(ExampleReferenceName, ZeroHash)
+ r := ExampleReferenceName
c.Assert(r.IsBranch(), Equals, true)
}
func (s *ReferenceSuite) TestIsNote(c *C) {
- r := NewHashReference(ReferenceName("refs/notes/foo"), ZeroHash)
+ r := ReferenceName("refs/notes/foo")
c.Assert(r.IsNote(), Equals, true)
}
func (s *ReferenceSuite) TestIsRemote(c *C) {
- r := NewHashReference(ReferenceName("refs/remotes/origin/master"), ZeroHash)
+ r := ReferenceName("refs/remotes/origin/master")
c.Assert(r.IsRemote(), Equals, true)
}
func (s *ReferenceSuite) TestIsTag(c *C) {
- r := NewHashReference(ReferenceName("refs/tags/v3.1."), ZeroHash)
+ r := ReferenceName("refs/tags/v3.1.")
c.Assert(r.IsTag(), Equals, true)
}
diff --git a/plumbing/transport/file/receive_pack_test.go b/plumbing/transport/file/receive_pack_test.go
index ab21aea..a7dc399 100644
--- a/plumbing/transport/file/receive_pack_test.go
+++ b/plumbing/transport/file/receive_pack_test.go
@@ -70,6 +70,6 @@ func (s *ReceivePackSuite) TestNonExistentCommand(c *C) {
cmd := "/non-existent-git"
client := NewClient(cmd, cmd)
session, err := client.NewReceivePackSession(s.Endpoint, s.EmptyAuth)
- c.Assert(err, ErrorMatches, ".*no such file or directory.*")
+ c.Assert(err, ErrorMatches, ".*(no such file or directory.*|.*file does not exist)*.")
c.Assert(session, IsNil)
}
diff --git a/plumbing/transport/test/receive_pack.go b/plumbing/transport/test/receive_pack.go
index 6309ef0..d29d9ca 100644
--- a/plumbing/transport/test/receive_pack.go
+++ b/plumbing/transport/test/receive_pack.go
@@ -61,6 +61,7 @@ func (s *ReceivePackSuite) TestAdvertisedReferencesNotExists(c *C) {
func (s *ReceivePackSuite) TestCallAdvertisedReferenceTwice(c *C) {
r, err := s.Client.NewReceivePackSession(s.Endpoint, s.EmptyAuth)
+ defer func() { c.Assert(r.Close(), IsNil) }()
c.Assert(err, IsNil)
ar1, err := r.AdvertisedReferences()
c.Assert(err, IsNil)
diff --git a/remote.go b/remote.go
index fe44009..2409301 100644
--- a/remote.go
+++ b/remote.go
@@ -43,8 +43,11 @@ func (r *Remote) Config() *config.RemoteConfig {
}
func (r *Remote) String() string {
- fetch := r.c.URL
- push := r.c.URL
+ var fetch, push string
+ if len(r.c.URLs) > 0 {
+ fetch = r.c.URLs[0]
+ push = r.c.URLs[0]
+ }
return fmt.Sprintf("%s\t%s (fetch)\n%[1]s\t%[3]s (push)", r.c.Name, fetch, push)
}
@@ -71,7 +74,7 @@ func (r *Remote) PushContext(ctx context.Context, o *PushOptions) error {
return fmt.Errorf("remote names don't match: %s != %s", o.RemoteName, r.c.Name)
}
- s, err := newSendPackSession(r.c.URL, o.Auth)
+ s, err := newSendPackSession(r.c.URLs[0], o.Auth)
if err != nil {
return err
}
@@ -211,7 +214,7 @@ func (r *Remote) fetch(ctx context.Context, o *FetchOptions) (storer.ReferenceSt
o.RefSpecs = r.c.Fetch
}
- s, err := newUploadPackSession(r.c.URL, o.Auth)
+ s, err := newUploadPackSession(r.c.URLs[0], o.Auth)
if err != nil {
return nil, err
}
@@ -464,7 +467,7 @@ func calculateRefs(spec []config.RefSpec,
refs := make(memory.ReferenceStorage, 0)
return refs, iter.ForEach(func(ref *plumbing.Reference) error {
if !config.MatchAny(spec, ref.Name()) {
- if !ref.IsTag() || tags != AllTags {
+ if !ref.Name().IsTag() || tags != AllTags {
return nil
}
}
@@ -663,7 +666,7 @@ func (r *Remote) updateLocalReferenceStorage(
func (r *Remote) buildFetchedTags(refs memory.ReferenceStorage) (updated bool, err error) {
for _, ref := range refs {
- if !ref.IsTag() {
+ if !ref.Name().IsTag() {
continue
}
diff --git a/remote_test.go b/remote_test.go
index ece052a..e2fd8ae 100644
--- a/remote_test.go
+++ b/remote_test.go
@@ -26,25 +26,25 @@ type RemoteSuite struct {
var _ = Suite(&RemoteSuite{})
func (s *RemoteSuite) TestFetchInvalidEndpoint(c *C) {
- r := newRemote(nil, &config.RemoteConfig{Name: "foo", URL: "http://\\"})
+ r := newRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"http://\\"}})
err := r.Fetch(&FetchOptions{RemoteName: "foo"})
c.Assert(err, ErrorMatches, ".*invalid character.*")
}
func (s *RemoteSuite) TestFetchNonExistentEndpoint(c *C) {
- r := newRemote(nil, &config.RemoteConfig{Name: "foo", URL: "ssh://non-existent/foo.git"})
+ r := newRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"ssh://non-existent/foo.git"}})
err := r.Fetch(&FetchOptions{})
c.Assert(err, NotNil)
}
func (s *RemoteSuite) TestFetchInvalidSchemaEndpoint(c *C) {
- r := newRemote(nil, &config.RemoteConfig{Name: "foo", URL: "qux://foo"})
+ r := newRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"qux://foo"}})
err := r.Fetch(&FetchOptions{})
c.Assert(err, ErrorMatches, ".*unsupported scheme.*")
}
func (s *RemoteSuite) TestFetchInvalidFetchOptions(c *C) {
- r := newRemote(nil, &config.RemoteConfig{Name: "foo", URL: "qux://foo"})
+ r := newRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"qux://foo"}})
invalid := config.RefSpec("^*$ñ")
err := r.Fetch(&FetchOptions{RefSpecs: []config.RefSpec{invalid}})
c.Assert(err, Equals, config.ErrRefSpecMalformedSeparator)
@@ -52,7 +52,7 @@ func (s *RemoteSuite) TestFetchInvalidFetchOptions(c *C) {
func (s *RemoteSuite) TestFetchWildcard(c *C) {
r := newRemote(memory.NewStorage(), &config.RemoteConfig{
- URL: s.GetBasicLocalRepositoryURL(),
+ URLs: []string{s.GetBasicLocalRepositoryURL()},
})
s.testFetch(c, r, &FetchOptions{
@@ -68,7 +68,7 @@ func (s *RemoteSuite) TestFetchWildcard(c *C) {
func (s *RemoteSuite) TestFetchWildcardTags(c *C) {
r := newRemote(memory.NewStorage(), &config.RemoteConfig{
- URL: s.GetLocalRepositoryURL(fixtures.ByTag("tags").One()),
+ URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())},
})
s.testFetch(c, r, &FetchOptions{
@@ -87,7 +87,7 @@ func (s *RemoteSuite) TestFetchWildcardTags(c *C) {
func (s *RemoteSuite) TestFetch(c *C) {
r := newRemote(memory.NewStorage(), &config.RemoteConfig{
- URL: s.GetLocalRepositoryURL(fixtures.ByTag("tags").One()),
+ URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())},
})
s.testFetch(c, r, &FetchOptions{
@@ -101,7 +101,7 @@ func (s *RemoteSuite) TestFetch(c *C) {
func (s *RemoteSuite) TestFetchContext(c *C) {
r := newRemote(memory.NewStorage(), &config.RemoteConfig{
- URL: s.GetLocalRepositoryURL(fixtures.ByTag("tags").One()),
+ URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())},
})
ctx, cancel := context.WithCancel(context.Background())
@@ -113,12 +113,11 @@ func (s *RemoteSuite) TestFetchContext(c *C) {
},
})
c.Assert(err, NotNil)
-
}
func (s *RemoteSuite) TestFetchWithAllTags(c *C) {
r := newRemote(memory.NewStorage(), &config.RemoteConfig{
- URL: s.GetLocalRepositoryURL(fixtures.ByTag("tags").One()),
+ URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())},
})
s.testFetch(c, r, &FetchOptions{
@@ -138,7 +137,7 @@ func (s *RemoteSuite) TestFetchWithAllTags(c *C) {
func (s *RemoteSuite) TestFetchWithNoTags(c *C) {
r := newRemote(memory.NewStorage(), &config.RemoteConfig{
- URL: s.GetLocalRepositoryURL(fixtures.ByTag("tags").One()),
+ URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())},
})
s.testFetch(c, r, &FetchOptions{
@@ -154,7 +153,7 @@ func (s *RemoteSuite) TestFetchWithNoTags(c *C) {
func (s *RemoteSuite) TestFetchWithDepth(c *C) {
r := newRemote(memory.NewStorage(), &config.RemoteConfig{
- URL: s.GetBasicLocalRepositoryURL(),
+ URLs: []string{s.GetBasicLocalRepositoryURL()},
})
s.testFetch(c, r, &FetchOptions{
@@ -193,7 +192,7 @@ func (s *RemoteSuite) TestFetchWithProgress(c *C) {
sto := memory.NewStorage()
buf := bytes.NewBuffer(nil)
- r := newRemote(sto, &config.RemoteConfig{Name: "foo", URL: url})
+ r := newRemote(sto, &config.RemoteConfig{Name: "foo", URLs: []string{url}})
refspec := config.RefSpec("+refs/heads/*:refs/remotes/origin/*")
err := r.Fetch(&FetchOptions{
@@ -229,7 +228,7 @@ func (s *RemoteSuite) TestFetchWithPackfileWriter(c *C) {
mock := &mockPackfileWriter{Storer: fss}
url := s.GetBasicLocalRepositoryURL()
- r := newRemote(mock, &config.RemoteConfig{Name: "foo", URL: url})
+ r := newRemote(mock, &config.RemoteConfig{Name: "foo", URLs: []string{url}})
refspec := config.RefSpec("+refs/heads/*:refs/remotes/origin/*")
err = r.Fetch(&FetchOptions{
@@ -258,7 +257,7 @@ func (s *RemoteSuite) TestFetchNoErrAlreadyUpToDate(c *C) {
func (s *RemoteSuite) TestFetchNoErrAlreadyUpToDateButStillUpdateLocalRemoteRefs(c *C) {
r := newRemote(memory.NewStorage(), &config.RemoteConfig{
- URL: s.GetBasicLocalRepositoryURL(),
+ URLs: []string{s.GetBasicLocalRepositoryURL()},
})
o := &FetchOptions{
@@ -294,7 +293,7 @@ func (s *RemoteSuite) TestFetchNoErrAlreadyUpToDateWithNonCommitObjects(c *C) {
}
func (s *RemoteSuite) doTestFetchNoErrAlreadyUpToDate(c *C, url string) {
- r := newRemote(memory.NewStorage(), &config.RemoteConfig{URL: url})
+ r := newRemote(memory.NewStorage(), &config.RemoteConfig{URLs: []string{url}})
o := &FetchOptions{
RefSpecs: []config.RefSpec{
@@ -311,7 +310,7 @@ func (s *RemoteSuite) doTestFetchNoErrAlreadyUpToDate(c *C, url string) {
func (s *RemoteSuite) TestString(c *C) {
r := newRemote(nil, &config.RemoteConfig{
Name: "foo",
- URL: "https://github.com/git-fixtures/basic.git",
+ URLs: []string{"https://github.com/git-fixtures/basic.git"},
})
c.Assert(r.String(), Equals, ""+
@@ -331,7 +330,7 @@ func (s *RemoteSuite) TestPushToEmptyRepository(c *C) {
r := newRemote(sto, &config.RemoteConfig{
Name: DefaultRemoteName,
- URL: url,
+ URLs: []string{url},
})
rs := config.RefSpec("refs/heads/*:refs/heads/*")
@@ -345,7 +344,7 @@ func (s *RemoteSuite) TestPushToEmptyRepository(c *C) {
expected := make(map[string]string)
iter.ForEach(func(ref *plumbing.Reference) error {
- if !ref.IsBranch() {
+ if !ref.Name().IsBranch() {
return nil
}
@@ -369,7 +368,7 @@ func (s *RemoteSuite) TestPushContext(c *C) {
r := newRemote(sto, &config.RemoteConfig{
Name: DefaultRemoteName,
- URL: url,
+ URLs: []string{url},
})
ctx, cancel := context.WithCancel(context.Background())
@@ -392,7 +391,7 @@ func (s *RemoteSuite) TestPushTags(c *C) {
r := newRemote(sto, &config.RemoteConfig{
Name: DefaultRemoteName,
- URL: url,
+ URLs: []string{url},
})
err = r.Push(&PushOptions{
@@ -416,7 +415,7 @@ func (s *RemoteSuite) TestPushNoErrAlreadyUpToDate(c *C) {
r := newRemote(sto, &config.RemoteConfig{
Name: DefaultRemoteName,
- URL: fs.Root(),
+ URLs: []string{fs.Root()},
})
err = r.Push(&PushOptions{
@@ -490,7 +489,7 @@ func (s *RemoteSuite) TestPushForce(c *C) {
url := dstFs.Root()
r := newRemote(sto, &config.RemoteConfig{
Name: DefaultRemoteName,
- URL: url,
+ URLs: []string{url},
})
oldRef, err := dstSto.Reference(plumbing.ReferenceName("refs/heads/branch"))
@@ -540,25 +539,25 @@ func (s *RemoteSuite) TestPushNewReference(c *C) {
}
func (s *RemoteSuite) TestPushInvalidEndpoint(c *C) {
- r := newRemote(nil, &config.RemoteConfig{Name: "foo", URL: "http://\\"})
+ r := newRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"http://\\"}})
err := r.Push(&PushOptions{RemoteName: "foo"})
c.Assert(err, ErrorMatches, ".*invalid character.*")
}
func (s *RemoteSuite) TestPushNonExistentEndpoint(c *C) {
- r := newRemote(nil, &config.RemoteConfig{Name: "foo", URL: "ssh://non-existent/foo.git"})
+ r := newRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"ssh://non-existent/foo.git"}})
err := r.Push(&PushOptions{})
c.Assert(err, NotNil)
}
func (s *RemoteSuite) TestPushInvalidSchemaEndpoint(c *C) {
- r := newRemote(nil, &config.RemoteConfig{Name: "origin", URL: "qux://foo"})
+ r := newRemote(nil, &config.RemoteConfig{Name: "origin", URLs: []string{"qux://foo"}})
err := r.Push(&PushOptions{})
c.Assert(err, ErrorMatches, ".*unsupported scheme.*")
}
func (s *RemoteSuite) TestPushInvalidFetchOptions(c *C) {
- r := newRemote(nil, &config.RemoteConfig{Name: "foo", URL: "qux://foo"})
+ r := newRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"qux://foo"}})
invalid := config.RefSpec("^*$ñ")
err := r.Push(&PushOptions{RefSpecs: []config.RefSpec{invalid}})
c.Assert(err, Equals, config.ErrRefSpecMalformedSeparator)
@@ -567,7 +566,7 @@ func (s *RemoteSuite) TestPushInvalidFetchOptions(c *C) {
func (s *RemoteSuite) TestPushInvalidRefSpec(c *C) {
r := newRemote(nil, &config.RemoteConfig{
Name: DefaultRemoteName,
- URL: "some-url",
+ URLs: []string{"some-url"},
})
rs := config.RefSpec("^*$**")
@@ -580,7 +579,7 @@ func (s *RemoteSuite) TestPushInvalidRefSpec(c *C) {
func (s *RemoteSuite) TestPushWrongRemoteName(c *C) {
r := newRemote(nil, &config.RemoteConfig{
Name: DefaultRemoteName,
- URL: "some-url",
+ URLs: []string{"some-url"},
})
err := r.Push(&PushOptions{
diff --git a/repository.go b/repository.go
index 7f5b793..8110cf1 100644
--- a/repository.go
+++ b/repository.go
@@ -286,7 +286,7 @@ func dotGitFileToOSFilesystem(path string, fs billy.Filesystem) (billy.Filesyste
return nil, fmt.Errorf(".git file has no %s prefix", prefix)
}
- gitdir := line[len(prefix):]
+ gitdir := strings.Split(line[len(prefix):], "\n")[0]
gitdir = strings.TrimSpace(gitdir)
if filepath.IsAbs(gitdir) {
return osfs.New(gitdir), nil
@@ -408,7 +408,7 @@ func (r *Repository) clone(ctx context.Context, o *CloneOptions) error {
c := &config.RemoteConfig{
Name: o.RemoteName,
- URL: o.URL,
+ URLs: []string{o.URL},
}
if _, err := r.CreateRemote(c); err != nil {
@@ -448,20 +448,24 @@ func (r *Repository) clone(ctx context.Context, o *CloneOptions) error {
return r.updateRemoteConfigIfNeeded(o, c, head)
}
-func (r *Repository) cloneRefSpec(o *CloneOptions,
- c *config.RemoteConfig) []config.RefSpec {
-
- if !o.SingleBranch {
- return c.Fetch
- }
+const (
+ refspecTagWithDepth = "+refs/tags/%s:refs/tags/%[1]s"
+ refspecSingleBranch = "+refs/heads/%s:refs/remotes/%s/%[1]s"
+ refspecSingleBranchHEAD = "+HEAD:refs/remotes/%s/HEAD"
+)
+func (r *Repository) cloneRefSpec(o *CloneOptions, c *config.RemoteConfig) []config.RefSpec {
var rs string
- if o.ReferenceName == plumbing.HEAD {
+ switch {
+ case o.ReferenceName.IsTag() && o.Depth > 0:
+ rs = fmt.Sprintf(refspecTagWithDepth, o.ReferenceName.Short())
+ case o.SingleBranch && o.ReferenceName == plumbing.HEAD:
rs = fmt.Sprintf(refspecSingleBranchHEAD, c.Name)
- } else {
- rs = fmt.Sprintf(refspecSingleBranch,
- o.ReferenceName.Short(), c.Name)
+ case o.SingleBranch:
+ rs = fmt.Sprintf(refspecSingleBranch, o.ReferenceName.Short(), c.Name)
+ default:
+ return c.Fetch
}
return []config.RefSpec{config.RefSpec(rs)}
@@ -477,11 +481,6 @@ func (r *Repository) setIsBare(isBare bool) error {
return r.Storer.SetConfig(cfg)
}
-const (
- refspecSingleBranch = "+refs/heads/%s:refs/remotes/%s/%[1]s"
- refspecSingleBranchHEAD = "+HEAD:refs/remotes/%s/HEAD"
-)
-
func (r *Repository) updateRemoteConfigIfNeeded(o *CloneOptions, c *config.RemoteConfig, head *plumbing.Reference) error {
if !o.SingleBranch {
return nil
@@ -541,7 +540,7 @@ func (r *Repository) fetchAndUpdateReferences(
func (r *Repository) updateReferences(spec []config.RefSpec,
resolvedHead *plumbing.Reference) (updated bool, err error) {
- if !resolvedHead.IsBranch() {
+ if !resolvedHead.Name().IsBranch() {
// Detached HEAD mode
head := plumbing.NewHashReference(plumbing.HEAD, resolvedHead.Hash())
return updateReferenceStorerIfNeeded(r.Storer, head)
@@ -701,7 +700,7 @@ func (r *Repository) Tags() (storer.ReferenceIter, error) {
return storer.NewReferenceFilteredIter(
func(r *plumbing.Reference) bool {
- return r.IsTag()
+ return r.Name().IsTag()
}, refIter), nil
}
@@ -714,7 +713,7 @@ func (r *Repository) Branches() (storer.ReferenceIter, error) {
return storer.NewReferenceFilteredIter(
func(r *plumbing.Reference) bool {
- return r.IsBranch()
+ return r.Name().IsBranch()
}, refIter), nil
}
@@ -727,7 +726,7 @@ func (r *Repository) Notes() (storer.ReferenceIter, error) {
return storer.NewReferenceFilteredIter(
func(r *plumbing.Reference) bool {
- return r.IsNote()
+ return r.Name().IsNote()
}, refIter), nil
}
diff --git a/repository_test.go b/repository_test.go
index 558149b..3da11f6 100644
--- a/repository_test.go
+++ b/repository_test.go
@@ -181,7 +181,7 @@ func (s *RepositorySuite) TestCreateRemoteAndRemote(c *C) {
r, _ := Init(memory.NewStorage(), nil)
remote, err := r.CreateRemote(&config.RemoteConfig{
Name: "foo",
- URL: "http://foo/foo.git",
+ URLs: []string{"http://foo/foo.git"},
})
c.Assert(err, IsNil)
@@ -205,7 +205,7 @@ func (s *RepositorySuite) TestDeleteRemote(c *C) {
r, _ := Init(memory.NewStorage(), nil)
_, err := r.CreateRemote(&config.RemoteConfig{
Name: "foo",
- URL: "http://foo/foo.git",
+ URLs: []string{"http://foo/foo.git"},
})
c.Assert(err, IsNil)
@@ -348,7 +348,7 @@ func (s *RepositorySuite) TestPlainOpenBareRelativeGitDirFileTrailingGarbage(c *
altDir, err := ioutil.TempDir("", "plain-open")
c.Assert(err, IsNil)
- err = ioutil.WriteFile(filepath.Join(altDir, ".git"), []byte(fmt.Sprintf("gitdir: %s\nTRAILING", dir)), 0644)
+ err = ioutil.WriteFile(filepath.Join(altDir, ".git"), []byte(fmt.Sprintf("gitdir: %s\nTRAILING", altDir)), 0644)
c.Assert(err, IsNil)
r, err = PlainOpen(altDir)
@@ -426,7 +426,7 @@ func (s *RepositorySuite) TestFetch(c *C) {
r, _ := Init(memory.NewStorage(), nil)
_, err := r.CreateRemote(&config.RemoteConfig{
Name: DefaultRemoteName,
- URL: s.GetBasicLocalRepositoryURL(),
+ URLs: []string{s.GetBasicLocalRepositoryURL()},
})
c.Assert(err, IsNil)
c.Assert(r.Fetch(&FetchOptions{}), IsNil)
@@ -449,7 +449,7 @@ func (s *RepositorySuite) TestFetchContext(c *C) {
r, _ := Init(memory.NewStorage(), nil)
_, err := r.CreateRemote(&config.RemoteConfig{
Name: DefaultRemoteName,
- URL: s.GetBasicLocalRepositoryURL(),
+ URLs: []string{s.GetBasicLocalRepositoryURL()},
})
c.Assert(err, IsNil)
@@ -531,7 +531,7 @@ func (s *RepositorySuite) TestCloneConfig(c *C) {
c.Assert(cfg.Core.IsBare, Equals, true)
c.Assert(cfg.Remotes, HasLen, 1)
c.Assert(cfg.Remotes["origin"].Name, Equals, "origin")
- c.Assert(cfg.Remotes["origin"].URL, Not(Equals), "")
+ c.Assert(cfg.Remotes["origin"].URLs, HasLen, 1)
}
func (s *RepositorySuite) TestCloneSingleBranchAndNonHEAD(c *C) {
@@ -613,23 +613,52 @@ func (s *RepositorySuite) TestCloneDetachedHEAD(c *C) {
URL: s.GetBasicLocalRepositoryURL(),
ReferenceName: plumbing.ReferenceName("refs/tags/v1.0.0"),
})
+ c.Assert(err, IsNil)
+
+ head, err := r.Reference(plumbing.HEAD, false)
+ c.Assert(err, IsNil)
+ c.Assert(head, NotNil)
+ c.Assert(head.Type(), Equals, plumbing.HashReference)
+ c.Assert(head.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
+
+ count := 0
+ objects, err := r.Objects()
+ c.Assert(err, IsNil)
+ objects.ForEach(func(object.Object) error { count++; return nil })
+ c.Assert(count, Equals, 31)
+}
+
+func (s *RepositorySuite) TestCloneDetachedHEADAndShallow(c *C) {
+ r, _ := Init(memory.NewStorage(), memfs.New())
+ err := r.clone(context.Background(), &CloneOptions{
+ URL: s.GetBasicLocalRepositoryURL(),
+ ReferenceName: plumbing.ReferenceName("refs/tags/v1.0.0"),
+ Depth: 1,
+ })
+
+ c.Assert(err, IsNil)
head, err := r.Reference(plumbing.HEAD, false)
c.Assert(err, IsNil)
c.Assert(head, NotNil)
c.Assert(head.Type(), Equals, plumbing.HashReference)
c.Assert(head.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
+
+ count := 0
+ objects, err := r.Objects()
+ c.Assert(err, IsNil)
+ objects.ForEach(func(object.Object) error { count++; return nil })
+ c.Assert(count, Equals, 15)
}
func (s *RepositorySuite) TestPush(c *C) {
url := c.MkDir()
- fmt.Println(url)
server, err := PlainInit(url, true)
c.Assert(err, IsNil)
_, err = s.Repository.CreateRemote(&config.RemoteConfig{
Name: "test",
- URL: url,
+ URLs: []string{url},
})
c.Assert(err, IsNil)
@@ -651,13 +680,12 @@ func (s *RepositorySuite) TestPush(c *C) {
func (s *RepositorySuite) TestPushContext(c *C) {
url := c.MkDir()
- fmt.Println(url)
_, err := PlainInit(url, true)
c.Assert(err, IsNil)
_, err = s.Repository.CreateRemote(&config.RemoteConfig{
Name: "foo",
- URL: url,
+ URLs: []string{url},
})
c.Assert(err, IsNil)
@@ -923,7 +951,7 @@ func (s *RepositorySuite) TestTags(c *C) {
tags.ForEach(func(tag *plumbing.Reference) error {
count++
c.Assert(tag.Hash().IsZero(), Equals, false)
- c.Assert(tag.IsTag(), Equals, true)
+ c.Assert(tag.Name().IsTag(), Equals, true)
return nil
})
@@ -944,7 +972,7 @@ func (s *RepositorySuite) TestBranches(c *C) {
branches.ForEach(func(branch *plumbing.Reference) error {
count++
c.Assert(branch.Hash().IsZero(), Equals, false)
- c.Assert(branch.IsBranch(), Equals, true)
+ c.Assert(branch.Name().IsBranch(), Equals, true)
return nil
})
@@ -968,7 +996,7 @@ func (s *RepositorySuite) TestNotes(c *C) {
notes.ForEach(func(note *plumbing.Reference) error {
count++
c.Assert(note.Hash().IsZero(), Equals, false)
- c.Assert(note.IsNote(), Equals, true)
+ c.Assert(note.Name().IsNote(), Equals, true)
return nil
})
diff --git a/storage/filesystem/config_test.go b/storage/filesystem/config_test.go
index 1b812e6..4226b33 100644
--- a/storage/filesystem/config_test.go
+++ b/storage/filesystem/config_test.go
@@ -5,6 +5,7 @@ import (
"os"
"github.com/src-d/go-git-fixtures"
+ "gopkg.in/src-d/go-git.v4/config"
"gopkg.in/src-d/go-git.v4/storage/filesystem/internal/dotgit"
. "gopkg.in/check.v1"
@@ -39,9 +40,8 @@ func (s *ConfigSuite) TestRemotes(c *C) {
c.Assert(remotes, HasLen, 1)
remote := remotes["origin"]
c.Assert(remote.Name, Equals, "origin")
- c.Assert(remote.URL, Equals, "https://github.com/git-fixtures/basic")
- c.Assert(remote.Fetch, HasLen, 1)
- c.Assert(remote.Fetch[0].String(), Equals, "+refs/heads/*:refs/remotes/origin/*")
+ c.Assert(remote.URLs, DeepEquals, []string{"https://github.com/git-fixtures/basic"})
+ c.Assert(remote.Fetch, DeepEquals, []config.RefSpec{config.RefSpec("+refs/heads/*:refs/remotes/origin/*")})
}
func (s *ConfigSuite) TearDownTest(c *C) {
diff --git a/storage/test/storage_suite.go b/storage/test/storage_suite.go
index 624dc57..bf93515 100644
--- a/storage/test/storage_suite.go
+++ b/storage/test/storage_suite.go
@@ -351,7 +351,7 @@ func (s *BaseStorageSuite) TestSetConfigAndConfig(c *C) {
expected.Core.IsBare = true
expected.Remotes["foo"] = &config.RemoteConfig{
Name: "foo",
- URL: "http://foo/bar.git",
+ URLs: []string{"http://foo/bar.git"},
}
err := s.Storer.SetConfig(expected)
diff --git a/submodule.go b/submodule.go
index b5de41f..fd3d173 100644
--- a/submodule.go
+++ b/submodule.go
@@ -130,7 +130,7 @@ func (s *Submodule) Repository() (*Repository, error) {
_, err = r.CreateRemote(&config.RemoteConfig{
Name: DefaultRemoteName,
- URL: s.c.URL,
+ URLs: []string{s.c.URL},
})
return r, err
diff --git a/utils/merkletrie/noder/path.go b/utils/merkletrie/noder/path.go
index 85742db..d2e2932 100644
--- a/utils/merkletrie/noder/path.go
+++ b/utils/merkletrie/noder/path.go
@@ -3,6 +3,8 @@ package noder
import (
"bytes"
"strings"
+
+ "golang.org/x/text/unicode/norm"
)
// Path values represent a noder and its ancestors. The root goes first
@@ -78,7 +80,11 @@ func (p Path) Compare(other Path) int {
case i == len(p):
return -1
default:
- cmp := strings.Compare(p[i].Name(), other[i].Name())
+ form := norm.Form(norm.NFC)
+ this := form.String(p[i].Name())
+ that := form.String(other[i].Name())
+
+ cmp := strings.Compare(this, that)
if cmp != 0 {
return cmp
}
diff --git a/utils/merkletrie/noder/path_test.go b/utils/merkletrie/noder/path_test.go
index 44e3c3c..be25444 100644
--- a/utils/merkletrie/noder/path_test.go
+++ b/utils/merkletrie/noder/path_test.go
@@ -1,6 +1,9 @@
package noder
-import . "gopkg.in/check.v1"
+import (
+ "golang.org/x/text/unicode/norm"
+ . "gopkg.in/check.v1"
+)
type PathSuite struct{}
@@ -149,3 +152,10 @@ func (s *PathSuite) TestCompareMixedDepths(c *C) {
c.Assert(p1.Compare(p2), Equals, 1)
c.Assert(p2.Compare(p1), Equals, -1)
}
+
+func (s *PathSuite) TestCompareNormalization(c *C) {
+ p1 := Path([]Noder{&noderMock{name: norm.Form(norm.NFKC).String("페")}})
+ p2 := Path([]Noder{&noderMock{name: norm.Form(norm.NFKD).String("페")}})
+ c.Assert(p1.Compare(p2), Equals, 0)
+ c.Assert(p2.Compare(p1), Equals, 0)
+}
diff --git a/worktree.go b/worktree.go
index 60c8adb..4f8e740 100644
--- a/worktree.go
+++ b/worktree.go
@@ -209,7 +209,7 @@ func (w *Worktree) getCommitFromCheckoutOptions(opts *CheckoutOptions) (plumbing
return plumbing.ZeroHash, err
}
- if !b.IsTag() {
+ if !b.Name().IsTag() {
return b.Hash(), nil
}
@@ -244,7 +244,7 @@ func (w *Worktree) setHEADToBranch(branch plumbing.ReferenceName, commit plumbin
}
var head *plumbing.Reference
- if target.IsBranch() {
+ if target.Name().IsBranch() {
head = plumbing.NewSymbolicReference(plumbing.HEAD, target.Name())
} else {
head = plumbing.NewHashReference(plumbing.HEAD, commit)
@@ -323,7 +323,7 @@ func (w *Worktree) setHEADCommit(commit plumbing.Hash) error {
return err
}
- if !branch.IsBranch() {
+ if !branch.Name().IsBranch() {
return fmt.Errorf("invalid HEAD target should be a branch, found %s", branch.Type())
}
diff --git a/worktree_test.go b/worktree_test.go
index 10774a4..0a1c2d1 100644
--- a/worktree_test.go
+++ b/worktree_test.go
@@ -6,6 +6,9 @@ import (
"io/ioutil"
"os"
"path/filepath"
+ "runtime"
+
+ "golang.org/x/text/unicode/norm"
"gopkg.in/src-d/go-git.v4/config"
"gopkg.in/src-d/go-git.v4/plumbing"
@@ -37,7 +40,7 @@ func (s *WorktreeSuite) TestPullCheckout(c *C) {
r, _ := Init(memory.NewStorage(), fs)
r.CreateRemote(&config.RemoteConfig{
Name: DefaultRemoteName,
- URL: s.GetBasicLocalRepositoryURL(),
+ URLs: []string{s.GetBasicLocalRepositoryURL()},
})
w, err := r.Worktree()
@@ -115,7 +118,7 @@ func (s *WorktreeSuite) TestPullUpdateReferencesIfNeeded(c *C) {
r, _ := Init(memory.NewStorage(), memfs.New())
r.CreateRemote(&config.RemoteConfig{
Name: DefaultRemoteName,
- URL: s.GetBasicLocalRepositoryURL(),
+ URLs: []string{s.GetBasicLocalRepositoryURL()},
})
err := r.Fetch(&FetchOptions{})
@@ -173,7 +176,7 @@ func (s *WorktreeSuite) TestPullProgress(c *C) {
r.CreateRemote(&config.RemoteConfig{
Name: DefaultRemoteName,
- URL: s.GetBasicLocalRepositoryURL(),
+ URLs: []string{s.GetBasicLocalRepositoryURL()},
})
w, err := r.Worktree()
@@ -198,7 +201,7 @@ func (s *WorktreeSuite) TestPullProgressWithRecursion(c *C) {
r, _ := PlainInit(dir, false)
r.CreateRemote(&config.RemoteConfig{
Name: DefaultRemoteName,
- URL: path,
+ URLs: []string{path},
})
w, err := r.Worktree()
@@ -276,6 +279,10 @@ func (s *WorktreeSuite) TestCheckout(c *C) {
}
func (s *WorktreeSuite) TestCheckoutSymlink(c *C) {
+ if runtime.GOOS == "windows" {
+ c.Skip("git doesn't support symlinks by default in windows")
+ }
+
dir, err := ioutil.TempDir("", "checkout")
defer os.RemoveAll(dir)
@@ -304,6 +311,47 @@ func (s *WorktreeSuite) TestCheckoutSymlink(c *C) {
c.Assert(err, IsNil)
}
+func (s *WorktreeSuite) TestFilenameNormalization(c *C) {
+ url := c.MkDir()
+ path := fixtures.Basic().ByTag("worktree").One().Worktree().Root()
+
+ server, err := PlainClone(url, false, &CloneOptions{
+ URL: path,
+ })
+
+ filename := "페"
+
+ w, err := server.Worktree()
+ c.Assert(err, IsNil)
+ util.WriteFile(w.Filesystem, filename, []byte("foo"), 0755)
+ _, err = w.Add(filename)
+ c.Assert(err, IsNil)
+ _, err = w.Commit("foo", &CommitOptions{Author: defaultSignature()})
+ c.Assert(err, IsNil)
+
+ r, err := Clone(memory.NewStorage(), memfs.New(), &CloneOptions{
+ URL: url,
+ })
+
+ w, err = r.Worktree()
+ c.Assert(err, IsNil)
+
+ status, err := w.Status()
+ c.Assert(err, IsNil)
+ c.Assert(status.IsClean(), Equals, true)
+
+ err = w.Filesystem.Remove(filename)
+ c.Assert(err, IsNil)
+
+ modFilename := norm.Form(norm.NFKD).String(filename)
+ util.WriteFile(w.Filesystem, modFilename, []byte("foo"), 0755)
+ _, err = w.Add(filename)
+
+ status, err = w.Status()
+ c.Assert(err, IsNil)
+ c.Assert(status.IsClean(), Equals, true)
+}
+
func (s *WorktreeSuite) TestCheckoutSubmodule(c *C) {
url := "https://github.com/git-fixtures/submodule.git"
r := s.NewRepositoryWithEmptyWorktree(fixtures.ByURL(url).One())
@@ -387,10 +435,12 @@ func (s *WorktreeSuite) TestCheckoutIndexOS(c *C) {
c.Assert(idx.Entries[0].Size, Equals, uint32(189))
c.Assert(idx.Entries[0].CreatedAt.IsZero(), Equals, false)
- c.Assert(idx.Entries[0].Dev, Not(Equals), uint32(0))
- c.Assert(idx.Entries[0].Inode, Not(Equals), uint32(0))
- c.Assert(idx.Entries[0].UID, Not(Equals), uint32(0))
- c.Assert(idx.Entries[0].GID, Not(Equals), uint32(0))
+ if runtime.GOOS != "windows" {
+ c.Assert(idx.Entries[0].Dev, Not(Equals), uint32(0))
+ c.Assert(idx.Entries[0].Inode, Not(Equals), uint32(0))
+ c.Assert(idx.Entries[0].UID, Not(Equals), uint32(0))
+ c.Assert(idx.Entries[0].GID, Not(Equals), uint32(0))
+ }
}
func (s *WorktreeSuite) TestCheckoutBranch(c *C) {