@@ -45,6 +45,7 @@ impl GitGraph {
4545 settings : & Settings ,
4646 start_point : Option < String > ,
4747 max_count : Option < usize > ,
48+ refspecs : Vec < String > ,
4849 ) -> Result < Self , String > {
4950 #![ doc = include_str ! ( "../docs/branch_assignment.md" ) ]
5051 let mut stashes = HashSet :: new ( ) ;
@@ -62,17 +63,7 @@ impl GitGraph {
6263 walk. set_sorting ( git2:: Sort :: TOPOLOGICAL | git2:: Sort :: TIME )
6364 . map_err ( |err| err. message ( ) . to_string ( ) ) ?;
6465
65- // Use starting point if specified
66- if let Some ( start) = start_point {
67- let object = repository
68- . revparse_single ( & start)
69- . map_err ( |err| format ! ( "Failed to resolve start point '{}': {}" , start, err) ) ?;
70- walk. push ( object. id ( ) )
71- . map_err ( |err| err. message ( ) . to_string ( ) ) ?;
72- } else {
73- walk. push_glob ( "*" )
74- . map_err ( |err| err. message ( ) . to_string ( ) ) ?;
75- }
66+ configure_revwalk ( & repository, & mut walk, start_point, & refspecs) ?;
7667
7768 if repository. is_shallow ( ) {
7869 return Err ( "ERROR: git-graph does not support shallow clones due to a missing feature in the underlying libgit2 library." . to_string ( ) ) ;
@@ -300,6 +291,87 @@ impl BranchVis {
300291 }
301292}
302293
294+ /// For a single refspec, find a base branch to compare against
295+ /// using the branch's upstream tracking ref.
296+ fn find_base_oid ( repository : & Repository , refspec : & str , tip_oid : Oid ) -> Option < Oid > {
297+ if let Ok ( branch) = repository. find_branch ( refspec, BranchType :: Local ) {
298+ if let Ok ( upstream) = branch. upstream ( ) {
299+ if let Some ( oid) = upstream. get ( ) . target ( ) {
300+ if oid != tip_oid {
301+ return Some ( oid) ;
302+ }
303+ }
304+ }
305+ }
306+
307+ None
308+ }
309+
310+ fn hide_ancestors_of ( repository : & Repository , walk : & mut git2:: Revwalk , merge_base : Oid ) {
311+ if let Ok ( commit) = repository. find_commit ( merge_base) {
312+ for parent in commit. parents ( ) {
313+ let _ = walk. hide ( parent. id ( ) ) ;
314+ }
315+ }
316+ }
317+
318+ fn configure_revwalk (
319+ repository : & Repository ,
320+ walk : & mut git2:: Revwalk ,
321+ start_point : Option < String > ,
322+ refspecs : & [ String ] ,
323+ ) -> Result < ( ) , String > {
324+ if !refspecs. is_empty ( ) {
325+ let mut resolved_oids = Vec :: with_capacity ( refspecs. len ( ) ) ;
326+ for refspec in refspecs {
327+ let object = repository
328+ . revparse_single ( refspec)
329+ . map_err ( |err| format ! ( "Failed to resolve refspec '{}': {}" , refspec, err) ) ?;
330+ let oid = object. id ( ) ;
331+ walk. push ( oid)
332+ . map_err ( |err| err. message ( ) . to_string ( ) ) ?;
333+ resolved_oids. push ( oid) ;
334+ }
335+
336+ if resolved_oids. len ( ) == 1 {
337+ // Single refspec: auto-detect base branch
338+ if let Some ( base_oid) = find_base_oid ( repository, & refspecs[ 0 ] , resolved_oids[ 0 ] ) {
339+ walk. push ( base_oid)
340+ . map_err ( |err| err. message ( ) . to_string ( ) ) ?;
341+ if let Ok ( mb) = repository. merge_base ( resolved_oids[ 0 ] , base_oid) {
342+ hide_ancestors_of ( repository, walk, mb) ;
343+ }
344+ }
345+ } else {
346+ // Multiple refspecs: compute merge-base of all
347+ let mut base = resolved_oids[ 0 ] ;
348+ let mut base_found = true ;
349+ for oid in & resolved_oids[ 1 ..] {
350+ match repository. merge_base ( base, * oid) {
351+ Ok ( mb) => base = mb,
352+ Err ( _) => {
353+ base_found = false ;
354+ break ;
355+ }
356+ }
357+ }
358+ if base_found {
359+ hide_ancestors_of ( repository, walk, base) ;
360+ }
361+ }
362+ } else if let Some ( start) = start_point {
363+ let object = repository
364+ . revparse_single ( & start)
365+ . map_err ( |err| format ! ( "Failed to resolve start point '{}': {}" , start, err) ) ?;
366+ walk. push ( object. id ( ) )
367+ . map_err ( |err| err. message ( ) . to_string ( ) ) ?;
368+ } else {
369+ walk. push_glob ( "*" )
370+ . map_err ( |err| err. message ( ) . to_string ( ) ) ?;
371+ }
372+ Ok ( ( ) )
373+ }
374+
303375/// Walks through the commits and adds each commit's Oid to the children of its parents.
304376fn assign_children ( commits : & mut [ CommitInfo ] , indices : & HashMap < Oid , usize > ) {
305377 for idx in 0 ..commits. len ( ) {
0 commit comments