`. There exists a default stream
+ // type for directories, allowing `.git/` to be accessed via
+ // `.git::$INDEX_ALLOCATION/`.
+ //
+ // For performance reasons, _all_ Alternate Data Streams of `.git/` are
+ // forbidden, not just `::$INDEX_ALLOCATION`.
+ if len(part) > 4 && part[4:5] == ":" {
+ return false
+ }
+ }
+ return true
+}
+
+func (w *Worktree) validChange(ch merkletrie.Change) error {
+ action, err := ch.Action()
+ if err != nil {
+ return nil
+ }
+
+ switch action {
+ case merkletrie.Delete:
+ return validPath(ch.From.String())
+ case merkletrie.Insert:
+ return validPath(ch.To.String())
+ case merkletrie.Modify:
+ return validPath(ch.From.String(), ch.To.String())
+ }
+
+ return nil
+}
+
func (w *Worktree) checkoutChange(ch merkletrie.Change, t *object.Tree, idx *indexBuilder) error {
a, err := ch.Action()
if err != nil {
@@ -561,6 +677,11 @@ func (w *Worktree) checkoutFile(f *object.File) (err error) {
}
func (w *Worktree) checkoutFileSymlink(f *object.File) (err error) {
+ // https://github.com/git/git/commit/10ecfa76491e4923988337b2e2243b05376b40de
+ if strings.EqualFold(f.Name, gitmodulesFile) {
+ return ErrGitModulesSymlink
+ }
+
from, err := f.Reader()
if err != nil {
return
diff --git a/worktree_test.go b/worktree_test.go
index c69c61717..50ff189fa 100644
--- a/worktree_test.go
+++ b/worktree_test.go
@@ -4,6 +4,7 @@ import (
"bytes"
"context"
"errors"
+ "fmt"
"io"
"os"
"path/filepath"
@@ -16,11 +17,14 @@ import (
fixtures "github.com/go-git/go-git-fixtures/v4"
"github.com/go-git/go-git/v5/config"
"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/filemode"
"github.com/go-git/go-git/v5/plumbing/format/gitignore"
"github.com/go-git/go-git/v5/plumbing/format/index"
"github.com/go-git/go-git/v5/plumbing/object"
+ "github.com/go-git/go-git/v5/storage/filesystem"
"github.com/go-git/go-git/v5/storage/memory"
+ "github.com/stretchr/testify/assert"
"github.com/go-git/go-billy/v5/memfs"
"github.com/go-git/go-billy/v5/osfs"
@@ -299,6 +303,56 @@ func (s *WorktreeSuite) TestPullAlreadyUptodate(c *C) {
c.Assert(err, Equals, NoErrAlreadyUpToDate)
}
+func (s *WorktreeSuite) TestPullDepth(c *C) {
+ r, err := Clone(memory.NewStorage(), memfs.New(), &CloneOptions{
+ URL: fixtures.Basic().One().URL,
+ Depth: 1,
+ })
+
+ c.Assert(err, IsNil)
+
+ w, err := r.Worktree()
+ c.Assert(err, IsNil)
+ err = w.Pull(&PullOptions{})
+ c.Assert(err, Equals, nil)
+}
+
+func (s *WorktreeSuite) TestPullAfterShallowClone(c *C) {
+ tempDir, clean := s.TemporalDir()
+ defer clean()
+ remoteURL := filepath.Join(tempDir, "remote")
+ repoDir := filepath.Join(tempDir, "repo")
+
+ remote, err := PlainInit(remoteURL, false)
+ c.Assert(err, IsNil)
+ c.Assert(remote, NotNil)
+
+ _ = CommitNewFile(c, remote, "File1")
+ _ = CommitNewFile(c, remote, "File2")
+
+ repo, err := PlainClone(repoDir, false, &CloneOptions{
+ URL: remoteURL,
+ Depth: 1,
+ Tags: NoTags,
+ SingleBranch: true,
+ ReferenceName: "master",
+ })
+ c.Assert(err, IsNil)
+
+ _ = CommitNewFile(c, remote, "File3")
+ _ = CommitNewFile(c, remote, "File4")
+
+ w, err := repo.Worktree()
+ c.Assert(err, IsNil)
+
+ err = w.Pull(&PullOptions{
+ RemoteName: DefaultRemoteName,
+ SingleBranch: true,
+ ReferenceName: plumbing.NewBranchReferenceName("master"),
+ })
+ c.Assert(err, IsNil)
+}
+
func (s *WorktreeSuite) TestCheckout(c *C) {
fs := memfs.New()
w := &Worktree{
@@ -771,6 +825,30 @@ func (s *WorktreeSuite) TestCheckoutCreateMissingBranch(c *C) {
c.Assert(err, Equals, ErrCreateRequiresBranch)
}
+func (s *WorktreeSuite) TestCheckoutCreateInvalidBranch(c *C) {
+ w := &Worktree{
+ r: s.Repository,
+ Filesystem: memfs.New(),
+ }
+
+ for _, name := range []plumbing.ReferenceName{
+ "foo",
+ "-",
+ "-foo",
+ "refs/heads//",
+ "refs/heads/..",
+ "refs/heads/a..b",
+ "refs/heads/.",
+ } {
+ err := w.Checkout(&CheckoutOptions{
+ Create: true,
+ Branch: name,
+ })
+
+ c.Assert(err, Equals, plumbing.ErrInvalidReferenceName)
+ }
+}
+
func (s *WorktreeSuite) TestCheckoutTag(c *C) {
f := fixtures.ByTag("tags").One()
r := s.NewRepositoryWithEmptyWorktree(f)
@@ -903,7 +981,7 @@ func (s *WorktreeSuite) TestStatusCheckedInBeforeIgnored(c *C) {
c.Assert(status.IsClean(), Equals, true)
c.Assert(status, NotNil)
- err = util.WriteFile(fs, "secondIgnoredFile", []byte("Should be completly ignored"), 0755)
+ err = util.WriteFile(fs, "secondIgnoredFile", []byte("Should be completely ignored"), 0755)
c.Assert(err, IsNil)
status = nil
status, err = w.Status()
@@ -2124,34 +2202,40 @@ func (s *WorktreeSuite) TestCleanBare(c *C) {
c.Assert(err, IsNil)
}
-func (s *WorktreeSuite) TestAlternatesRepo(c *C) {
+func TestAlternatesRepo(t *testing.T) {
fs := fixtures.ByTag("alternates").One().Worktree()
// Open 1st repo.
rep1fs, err := fs.Chroot("rep1")
- c.Assert(err, IsNil)
+ assert.NoError(t, err)
rep1, err := PlainOpen(rep1fs.Root())
- c.Assert(err, IsNil)
+ assert.NoError(t, err)
// Open 2nd repo.
rep2fs, err := fs.Chroot("rep2")
- c.Assert(err, IsNil)
- rep2, err := PlainOpen(rep2fs.Root())
- c.Assert(err, IsNil)
+ assert.NoError(t, err)
+ d, _ := rep2fs.Chroot(GitDirName)
+ storer := filesystem.NewStorageWithOptions(d,
+ cache.NewObjectLRUDefault(), filesystem.Options{
+ AlternatesFS: fs,
+ })
+ rep2, err := Open(storer, rep2fs)
+
+ assert.NoError(t, err)
// Get the HEAD commit from the main repo.
h, err := rep1.Head()
- c.Assert(err, IsNil)
+ assert.NoError(t, err)
commit1, err := rep1.CommitObject(h.Hash())
- c.Assert(err, IsNil)
+ assert.NoError(t, err)
// Get the HEAD commit from the shared repo.
h, err = rep2.Head()
- c.Assert(err, IsNil)
+ assert.NoError(t, err)
commit2, err := rep2.CommitObject(h.Hash())
- c.Assert(err, IsNil)
+ assert.NoError(t, err)
- c.Assert(commit1.String(), Equals, commit2.String())
+ assert.Equal(t, commit1.String(), commit2.String())
}
func (s *WorktreeSuite) TestGrep(c *C) {
@@ -2664,3 +2748,77 @@ func (s *WorktreeSuite) TestLinkedWorktree(c *C) {
c.Assert(err, Equals, ErrRepositoryIncomplete)
}
}
+
+func TestValidPath(t *testing.T) {
+ type testcase struct {
+ path string
+ wantErr bool
+ }
+
+ tests := []testcase{
+ {".git", true},
+ {".git/b", true},
+ {".git\\b", true},
+ {"git~1", true},
+ {"a/../b", true},
+ {"a\\..\\b", true},
+ {".gitmodules", false},
+ {".gitignore", false},
+ {"a..b", false},
+ {".", false},
+ {"a/.git", false},
+ {"a\\.git", false},
+ {"a/.git/b", false},
+ {"a\\.git\\b", false},
+ }
+
+ if runtime.GOOS == "windows" {
+ tests = append(tests, []testcase{
+ {"\\\\a\\b", true},
+ {"C:\\a\\b", true},
+ {".git . . .", true},
+ {".git . . ", true},
+ {".git ", true},
+ {".git.", true},
+ {".git::$INDEX_ALLOCATION", true},
+ }...)
+ }
+
+ for _, tc := range tests {
+ t.Run(fmt.Sprintf("%s", tc.path), func(t *testing.T) {
+ err := validPath(tc.path)
+ if tc.wantErr {
+ assert.Error(t, err)
+ } else {
+ assert.NoError(t, err)
+ }
+ })
+ }
+}
+
+func TestWindowsValidPath(t *testing.T) {
+ tests := []struct {
+ path string
+ want bool
+ }{
+ {".git", false},
+ {".git . . .", false},
+ {".git ", false},
+ {".git ", false},
+ {".git . .", false},
+ {".git . .", false},
+ {".git::$INDEX_ALLOCATION", false},
+ {".git:", false},
+ {"a", true},
+ {"a\\b", true},
+ {"a/b", true},
+ {".gitm", true},
+ }
+
+ for _, tc := range tests {
+ t.Run(fmt.Sprintf("%s", tc.path), func(t *testing.T) {
+ got := windowsValidPath(tc.path)
+ assert.Equal(t, tc.want, got)
+ })
+ }
+}
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy