pr-git-2380/vladpetric/vp/reflink-copy-v1
tagged this
11 Aug 15:03
From: Vlad Petric <vlad@drpetric.com> Git currently copies files byte-for-byte through copy_file(). Local clones separately try to hardlink object files before falling back to copying them. On filesystems that support copy-on-write cloning, a reflink can share the underlying storage without making the source and destination names refer to the same inode. This provides most of the space and I/O benefits of hardlinks while allowing either file to be replaced or modified independently. On Linux, try FICLONE before performing a byte-for-byte copy. Treat reflinking as an optimization: if the ioctl is unavailable or fails, remove the partial destination and use the existing copy path. For local clones, try a reflink before the existing hardlink path. The resulting order is therefore: - reflink; - hardlink, unless --no-hardlinks was requested; - byte-for-byte copy. Preserve source timestamps when reflinking local object files. This matches the previous hardlink and copy behavior and is important for the expiry decisions made by prune and gc. Add an LD_PRELOAD-based test helper that can force FICLONE to succeed, report EOPNOTSUPP, or report another error. This exercises the reflink and fallback paths even when the test filesystem does not support reflinks. Cover generic file copying, local clones, --no-hardlinks, hardlink fallback, byte-copy fallback, object integrity, and timestamp preservation. The focused tests pass on three independent filesystems: - ZFS at /home; - ext4 at /tmp; - tmpfs at /dev/shm. The complete Git test suite also passes on all three filesystems with no unexpected failures. Signed-off-by: Vlad Petric <vlad@drpetric.com> Submitted-As: https://lore.kernel.org/git/pull.2380.git.git.1786460606222.gitgitgadget@gmail.com