@@ -77,6 +77,9 @@ impl Graph {
77
77
// the foundation for figuring out our workspaces more easily.
78
78
self . workspace_upgrades ( meta, repo) ?;
79
79
80
+ // Point entrypoint to the right spot after all the virtual branches were added.
81
+ self . set_entrypoint_to_ref_name ( meta) ?;
82
+
80
83
// However, when it comes to using remotes to disambiguate, it's better to
81
84
// *not* do that before workspaces are sorted as it might incorrectly place
82
85
// a segment on top of another one, setting a first-second relationship that isn't
@@ -95,6 +98,108 @@ impl Graph {
95
98
Ok ( self )
96
99
}
97
100
101
+ /// After everything, assure the entrypoint still points to a segment with the correct ref-name,
102
+ /// if one was given when starting the traversal.
103
+ /// If not, try to find a segment with the right ref-name.
104
+ ///
105
+ /// *This is the brute-force way of doing it, instead of ensuring that the workspace upgrade functions
106
+ /// that create independent and dependent branches keep everything up-to-date at all times.
107
+ fn set_entrypoint_to_ref_name < T : RefMetadata > (
108
+ & mut self ,
109
+ meta : & OverlayMetadata < ' _ , T > ,
110
+ ) -> anyhow:: Result < ( ) > {
111
+ let Some ( ( ( ep_sidx, _commit_idx) , desired_ref_name) ) =
112
+ self . entrypoint . zip ( self . entrypoint_ref . clone ( ) )
113
+ else {
114
+ return Ok ( ( ) ) ;
115
+ } ;
116
+
117
+ let ep_segment_is_correctly_named = self [ ep_sidx]
118
+ . ref_name
119
+ . as_ref ( )
120
+ . is_some_and ( |rn| rn == & desired_ref_name) ;
121
+ if ep_segment_is_correctly_named {
122
+ return Ok ( ( ) ) ;
123
+ }
124
+
125
+ let ( sidx_with_desired_name, sidx_with_first_commit_with_desired_name) = self
126
+ . node_weights ( )
127
+ . find_map ( |s| {
128
+ s. ref_name
129
+ . as_ref ( )
130
+ . is_some_and ( |rn| rn == & desired_ref_name)
131
+ . then_some ( ( Some ( s. id ) , None ) )
132
+ . or_else ( || {
133
+ s. commits . first ( ) . and_then ( |c| {
134
+ c. refs
135
+ . iter ( )
136
+ . position ( |rn| rn == & desired_ref_name)
137
+ . map ( |pos| ( None , Some ( ( s. id , pos) ) ) )
138
+ } )
139
+ } )
140
+ } )
141
+ . unwrap_or_default ( ) ;
142
+ if let Some ( new_ep_sidx) = sidx_with_desired_name {
143
+ let assume_tip_is_not_available_in_segment_anymore = None ;
144
+ self . entrypoint = Some ( ( new_ep_sidx, assume_tip_is_not_available_in_segment_anymore) ) ;
145
+ } else if let Some ( ( new_ep_sidx, ref_idx) ) = sidx_with_first_commit_with_desired_name {
146
+ let s = & mut self . inner [ new_ep_sidx] ;
147
+ let desired_ref_name = s
148
+ . commits
149
+ . first_mut ( )
150
+ . context ( "BUG: we have ref_idx because the first commit was checked" ) ?
151
+ . refs
152
+ . remove ( ref_idx) ;
153
+ if s. ref_name . is_some ( ) {
154
+ // ref-name is known to not be the desired one, and the first commit of this segment has the name
155
+ // we seek. For that, we now create a new
156
+ let new_ep_sidx_first_commit_idx = s. commits . first ( ) . map ( |_| 0 ) ;
157
+ let incoming_edges = collect_edges_at_commit_reverse_order (
158
+ & self . inner ,
159
+ ( new_ep_sidx, new_ep_sidx_first_commit_idx) ,
160
+ Direction :: Incoming ,
161
+ ) ;
162
+ let entrypoint_segment =
163
+ branch_segment_from_name_and_meta ( Some ( ( desired_ref_name, None ) ) , meta, None ) ?;
164
+ let entrypoint_sidx = self . insert_root ( entrypoint_segment) ;
165
+ self . connect_segments (
166
+ entrypoint_sidx,
167
+ None ,
168
+ new_ep_sidx,
169
+ new_ep_sidx_first_commit_idx,
170
+ ) ;
171
+ for edge in incoming_edges {
172
+ self . inner . add_edge (
173
+ edge. source ,
174
+ entrypoint_sidx,
175
+ Edge {
176
+ src : edge. weight . src ,
177
+ src_id : edge. weight . src_id ,
178
+ dst : None ,
179
+ dst_id : None ,
180
+ } ,
181
+ ) ;
182
+ self . inner . remove_edge ( edge. id ) ;
183
+ }
184
+ self . entrypoint = Some ( ( entrypoint_sidx, None ) ) ;
185
+ } else {
186
+ self . entrypoint = Some ( ( new_ep_sidx, Some ( 0 ) ) ) ;
187
+ // It's really important to get the name, as the HEAD is pointing to this segment.
188
+ // So find the segment with the ambiguous ref we desire, and rewrite it to be non-ambiguous.
189
+ // The reason we wait till now is to not disturb the workspace upgrades, which act differently
190
+ // if they already have a named segment.
191
+ // Note that any ref type works here, we just do as we are told even though tags for instance aren't usually
192
+ // pointed to by HEAD.
193
+ s. ref_name = Some ( desired_ref_name) ;
194
+ }
195
+ } else {
196
+ tracing:: warn!(
197
+ "Couldn't find any segment that was named after the entrypoint ref name or contained its name '{desired_ref_name}'" ,
198
+ ) ;
199
+ } ;
200
+ Ok ( ( ) )
201
+ }
202
+
98
203
/// This is a post-process as only in the end we are sure what is a remote commit.
99
204
/// On remote commits, we want to further segment remote tracking segments to avoid picking
100
205
/// up too many remote commits later.
@@ -570,7 +675,7 @@ impl Graph {
570
675
s. ref_name = Some ( name) ;
571
676
s. metadata = md;
572
677
}
573
- reconnect_edges (
678
+ reconnect_outgoing_edges (
574
679
self ,
575
680
edges_from_segment_above,
576
681
( new_sidx_above_base_sidx, None ) ,
@@ -675,6 +780,11 @@ impl Graph {
675
780
/// Name ambiguous segments if they are reachable by remote tracking branch and
676
781
/// if the first commit has (unambiguously) the matching local tracking branch.
677
782
/// Also, link up all remote segments with their local ones, and vice versa.
783
+ ///
784
+ /// Additionally, restore possibly broken linkage to their siblings
785
+ /// (from remote to local tracking branch), as this connection might have been destroyed by
786
+ /// the insertion of empty segments. Again, instead of making that smarter, we fix it up here
787
+ /// because it's simpler.
678
788
fn improve_remote_segments (
679
789
& mut self ,
680
790
repo : & OverlayRepo < ' _ > ,
@@ -1125,11 +1235,11 @@ fn reconnect_outgoing(
1125
1235
( source_sidx, Some ( source_cidx) ) ,
1126
1236
Direction :: Outgoing ,
1127
1237
) ;
1128
- reconnect_edges ( graph, edges, ( target_sidx, Some ( target_cidx) ) )
1238
+ reconnect_outgoing_edges ( graph, edges, ( target_sidx, Some ( target_cidx) ) )
1129
1239
}
1130
1240
1131
1241
/// Delete all `edges` and recreate the edges with `target` as new source.
1132
- fn reconnect_edges (
1242
+ fn reconnect_outgoing_edges (
1133
1243
graph : & mut PetGraph ,
1134
1244
edges : Vec < EdgeOwned > ,
1135
1245
( target_sidx, target_first_commit_id) : ( SegmentIndex , Option < gix:: ObjectId > ) ,
0 commit comments