Skip to content

Commit

Permalink
git/UpdateTree: Don't leave empty trees behind
Browse files Browse the repository at this point in the history
When all files from a tree are deleted,
delete the subtree from the parent tree
instead of leaving an empty entry behind.
This matches git's behavior.

[skip changelog]: no user-facing changes
  • Loading branch information
abhinav committed Dec 4, 2024
1 parent e1cb2a2 commit 62a57db
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 0 deletions.
9 changes: 9 additions & 0 deletions internal/git/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,15 @@ func (r *Repository) UpdateTree(ctx context.Context, req UpdateTreeRequest) (_ H
}
}

entries = update.Apply(entries)
if len(entries) == 0 {
// If the directory is empty, we don't need to create a tree.
// We can just delete the directory.
parent, base := pathSplit(dir)
ensureUpdate(parent).Delete(base)
continue
}

newHash, err := r.MakeTree(ctx, update.Apply(entries))
if err != nil {
return ZeroHash, fmt.Errorf("make tree: %w", err)
Expand Down
37 changes: 37 additions & 0 deletions internal/git/tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,41 @@ func TestIntegrationUpdateTree(t *testing.T) {
{Mode: git.RegularMode, Type: git.BlobType, Name: "qux/quux/qu", Hash: emptyFile},
}, ents)
})

// empty directories are pruned from the tree.
t.Run("clear empty dirs", func(t *testing.T) {
deletedHash, err := repo.UpdateTree(ctx, git.UpdateTreeRequest{
Tree: newHash,
Deletes: []string{"qux/quux/qu"},
})
require.NoError(t, err)

ents, err := repo.ListTree(ctx, deletedHash, git.ListTreeOptions{})
require.NoError(t, err)
assert.ElementsMatch(t, []git.TreeEntry{
{Mode: git.DirMode, Type: git.TreeType, Name: "bar", Hash: "94b2978d84f4cbb7449c092255b38a1e1b40da42"},
{Mode: git.RegularMode, Type: git.BlobType, Name: "foo", Hash: emptyFile},
}, ents)

ents, err = repo.ListTree(ctx, deletedHash, git.ListTreeOptions{
Recurse: true,
})
require.NoError(t, err)
assert.ElementsMatch(t, []git.TreeEntry{
{Mode: git.RegularMode, Type: git.BlobType, Name: "foo", Hash: emptyFile},
{Mode: git.RegularMode, Type: git.BlobType, Name: "bar/baz", Hash: emptyFile},
}, ents)
})

t.Run("delete all files", func(t *testing.T) {
deletedHash, err := repo.UpdateTree(ctx, git.UpdateTreeRequest{
Tree: newHash,
Deletes: []string{"foo", "bar/baz", "qux/quux/qu"},
})
require.NoError(t, err)

ents, err := repo.ListTree(ctx, deletedHash, git.ListTreeOptions{})
require.NoError(t, err)
assert.Empty(t, ents)
})
}

0 comments on commit 62a57db

Please sign in to comment.