@@ -453,3 +453,79 @@ def test_clone_legacy_strips_ref_prefixes(
453453
454454 mock_clone .assert_called_once ()
455455 mock_checkout .assert_called_once_with (expected_checkout , target )
456+
457+
458+ @pytest .mark .skip_git_mock
459+ def test_clone_with_lfs_files (tmp_path : Path ) -> None :
460+ """Test cloning a repository with Git LFS files (issue #8723)."""
461+ from dulwich import porcelain
462+ from dulwich .lfs import LFSStore
463+
464+ # Create a source repository with LFS support
465+ source_path = tmp_path / "source-repo"
466+ source_path .mkdir ()
467+ repo = Repo .init (str (source_path ))
468+
469+ # Set up LFS in the repository
470+ lfs_dir = source_path / ".git" / "lfs"
471+ lfs_dir .mkdir (parents = True )
472+ lfs_store = LFSStore .create (str (lfs_dir ))
473+
474+ # Configure .gitattributes to track large files with LFS
475+ gitattributes = source_path / ".gitattributes"
476+ gitattributes .write_text ("*.bin filter=lfs diff=lfs merge=lfs -text\n " )
477+ porcelain .add (repo , str (gitattributes ))
478+
479+ # Create a regular file
480+ regular_file = source_path / "regular.txt"
481+ regular_file .write_text ("This is a regular file" )
482+ porcelain .add (repo , str (regular_file ))
483+
484+ # Create an LFS file with a pointer
485+ lfs_content = b"This is a large binary file content for LFS storage"
486+ lfs_file = source_path / "large.bin"
487+
488+ # Store the actual content in LFS store and create pointer
489+ lfs_object_id = lfs_store .write_object ([lfs_content ])
490+ lfs_pointer = (
491+ f"version https://git-lfs.github.com/spec/v1\n "
492+ f"oid sha256:{ lfs_object_id } \n "
493+ f"size { len (lfs_content )} \n "
494+ )
495+ lfs_file .write_text (lfs_pointer )
496+ porcelain .add (repo , str (lfs_file ))
497+
498+ # Commit the files
499+ porcelain .commit (
500+ repo ,
501+ message = b"Add files with LFS support" ,
502+ author = b"Test <test@example.com>" ,
503+ committer = b"Test <test@example.com>" ,
504+ )
505+
506+ # Clone the repository
507+ source_root_dir = tmp_path / "clone-root"
508+ source_root_dir .mkdir ()
509+ Git .clone (
510+ url = source_path .as_uri (),
511+ source_root = source_root_dir ,
512+ name = "clone-test" ,
513+ )
514+
515+ # Verify the clone succeeded
516+ clone_dir = source_root_dir / "clone-test"
517+ assert (clone_dir / ".git" ).is_dir ()
518+
519+ # Verify regular file is present
520+ assert (clone_dir / "regular.txt" ).exists ()
521+ assert (clone_dir / "regular.txt" ).read_text () == "This is a regular file"
522+
523+ # Verify .gitattributes is present
524+ assert (clone_dir / ".gitattributes" ).exists ()
525+ assert "filter=lfs" in (clone_dir / ".gitattributes" ).read_text ()
526+
527+ # Verify LFS file is present with actual content (not just pointer)
528+ # The LFS system should automatically retrieve the actual content
529+ assert (clone_dir / "large.bin" ).exists ()
530+ lfs_file_content = (clone_dir / "large.bin" ).read_bytes ()
531+ assert lfs_file_content == lfs_content
0 commit comments