@@ -1232,6 +1232,20 @@ impl Repository {
12321232 Ok ( ( ) )
12331233 }
12341234
1235+ /// Suggests that the reference database compress or optimize its
1236+ /// references. This mechanism is implementation specific. For on-disk
1237+ /// reference databases, for example, this may pack all loose references.
1238+ pub fn refdb_compress ( & self ) -> Result < ( ) , Error > {
1239+ let mut refdb = ptr:: null_mut ( ) ;
1240+ unsafe {
1241+ try_call ! ( raw:: git_repository_refdb( & mut refdb, self . raw( ) ) ) ;
1242+ let result = crate :: call:: c_try ( raw:: git_refdb_compress ( refdb) ) ;
1243+ raw:: git_refdb_free ( refdb) ;
1244+ result?;
1245+ }
1246+ Ok ( ( ) )
1247+ }
1248+
12351249 /// Create a new branch pointing at a target commit
12361250 ///
12371251 /// A new direct reference will be created pointing to this target commit.
@@ -4557,4 +4571,64 @@ Committer Name <committer.proper@email> <committer@email>"#,
45574571 crate :: test:: realpath( worktree_repo. commondir( ) ) . unwrap( )
45584572 ) ;
45594573 }
4574+
4575+ #[ test]
4576+ fn smoke_refdb_compress ( ) {
4577+ let ( _td, repo) = crate :: test:: repo_init ( ) ;
4578+ // Compressing an empty-ish refdb should succeed.
4579+ repo. refdb_compress ( ) . unwrap ( ) ;
4580+ }
4581+
4582+ #[ test]
4583+ fn refdb_compress_with_loose_refs ( ) {
4584+ let ( _td, repo) = crate :: test:: repo_init ( ) ;
4585+ let head_id = repo. refname_to_id ( "HEAD" ) . unwrap ( ) ;
4586+
4587+ // Create several loose refs.
4588+ for i in 0 ..20 {
4589+ repo. reference ( & format ! ( "refs/tags/test-{}" , i) , head_id, false , "test ref" )
4590+ . unwrap ( ) ;
4591+ }
4592+
4593+ // Verify refs exist.
4594+ assert ! ( repo. references_glob( "refs/tags/test-*" ) . unwrap( ) . count( ) == 20 ) ;
4595+
4596+ // Compress should pack them without error.
4597+ repo. refdb_compress ( ) . unwrap ( ) ;
4598+
4599+ // Refs should still be resolvable after packing.
4600+ assert ! ( repo. references_glob( "refs/tags/test-*" ) . unwrap( ) . count( ) == 20 ) ;
4601+ for i in 0 ..20 {
4602+ let r = repo
4603+ . find_reference ( & format ! ( "refs/tags/test-{}" , i) )
4604+ . unwrap ( ) ;
4605+ assert_eq ! ( r. target( ) . unwrap( ) , head_id) ;
4606+ }
4607+ }
4608+
4609+ #[ test]
4610+ fn refdb_compress_bare_repo ( ) {
4611+ let td = TempDir :: new ( ) . unwrap ( ) ;
4612+ let repo = Repository :: init_bare ( td. path ( ) ) . unwrap ( ) ;
4613+ // Compressing a bare repo with no refs should succeed.
4614+ repo. refdb_compress ( ) . unwrap ( ) ;
4615+ }
4616+
4617+ #[ test]
4618+ fn refdb_compress_idempotent ( ) {
4619+ let ( _td, repo) = crate :: test:: repo_init ( ) ;
4620+ let head_id = repo. refname_to_id ( "HEAD" ) . unwrap ( ) ;
4621+
4622+ for i in 0 ..5 {
4623+ repo. reference ( & format ! ( "refs/tags/idem-{}" , i) , head_id, false , "test" )
4624+ . unwrap ( ) ;
4625+ }
4626+
4627+ // Compress multiple times — should be safe and idempotent.
4628+ repo. refdb_compress ( ) . unwrap ( ) ;
4629+ repo. refdb_compress ( ) . unwrap ( ) ;
4630+ repo. refdb_compress ( ) . unwrap ( ) ;
4631+
4632+ assert ! ( repo. references_glob( "refs/tags/idem-*" ) . unwrap( ) . count( ) == 5 ) ;
4633+ }
45604634}
0 commit comments