Skip to content

feat: add directory-level CoW copy for faster worktree creation#163

Open
ryoppippi wants to merge 2 commits into
k1LoW:mainfrom
ryoppippi:feat/directory-level-cow-copy
Open

feat: add directory-level CoW copy for faster worktree creation#163
ryoppippi wants to merge 2 commits into
k1LoW:mainfrom
ryoppippi:feat/directory-level-cow-copy

Conversation

@ryoppippi
Copy link
Copy Markdown
Contributor

Summary

  • Add directory-level copy support (copyDir) that copies entire directories in one operation instead of file-by-file
  • macOS: Use clonefile(2) on directories for instant APFS CoW clones, with fallback to recursive file-by-file copy
  • Linux: Add FICLONE ioctl (via unix.IoctlFileClone) for CoW reflink on Btrfs/XFS, with fallback to io.Copy (which uses copy_file_range internally)
  • CopyFilesToWorktree now groups files by top-level directory and attempts directory-level copy when all files in that directory are being copied (no NoCopy exclusions apply)

Benchmark

On macOS (Apple M3 Pro, APFS) with a real 5.9GB node_modules (265K files, 40K directories):

Method Time Memory
copyDir (clonefile) ~21s 3.6 KB / 22 allocs
file-by-file copyFile ~85s 543 MB / 2.6M allocs

~4x faster, 150,000x less memory.

With a synthetic 2,500-file directory: ~12x faster (~31ms vs ~383ms).

Test plan

  • All existing copy tests pass
  • New tests: TestCopyDir, TestCopyDir_IndependentOfSource, TestCopyFilesToWorktree_DirectoryLevelCopy, TestCopyFilesToWorktree_DirectoryLevelCopy_WithNoCopy
  • Benchmarks: BenchmarkCopyDir_Small, BenchmarkCopyFileByFile_Small, BenchmarkCopyDir_RealNodeModules, BenchmarkCopyFileByFile_RealNodeModules (set BENCH_NODE_MODULES env var)
  • Full e2e test suite passes

Add directory-level copy support that dramatically speeds up copying
large directories like node_modules when creating new worktrees.

Platform-specific optimisations:

- macOS (APFS): Use clonefile(2) on entire directories for instant CoW
  clones, falling back to recursive file-by-file clonefile on failure.
- Linux: Add FICLONE ioctl support for CoW reflink on Btrfs/XFS,
  falling back to io.Copy (which uses copy_file_range internally).
- Other platforms: Recursive walk with io.Copy.

The copy logic now groups files by top-level directory and attempts a
single directory-level copy when all files within that directory are
being copied (no NoCopy exclusions). This avoids the overhead of
listing and copying hundreds of thousands of individual files.

Benchmark results on macOS (Apple M3 Pro) with a real 5.9GB
node_modules (265K files):

  copyDir (clonefile):  ~21s, 3.6 KB alloc
  file-by-file:         ~85s, 543 MB alloc

~4x faster with 150,000x less memory allocation.
- Add nolint:gosec annotations for internal copy functions (G703, G115)
- Use 0600 permissions in test WriteFile calls (G306)
- Fix LICENCE -> LICENSE spelling (misspell US locale)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant