@@ -1020,6 +1020,35 @@ impl Repository {
1020
1020
Ok ( Oid :: from_raw ( & raw ) )
1021
1021
}
1022
1022
}
1023
+
1024
+ /// Count the number of unique commits between two commit objects
1025
+ ///
1026
+ /// There is no need for branches containing the commits to have any
1027
+ /// upstream relationship, but it helps to think of one as a branch and the
1028
+ /// other as its upstream, the ahead and behind values will be what git
1029
+ /// would report for the branches.
1030
+ pub fn graph_ahead_behind ( & self , local : Oid , upstream : Oid )
1031
+ -> Result < ( uint , uint ) , Error > {
1032
+ unsafe {
1033
+ let mut ahead: size_t = 0 ;
1034
+ let mut behind: size_t = 0 ;
1035
+ try_call ! ( raw:: git_graph_ahead_behind( & mut ahead, & mut behind,
1036
+ self . raw( ) , local. raw( ) ,
1037
+ upstream. raw( ) ) ) ;
1038
+ Ok ( ( ahead as uint , behind as uint ) )
1039
+ }
1040
+ }
1041
+
1042
+ /// Determine if a commit is the descendant of another commit
1043
+ pub fn graph_descendant_of ( & self , commit : Oid , ancestor : Oid )
1044
+ -> Result < bool , Error > {
1045
+ unsafe {
1046
+ let rv = try_call ! ( raw:: git_graph_descendant_of( self . raw( ) ,
1047
+ commit. raw( ) ,
1048
+ ancestor. raw( ) ) ) ;
1049
+ Ok ( rv != 0 )
1050
+ }
1051
+ }
1023
1052
}
1024
1053
1025
1054
#[ unsafe_destructor]
@@ -1269,4 +1298,49 @@ mod tests {
1269
1298
let repo = Repository :: discover ( subdir. path ( ) ) . unwrap ( ) ;
1270
1299
assert ! ( repo. path( ) == * td. path( ) ) ;
1271
1300
}
1301
+
1302
+ fn graph_repo_init ( ) -> ( TempDir , Repository ) {
1303
+ let ( _td, repo) = :: test:: repo_init ( ) ;
1304
+ {
1305
+ let head = repo. head ( ) . unwrap ( ) . target ( ) . unwrap ( ) ;
1306
+ let head = repo. find_commit ( head) . unwrap ( ) ;
1307
+
1308
+ let mut index = repo. index ( ) . unwrap ( ) ;
1309
+ let id = index. write_tree ( ) . unwrap ( ) ;
1310
+
1311
+ let tree = repo. find_tree ( id) . unwrap ( ) ;
1312
+ let sig = repo. signature ( ) . unwrap ( ) ;
1313
+ repo. commit ( Some ( "HEAD" ) , & sig, & sig, "second" ,
1314
+ & tree, & [ & head] ) . unwrap ( ) ;
1315
+ }
1316
+ ( _td, repo)
1317
+ }
1318
+
1319
+ #[ test]
1320
+ fn smoke_graph_ahead_behind ( ) {
1321
+ let ( _td, repo) = graph_repo_init ( ) ;
1322
+ let head = repo. head ( ) . unwrap ( ) . target ( ) . unwrap ( ) ;
1323
+ let head = repo. find_commit ( head) . unwrap ( ) ;
1324
+ let head_id = head. id ( ) ;
1325
+ let head_parent_id = head. parent ( 0 ) . unwrap ( ) . id ( ) ;
1326
+ let ( ahead, behind) = repo. graph_ahead_behind ( head_id,
1327
+ head_parent_id) . unwrap ( ) ;
1328
+ assert_eq ! ( ahead, 1 ) ;
1329
+ assert_eq ! ( behind, 0 ) ;
1330
+ let ( ahead, behind) = repo. graph_ahead_behind ( head_parent_id,
1331
+ head_id) . unwrap ( ) ;
1332
+ assert_eq ! ( ahead, 0 ) ;
1333
+ assert_eq ! ( behind, 1 ) ;
1334
+ }
1335
+
1336
+ #[ test]
1337
+ fn smoke_graph_descendant_of ( ) {
1338
+ let ( _td, repo) = graph_repo_init ( ) ;
1339
+ let head = repo. head ( ) . unwrap ( ) . target ( ) . unwrap ( ) ;
1340
+ let head = repo. find_commit ( head) . unwrap ( ) ;
1341
+ let head_id = head. id ( ) ;
1342
+ let head_parent_id = head. parent ( 0 ) . unwrap ( ) . id ( ) ;
1343
+ assert ! ( repo. graph_descendant_of( head_id, head_parent_id) . unwrap( ) ) ;
1344
+ assert ! ( !repo. graph_descendant_of( head_parent_id, head_id) . unwrap( ) ) ;
1345
+ }
1272
1346
}
0 commit comments