1
1
bitflags:: bitflags! {
2
2
/// The flags used in the graph for finding [merge bases](crate::merge_base()).
3
- #[ derive( Debug , Default , Copy , Clone ) ]
3
+ #[ derive( Debug , Default , Copy , Clone , Eq , PartialEq ) ]
4
4
pub struct Flags : u8 {
5
5
/// The commit belongs to the graph reachable by the first commit
6
6
const COMMIT1 = 1 << 0 ;
@@ -18,6 +18,8 @@ bitflags::bitflags! {
18
18
#[ derive( Debug , thiserror:: Error ) ]
19
19
#[ allow( missing_docs) ]
20
20
pub enum Error {
21
+ #[ error( transparent) ]
22
+ IterParents ( #[ from] gix_revwalk:: graph:: commit:: iter_parents:: Error ) ,
21
23
#[ error( "A commit could not be found" ) ]
22
24
FindExistingCommit ( #[ from] gix_object:: find:: existing_iter:: Error ) ,
23
25
#[ error( "A commit could not be decoded during traversal" ) ]
@@ -51,6 +53,24 @@ pub(crate) mod function {
51
53
return Ok ( Some ( vec ! [ first] ) ) ;
52
54
}
53
55
56
+ let mut bases = paint_down_to_common ( first, others, graph) ?;
57
+ // TODO(ST): remove redundant
58
+ Ok ( if bases. is_empty ( ) {
59
+ None
60
+ } else {
61
+ let mut out = Vec :: with_capacity ( bases. len ( ) ) ;
62
+ while let Some ( ( _info, commit_id) ) = bases. pop ( ) {
63
+ out. push ( commit_id) ;
64
+ }
65
+ Some ( out)
66
+ } )
67
+ }
68
+
69
+ fn paint_down_to_common < ' name > (
70
+ first : ObjectId ,
71
+ others : & [ ObjectId ] ,
72
+ graph : & mut Graph < ' _ , Flags > ,
73
+ ) -> Result < PriorityQueue < GenThenTime , ObjectId > , Error > {
54
74
let mut queue = PriorityQueue :: < GenThenTime , ObjectId > :: new ( ) ;
55
75
graph. insert_data ( first, |commit| -> Result < _ , Error > {
56
76
queue. insert ( commit. try_into ( ) ?, first) ;
@@ -63,10 +83,47 @@ pub(crate) mod function {
63
83
Ok ( Flags :: COMMIT2 )
64
84
} ) ?;
65
85
}
66
- Ok ( None )
86
+
87
+ let mut out = PriorityQueue :: new ( ) ;
88
+ while queue
89
+ . iter_unordered ( )
90
+ . any ( |id| graph. get ( id) . map_or ( false , |data| !data. contains ( Flags :: STALE ) ) )
91
+ {
92
+ let ( info, commit_id) = queue. pop ( ) . expect ( "we have non-stale" ) ;
93
+ let flags_mut = graph. get_mut ( & commit_id) . expect ( "everything queued is in graph" ) ;
94
+ let mut flags_without_result = * flags_mut & ( Flags :: COMMIT1 | Flags :: COMMIT2 | Flags :: STALE ) ;
95
+ if flags_without_result == ( Flags :: COMMIT1 | Flags :: COMMIT2 ) {
96
+ if !flags_mut. contains ( Flags :: RESULT ) {
97
+ * flags_mut |= Flags :: RESULT ;
98
+ out. insert ( info, commit_id) ;
99
+ }
100
+ flags_without_result |= Flags :: STALE ;
101
+ }
102
+
103
+ graph. insert_parents_with_lookup ( & commit_id, & mut |parent_id, parent, ex_flags| -> Result < _ , Error > {
104
+ let queue_info = match ex_flags {
105
+ Some ( ex_flags) => {
106
+ if ( * ex_flags & flags_without_result) != flags_without_result {
107
+ * ex_flags |= flags_without_result;
108
+ Some ( GenThenTime :: try_from ( parent) ?)
109
+ } else {
110
+ None
111
+ }
112
+ }
113
+ None => Some ( GenThenTime :: try_from ( parent) ?) ,
114
+ } ;
115
+ if let Some ( info) = queue_info {
116
+ queue. insert ( info, parent_id) ;
117
+ }
118
+ Ok ( flags_without_result)
119
+ } ) ?;
120
+ }
121
+
122
+ Ok ( out)
67
123
}
68
124
69
125
// TODO(ST): Should this type be used for `describe` as well?
126
+ #[ derive( Debug ) ]
70
127
struct GenThenTime {
71
128
/// Note that the special [`GENERATION_NUMBER_INFINITY`](gix_commitgraph::GENERATION_NUMBER_INFINITY) is used to indicate
72
129
/// that no commitgraph is avaialble.
0 commit comments