@@ -97,28 +97,65 @@ pub struct Target {
97
97
impl Target {
98
98
/// Return `None` if `ref_name` wasn't found as segment in `graph`.
99
99
/// This can happen if a reference is configured, but not actually present as reference.
100
- fn from_ref_name ( ref_name : & gix:: refs:: FullName , graph : & Graph ) -> Option < Self > {
100
+ /// Note that `commits_ahead` isn't set yet, see [`Self::compute_and_set_commits_ahead()`].
101
+ fn from_ref_name_without_commits_ahead (
102
+ ref_name : & gix:: refs:: FullName ,
103
+ graph : & Graph ,
104
+ ) -> Option < Self > {
101
105
let target_segment = graph. inner . node_indices ( ) . find_map ( |n| {
102
106
let s = & graph[ n] ;
103
107
( s. ref_name . as_ref ( ) == Some ( ref_name) ) . then_some ( s)
104
108
} ) ?;
105
109
Some ( Target {
106
110
ref_name : ref_name. to_owned ( ) ,
107
111
segment_index : target_segment. id ,
108
- commits_ahead : {
109
- // Find all remote commits but stop traversing when there is segments without remotes.
110
- let mut count = 0 ;
111
- graph. visit_all_segments_until ( target_segment. id , Direction :: Outgoing , |s| {
112
- let remote_commits = s. commits . iter ( ) . filter ( |c| c. flags . is_remote ( ) ) . count ( ) ;
113
- count += remote_commits;
114
- remote_commits != s. commits . len ( )
115
- } ) ;
116
- count
117
- } ,
112
+ commits_ahead : 0 ,
113
+ } )
114
+ }
115
+
116
+ fn compute_and_set_commits_ahead (
117
+ & mut self ,
118
+ graph : & Graph ,
119
+ lower_bound_segment : Option < SegmentIndex > ,
120
+ ) {
121
+ let lower_bound = lower_bound_segment. map ( |sidx| ( sidx, graph[ sidx] . generation ) ) ;
122
+ self . commits_ahead = 0 ;
123
+ Self :: visit_upstream_commits ( graph, self . segment_index , lower_bound, |s| {
124
+ self . commits_ahead += s. commits . len ( ) ;
118
125
} )
119
126
}
120
127
}
121
128
129
+ /// Utilities
130
+ impl Target {
131
+ /// Visit all segments whose commits would be considered 'upstream', or part of the target branch
132
+ /// whose tip is identified with `target_segment`. The `lower_bound_segment_and_generation` is another way
133
+ /// to stop the traversal.
134
+ pub fn visit_upstream_commits (
135
+ graph : & Graph ,
136
+ target_segment : SegmentIndex ,
137
+ lower_bound_segment_and_generation : Option < ( SegmentIndex , usize ) > ,
138
+ mut visit : impl FnMut ( & Segment ) ,
139
+ ) {
140
+ graph. visit_all_segments_until ( target_segment, Direction :: Outgoing , |s| {
141
+ let prune = true ;
142
+ if lower_bound_segment_and_generation. is_some_and (
143
+ |( lower_bound, lower_bound_generation) | {
144
+ s. id == lower_bound || s. generation > lower_bound_generation
145
+ } ,
146
+ ) || s
147
+ . commits
148
+ . iter ( )
149
+ . any ( |c| c. flags . contains ( CommitFlags :: InWorkspace ) )
150
+ {
151
+ return prune;
152
+ }
153
+ visit ( s) ;
154
+ !prune
155
+ } ) ;
156
+ }
157
+ }
158
+
122
159
impl Graph {
123
160
/// Analyse the current graph starting at its [entrypoint](Self::lookup_entrypoint()).
124
161
///
@@ -196,9 +233,9 @@ impl Graph {
196
233
id : ws_tip_segment. id ,
197
234
kind,
198
235
stacks : vec ! [ ] ,
199
- target : metadata
200
- . as_ref ( )
201
- . and_then ( |md| Target :: from_ref_name ( md . target_ref . as_ref ( ) ? , self ) ) ,
236
+ target : metadata. as_ref ( ) . and_then ( |md| {
237
+ Target :: from_ref_name_without_commits_ahead ( md . target_ref . as_ref ( ) ? , self )
238
+ } ) ,
202
239
extra_target : self . extra_target ,
203
240
metadata,
204
241
lower_bound_segment_id : None ,
@@ -352,6 +389,9 @@ impl Graph {
352
389
) ;
353
390
}
354
391
392
+ if let Some ( target) = ws. target . as_mut ( ) {
393
+ target. compute_and_set_commits_ahead ( self , ws. lower_bound_segment_id ) ;
394
+ }
355
395
ws. mark_remote_reachability ( ) ?;
356
396
Ok ( ws)
357
397
}
@@ -834,6 +874,8 @@ impl std::fmt::Debug for Workspace<'_> {
834
874
. field ( "id" , & self . id . index ( ) )
835
875
. field ( "stacks" , & self . stacks )
836
876
. field ( "metadata" , & self . metadata )
877
+ . field ( "target" , & self . target )
878
+ . field ( "extra_target" , & self . extra_target )
837
879
. finish ( )
838
880
}
839
881
}
0 commit comments