From c3c841090facce33faa2c80ca475ee673442b4a5 Mon Sep 17 00:00:00 2001 From: Paulo Gomes Date: Mon, 14 Apr 2025 18:05:46 +0100 Subject: [PATCH 1/2] Merge pull request #1492 from onee-only/fix-sparse-checkout-status utils: merkletrie, Fix diff on sparse-checkout index. Fixes #1406 --- utils/merkletrie/change.go | 4 +++- utils/merkletrie/difftree.go | 43 +++++++++++++++++------------------- worktree_test.go | 17 ++++++++++++++ 3 files changed, 40 insertions(+), 24 deletions(-) diff --git a/utils/merkletrie/change.go b/utils/merkletrie/change.go index 450feb4ba..562ff8902 100644 --- a/utils/merkletrie/change.go +++ b/utils/merkletrie/change.go @@ -131,7 +131,9 @@ func (l *Changes) addRecursive(root noder.Path, ctor noderToChangeFn) error { } if !root.IsDir() { - l.Add(ctor(root)) + if !root.Skip() { + l.Add(ctor(root)) + } return nil } diff --git a/utils/merkletrie/difftree.go b/utils/merkletrie/difftree.go index 4ef2d9907..7fc8d02d7 100644 --- a/utils/merkletrie/difftree.go +++ b/utils/merkletrie/difftree.go @@ -297,18 +297,16 @@ func DiffTreeContext(ctx context.Context, fromTree, toTree noder.Noder, case noMoreNoders: return ret, nil case onlyFromRemains: - if err = ret.AddRecursiveDelete(from); err != nil { - return nil, err + if !from.Skip() { + if err = ret.AddRecursiveDelete(from); err != nil { + return nil, err + } } if err = ii.nextFrom(); err != nil { return nil, err } case onlyToRemains: - if to.Skip() { - if err = ret.AddRecursiveDelete(to); err != nil { - return nil, err - } - } else { + if !to.Skip() { if err = ret.AddRecursiveInsert(to); err != nil { return nil, err } @@ -317,26 +315,25 @@ func DiffTreeContext(ctx context.Context, fromTree, toTree noder.Noder, return nil, err } case bothHaveNodes: - if from.Skip() { - if err = ret.AddRecursiveDelete(from); err != nil { - return nil, err - } - if err := ii.nextBoth(); err != nil { - return nil, err + var err error + switch { + case from.Skip(): + if from.Name() == to.Name() { + err = ii.nextBoth() + } else { + err = ii.nextFrom() } - break - } - if to.Skip() { - if err = ret.AddRecursiveDelete(to); err != nil { - return nil, err - } - if err := ii.nextBoth(); err != nil { - return nil, err + case to.Skip(): + if from.Name() == to.Name() { + err = ii.nextBoth() + } else { + err = ii.nextTo() } - break + default: + err = diffNodes(&ret, ii) } - if err = diffNodes(&ret, ii); err != nil { + if err != nil { return nil, err } default: diff --git a/worktree_test.go b/worktree_test.go index a3dbcfeb3..db2fd7cde 100644 --- a/worktree_test.go +++ b/worktree_test.go @@ -1359,7 +1359,24 @@ func (s *WorktreeSuite) TestStatusAfterCheckout(c *C) { status, err := w.Status() c.Assert(err, IsNil) c.Assert(status.IsClean(), Equals, true) +} + +func (s *WorktreeSuite) TestStatusAfterSparseCheckout(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + err := w.Checkout(&CheckoutOptions{ + SparseCheckoutDirectories: []string{"php"}, + Force: true, + }) + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, true) } func (s *WorktreeSuite) TestStatusModified(c *C) { From 4f35ebab20f1034df1df943044903e7044e6cdf4 Mon Sep 17 00:00:00 2001 From: Paulo Gomes Date: Sun, 13 Apr 2025 16:48:21 +0100 Subject: [PATCH 2/2] Merge pull request #1484 from patricsss/patricsss/fix-1455 utils: fix diff so subpaths work for sparse checkouts, fixes 1455 --- utils/merkletrie/change.go | 2 +- utils/merkletrie/index/node.go | 10 ++++++++- utils/merkletrie/index/node_test.go | 34 +++++++++++++++++++++++++---- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/utils/merkletrie/change.go b/utils/merkletrie/change.go index 562ff8902..d32b5a7d4 100644 --- a/utils/merkletrie/change.go +++ b/utils/merkletrie/change.go @@ -150,7 +150,7 @@ func (l *Changes) addRecursive(root noder.Path, ctor noderToChangeFn) error { } return err } - if current.IsDir() { + if current.IsDir() || current.Skip() { continue } l.Add(ctor(current)) diff --git a/utils/merkletrie/index/node.go b/utils/merkletrie/index/node.go index c1809f7ec..5bc63f8b2 100644 --- a/utils/merkletrie/index/node.go +++ b/utils/merkletrie/index/node.go @@ -36,7 +36,15 @@ func NewRootNode(idx *index.Index) noder.Noder { parent := fullpath fullpath = path.Join(fullpath, part) - if _, ok := m[fullpath]; ok { + // It's possible that the first occurrence of subdirectory is skipped. + // The parent node can be created with SkipWorktree set to true, but + // if any future children do not skip their subtree, the entire lineage + // of the tree needs to have this value set to false so that subdirectories + // are not ignored. + if parentNode, ok := m[fullpath]; ok { + if e.SkipWorktree == false { + parentNode.skip = false + } continue } diff --git a/utils/merkletrie/index/node_test.go b/utils/merkletrie/index/node_test.go index cc5600dcb..53f8a9f45 100644 --- a/utils/merkletrie/index/node_test.go +++ b/utils/merkletrie/index/node_test.go @@ -2,7 +2,7 @@ package index import ( "bytes" - "path/filepath" + "path" "testing" "github.com/go-git/go-git/v5/plumbing" @@ -46,14 +46,14 @@ func (s *NoderSuite) TestDiff(c *C) { func (s *NoderSuite) TestDiffChange(c *C) { indexA := &index.Index{ Entries: []*index.Entry{{ - Name: filepath.Join("bar", "baz", "bar"), + Name: path.Join("bar", "baz", "bar"), Hash: plumbing.NewHash("8ab686eafeb1f44702738c8b0f24f2567c36da6d"), }}, } indexB := &index.Index{ Entries: []*index.Entry{{ - Name: filepath.Join("bar", "baz", "foo"), + Name: path.Join("bar", "baz", "foo"), Hash: plumbing.NewHash("8ab686eafeb1f44702738c8b0f24f2567c36da6d"), }}, } @@ -63,6 +63,32 @@ func (s *NoderSuite) TestDiffChange(c *C) { c.Assert(ch, HasLen, 2) } +func (s *NoderSuite) TestDiffSkipIssue1455(c *C) { + indexA := &index.Index{ + Entries: []*index.Entry{ + { + Name: path.Join("bar", "baz", "bar"), + Hash: plumbing.NewHash("8ab686eafeb1f44702738c8b0f24f2567c36da6d"), + SkipWorktree: true, + }, + { + Name: path.Join("bar", "biz", "bat"), + Hash: plumbing.NewHash("8ab686eafeb1f44702738c8b0f24f2567c36da6d"), + SkipWorktree: false, + }, + }, + } + + indexB := &index.Index{} + + ch, err := merkletrie.DiffTree(NewRootNode(indexB), NewRootNode(indexA), isEquals) + c.Assert(err, IsNil) + c.Assert(ch, HasLen, 1) + a, err := ch[0].Action() + c.Assert(err, IsNil) + c.Assert(a, Equals, merkletrie.Insert) +} + func (s *NoderSuite) TestDiffDir(c *C) { indexA := &index.Index{ Entries: []*index.Entry{{ @@ -73,7 +99,7 @@ func (s *NoderSuite) TestDiffDir(c *C) { indexB := &index.Index{ Entries: []*index.Entry{{ - Name: filepath.Join("foo", "bar"), + Name: path.Join("foo", "bar"), Hash: plumbing.NewHash("8ab686eafeb1f44702738c8b0f24f2567c36da6d"), }}, }