1#![expect(missing_docs)]
16
17use std::collections::BTreeMap;
18use std::collections::HashMap;
19use std::collections::HashSet;
20use std::collections::hash_map::Entry;
21use std::fmt::Debug;
22use std::fmt::Formatter;
23use std::fs;
24use std::path::Path;
25use std::slice;
26use std::sync::Arc;
27
28use futures::StreamExt as _;
29use futures::TryStreamExt as _;
30use futures::future::try_join_all;
31use futures::stream;
32use itertools::Itertools as _;
33use once_cell::sync::OnceCell;
34use thiserror::Error;
35use tracing::instrument;
36
37use crate::backend::Backend;
38use crate::backend::BackendError;
39use crate::backend::BackendInitError;
40use crate::backend::BackendLoadError;
41use crate::backend::BackendResult;
42use crate::backend::ChangeId;
43use crate::backend::CommitId;
44use crate::commit::Commit;
45use crate::commit::CommitByCommitterTimestamp;
46use crate::commit_builder::CommitBuilder;
47use crate::commit_builder::DetachedCommitBuilder;
48use crate::dag_walk;
49use crate::dag_walk_async;
50use crate::default_index::DefaultIndexStore;
51use crate::default_index::DefaultMutableIndex;
52use crate::default_submodule_store::DefaultSubmoduleStore;
53use crate::file_util::IoResultExt as _;
54use crate::file_util::PathError;
55use crate::index::ChangeIdIndex;
56use crate::index::Index;
57use crate::index::IndexError;
58use crate::index::IndexResult;
59use crate::index::IndexStore;
60use crate::index::IndexStoreError;
61use crate::index::MutableIndex;
62use crate::index::ReadonlyIndex;
63use crate::index::ResolvedChangeTargets;
64use crate::merge::MergeBuilder;
65use crate::merge::SameChange;
66use crate::merge::trivial_merge;
67use crate::merged_tree::MergedTree;
68use crate::object_id::HexPrefix;
69use crate::object_id::PrefixResolution;
70use crate::op_heads_store;
71use crate::op_heads_store::OpHeadsStore;
72use crate::op_heads_store::OpHeadsStoreError;
73use crate::op_store;
74use crate::op_store::OpStore;
75use crate::op_store::OpStoreError;
76use crate::op_store::OpStoreResult;
77use crate::op_store::OperationId;
78use crate::op_store::RefTarget;
79use crate::op_store::RemoteRef;
80use crate::op_store::RemoteRefState;
81use crate::op_store::RootOperationData;
82use crate::op_walk;
83use crate::operation::Operation;
84use crate::ref_name::GitRefName;
85use crate::ref_name::RefName;
86use crate::ref_name::RemoteName;
87use crate::ref_name::RemoteRefSymbol;
88use crate::ref_name::WorkspaceName;
89use crate::ref_name::WorkspaceNameBuf;
90use crate::refs::diff_named_commit_ids;
91use crate::refs::diff_named_ref_targets;
92use crate::refs::diff_named_remote_refs;
93use crate::refs::merge_ref_targets;
94use crate::refs::merge_remote_refs;
95use crate::revset;
96use crate::revset::ResolvedRevsetExpression;
97use crate::revset::RevsetEvaluationError;
98use crate::revset::RevsetExpression;
99use crate::revset::RevsetStreamExt as _;
100use crate::rewrite::CommitRewriter;
101use crate::rewrite::RebaseOptions;
102use crate::rewrite::RebasedCommit;
103use crate::rewrite::RewriteRefsOptions;
104use crate::rewrite::merge_commit_trees;
105use crate::rewrite::rebase_commit_with_options;
106use crate::settings::UserSettings;
107use crate::signing::SignInitError;
108use crate::signing::Signer;
109use crate::simple_op_heads_store::SimpleOpHeadsStore;
110use crate::simple_op_store::SimpleOpStore;
111use crate::store::Store;
112use crate::submodule_store::SubmoduleStore;
113use crate::transaction::Transaction;
114use crate::transaction::TransactionCommitError;
115use crate::tree_merge::MergeOptions;
116use crate::view::RenameWorkspaceError;
117use crate::view::View;
118
119pub trait Repo {
120 fn base_repo(&self) -> &ReadonlyRepo;
123
124 fn store(&self) -> &Arc<Store>;
125
126 fn op_store(&self) -> &Arc<dyn OpStore>;
127
128 fn index(&self) -> &dyn Index;
129
130 fn view(&self) -> &View;
131
132 fn submodule_store(&self) -> &Arc<dyn SubmoduleStore>;
133
134 fn resolve_change_id(
135 &self,
136 change_id: &ChangeId,
137 ) -> IndexResult<Option<ResolvedChangeTargets>> {
138 let prefix = HexPrefix::from_id(change_id);
140 match self.resolve_change_id_prefix(&prefix)? {
141 PrefixResolution::NoMatch => Ok(None),
142 PrefixResolution::SingleMatch(entries) => Ok(Some(entries)),
143 PrefixResolution::AmbiguousMatch => panic!("complete change_id should be unambiguous"),
144 }
145 }
146
147 fn resolve_change_id_prefix(
148 &self,
149 prefix: &HexPrefix,
150 ) -> IndexResult<PrefixResolution<ResolvedChangeTargets>>;
151
152 fn shortest_unique_change_id_prefix_len(
153 &self,
154 target_id_bytes: &ChangeId,
155 ) -> IndexResult<usize>;
156}
157
158pub struct ReadonlyRepo {
159 loader: RepoLoader,
160 operation: Operation,
161 index: Box<dyn ReadonlyIndex>,
162 change_id_index: OnceCell<Box<dyn ChangeIdIndex>>,
163 view: View,
165}
166
167impl Debug for ReadonlyRepo {
168 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
169 f.debug_struct("ReadonlyRepo")
170 .field("store", &self.loader.store)
171 .finish_non_exhaustive()
172 }
173}
174
175#[derive(Error, Debug)]
176pub enum RepoInitError {
177 #[error(transparent)]
178 Backend(#[from] BackendInitError),
179 #[error(transparent)]
180 OpHeadsStore(#[from] OpHeadsStoreError),
181 #[error(transparent)]
182 Path(#[from] PathError),
183}
184
185impl ReadonlyRepo {
186 pub fn default_op_store_initializer() -> &'static OpStoreInitializer<'static> {
187 &|_settings, store_path, root_data| {
188 Ok(Box::new(SimpleOpStore::init(store_path, root_data)?))
189 }
190 }
191
192 pub fn default_op_heads_store_initializer() -> &'static OpHeadsStoreInitializer<'static> {
193 &|_settings, store_path, root_op_id| {
194 Ok(Box::new(SimpleOpHeadsStore::init(store_path, root_op_id)?))
195 }
196 }
197
198 pub fn default_index_store_initializer() -> &'static IndexStoreInitializer<'static> {
199 &|_settings, store_path| Ok(Box::new(DefaultIndexStore::init(store_path)?))
200 }
201
202 pub fn default_submodule_store_initializer() -> &'static SubmoduleStoreInitializer<'static> {
203 &|_settings, store_path| Ok(Box::new(DefaultSubmoduleStore::init(store_path)))
204 }
205
206 #[expect(clippy::too_many_arguments)]
207 pub async fn init(
208 settings: &UserSettings,
209 repo_path: &Path,
210 backend_initializer: &BackendInitializer<'_>,
211 signer: Signer,
212 op_store_initializer: &OpStoreInitializer<'_>,
213 op_heads_store_initializer: &OpHeadsStoreInitializer<'_>,
214 index_store_initializer: &IndexStoreInitializer<'_>,
215 submodule_store_initializer: &SubmoduleStoreInitializer<'_>,
216 ) -> Result<Arc<Self>, RepoInitError> {
217 let repo_path = dunce::canonicalize(repo_path).context(repo_path)?;
218
219 let store_path = repo_path.join("store");
220 fs::create_dir(&store_path).context(&store_path)?;
221 let backend = backend_initializer(settings, &store_path)?;
222 let backend_path = store_path.join("type");
223 fs::write(&backend_path, backend.name()).context(&backend_path)?;
224 let merge_options =
225 MergeOptions::from_settings(settings).map_err(|err| BackendInitError(err.into()))?;
226 let store = Store::new(backend, signer, merge_options);
227
228 let op_store_path = repo_path.join("op_store");
229 fs::create_dir(&op_store_path).context(&op_store_path)?;
230 let root_op_data = RootOperationData {
231 root_commit_id: store.root_commit_id().clone(),
232 };
233 let op_store = op_store_initializer(settings, &op_store_path, root_op_data)?;
234 let op_store_type_path = op_store_path.join("type");
235 fs::write(&op_store_type_path, op_store.name()).context(&op_store_type_path)?;
236 let op_store: Arc<dyn OpStore> = Arc::from(op_store);
237
238 let op_heads_path = repo_path.join("op_heads");
239 fs::create_dir(&op_heads_path).context(&op_heads_path)?;
240 let op_heads_store =
241 op_heads_store_initializer(settings, &op_heads_path, op_store.root_operation_id())?;
242 let op_heads_type_path = op_heads_path.join("type");
243 fs::write(&op_heads_type_path, op_heads_store.name()).context(&op_heads_type_path)?;
244 let op_heads_store: Arc<dyn OpHeadsStore> = Arc::from(op_heads_store);
245
246 let index_path = repo_path.join("index");
247 fs::create_dir(&index_path).context(&index_path)?;
248 let index_store = index_store_initializer(settings, &index_path)?;
249 let index_type_path = index_path.join("type");
250 fs::write(&index_type_path, index_store.name()).context(&index_type_path)?;
251 let index_store: Arc<dyn IndexStore> = Arc::from(index_store);
252
253 let submodule_store_path = repo_path.join("submodule_store");
254 fs::create_dir(&submodule_store_path).context(&submodule_store_path)?;
255 let submodule_store = submodule_store_initializer(settings, &submodule_store_path)?;
256 let submodule_store_type_path = submodule_store_path.join("type");
257 fs::write(&submodule_store_type_path, submodule_store.name())
258 .context(&submodule_store_type_path)?;
259 let submodule_store = Arc::from(submodule_store);
260
261 let loader = RepoLoader {
262 settings: settings.clone(),
263 store,
264 op_store,
265 op_heads_store,
266 index_store,
267 submodule_store,
268 };
269
270 let root_operation = loader.root_operation().await;
271 let root_view = root_operation
272 .view()
273 .await
274 .expect("failed to read root view");
275 assert!(!root_view.heads().is_empty());
276 let index = loader
277 .index_store
278 .get_index_at_op(&root_operation, &loader.store)
279 .await
280 .map_err(|err| BackendInitError(err.into()))?;
283 Ok(Arc::new(Self {
284 loader,
285 operation: root_operation,
286 index,
287 change_id_index: OnceCell::new(),
288 view: root_view,
289 }))
290 }
291
292 pub fn loader(&self) -> &RepoLoader {
293 &self.loader
294 }
295
296 pub fn op_id(&self) -> &OperationId {
297 self.operation.id()
298 }
299
300 pub fn operation(&self) -> &Operation {
301 &self.operation
302 }
303
304 pub fn view(&self) -> &View {
305 &self.view
306 }
307
308 pub fn readonly_index(&self) -> &dyn ReadonlyIndex {
309 self.index.as_ref()
310 }
311
312 fn change_id_index(&self) -> &dyn ChangeIdIndex {
313 self.change_id_index
314 .get_or_init(|| {
315 self.readonly_index()
316 .change_id_index(&mut self.view().heads().iter())
317 })
318 .as_ref()
319 }
320
321 pub fn op_heads_store(&self) -> &Arc<dyn OpHeadsStore> {
322 self.loader.op_heads_store()
323 }
324
325 pub fn index_store(&self) -> &Arc<dyn IndexStore> {
326 self.loader.index_store()
327 }
328
329 pub fn settings(&self) -> &UserSettings {
330 self.loader.settings()
331 }
332
333 pub fn start_transaction(self: &Arc<Self>) -> Transaction {
334 let mut_repo = MutableRepo::new(self.clone(), self.readonly_index(), &self.view);
335 Transaction::new(mut_repo, self.settings())
336 }
337
338 pub async fn reload_at_head(&self) -> Result<Arc<Self>, RepoLoaderError> {
339 self.loader().load_at_head().await
340 }
341
342 #[instrument]
343 pub async fn reload_at(&self, operation: &Operation) -> Result<Arc<Self>, RepoLoaderError> {
344 self.loader().load_at(operation).await
345 }
346}
347
348impl Repo for ReadonlyRepo {
349 fn base_repo(&self) -> &ReadonlyRepo {
350 self
351 }
352
353 fn store(&self) -> &Arc<Store> {
354 self.loader.store()
355 }
356
357 fn op_store(&self) -> &Arc<dyn OpStore> {
358 self.loader.op_store()
359 }
360
361 fn index(&self) -> &dyn Index {
362 self.readonly_index().as_index()
363 }
364
365 fn view(&self) -> &View {
366 &self.view
367 }
368
369 fn submodule_store(&self) -> &Arc<dyn SubmoduleStore> {
370 self.loader.submodule_store()
371 }
372
373 fn resolve_change_id_prefix(
374 &self,
375 prefix: &HexPrefix,
376 ) -> IndexResult<PrefixResolution<ResolvedChangeTargets>> {
377 self.change_id_index().resolve_prefix(prefix)
378 }
379
380 fn shortest_unique_change_id_prefix_len(&self, target_id: &ChangeId) -> IndexResult<usize> {
381 self.change_id_index().shortest_unique_prefix_len(target_id)
382 }
383}
384
385pub type BackendInitializer<'a> =
386 dyn Fn(&UserSettings, &Path) -> Result<Box<dyn Backend>, BackendInitError> + 'a;
387#[rustfmt::skip] pub type OpStoreInitializer<'a> =
389 dyn Fn(&UserSettings, &Path, RootOperationData) -> Result<Box<dyn OpStore>, BackendInitError>
390 + 'a;
391#[rustfmt::skip] pub type OpHeadsStoreInitializer<'a> =
393 dyn Fn(&UserSettings, &Path, &OperationId)
394 -> Result<Box<dyn OpHeadsStore>, BackendInitError>
395 + 'a;
396pub type IndexStoreInitializer<'a> =
397 dyn Fn(&UserSettings, &Path) -> Result<Box<dyn IndexStore>, BackendInitError> + 'a;
398pub type SubmoduleStoreInitializer<'a> =
399 dyn Fn(&UserSettings, &Path) -> Result<Box<dyn SubmoduleStore>, BackendInitError> + 'a;
400
401type BackendFactory =
402 Box<dyn Fn(&UserSettings, &Path) -> Result<Box<dyn Backend>, BackendLoadError>>;
403type OpStoreFactory = Box<
404 dyn Fn(&UserSettings, &Path, RootOperationData) -> Result<Box<dyn OpStore>, BackendLoadError>,
405>;
406type OpHeadsStoreFactory =
407 Box<dyn Fn(&UserSettings, &Path) -> Result<Box<dyn OpHeadsStore>, BackendLoadError>>;
408type IndexStoreFactory =
409 Box<dyn Fn(&UserSettings, &Path) -> Result<Box<dyn IndexStore>, BackendLoadError>>;
410type SubmoduleStoreFactory =
411 Box<dyn Fn(&UserSettings, &Path) -> Result<Box<dyn SubmoduleStore>, BackendLoadError>>;
412
413pub fn merge_factories_map<F>(base: &mut HashMap<String, F>, ext: HashMap<String, F>) {
414 for (name, factory) in ext {
415 match base.entry(name) {
416 Entry::Vacant(v) => {
417 v.insert(factory);
418 }
419 Entry::Occupied(o) => {
420 panic!("Conflicting factory definitions for '{}' factory", o.key())
421 }
422 }
423 }
424}
425
426pub struct StoreFactories {
427 backend_factories: HashMap<String, BackendFactory>,
428 op_store_factories: HashMap<String, OpStoreFactory>,
429 op_heads_store_factories: HashMap<String, OpHeadsStoreFactory>,
430 index_store_factories: HashMap<String, IndexStoreFactory>,
431 submodule_store_factories: HashMap<String, SubmoduleStoreFactory>,
432}
433
434#[derive(Debug, Error)]
435pub enum StoreLoadError {
436 #[error("Unsupported {store} backend type '{store_type}'")]
437 UnsupportedType {
438 store: &'static str,
439 store_type: String,
440 },
441 #[error("Failed to read {store} backend type")]
442 ReadError {
443 store: &'static str,
444 source: PathError,
445 },
446 #[error(transparent)]
447 Backend(#[from] BackendLoadError),
448 #[error(transparent)]
449 Signing(#[from] SignInitError),
450}
451
452impl StoreFactories {
453 pub fn empty() -> Self {
454 Self {
455 backend_factories: HashMap::new(),
456 op_store_factories: HashMap::new(),
457 op_heads_store_factories: HashMap::new(),
458 index_store_factories: HashMap::new(),
459 submodule_store_factories: HashMap::new(),
460 }
461 }
462
463 pub fn merge(&mut self, ext: Self) {
464 let Self {
465 backend_factories,
466 op_store_factories,
467 op_heads_store_factories,
468 index_store_factories,
469 submodule_store_factories,
470 } = ext;
471
472 merge_factories_map(&mut self.backend_factories, backend_factories);
473 merge_factories_map(&mut self.op_store_factories, op_store_factories);
474 merge_factories_map(&mut self.op_heads_store_factories, op_heads_store_factories);
475 merge_factories_map(&mut self.index_store_factories, index_store_factories);
476 merge_factories_map(
477 &mut self.submodule_store_factories,
478 submodule_store_factories,
479 );
480 }
481
482 pub fn add_backend(&mut self, name: &str, factory: BackendFactory) {
483 self.backend_factories.insert(name.to_string(), factory);
484 }
485
486 pub fn load_backend(
487 &self,
488 settings: &UserSettings,
489 store_path: &Path,
490 ) -> Result<Box<dyn Backend>, StoreLoadError> {
491 let backend_type = read_store_type("commit", store_path.join("type"))?;
492 let backend_factory = self.backend_factories.get(&backend_type).ok_or_else(|| {
493 StoreLoadError::UnsupportedType {
494 store: "commit",
495 store_type: backend_type.clone(),
496 }
497 })?;
498 Ok(backend_factory(settings, store_path)?)
499 }
500
501 pub fn add_op_store(&mut self, name: &str, factory: OpStoreFactory) {
502 self.op_store_factories.insert(name.to_string(), factory);
503 }
504
505 pub fn load_op_store(
506 &self,
507 settings: &UserSettings,
508 store_path: &Path,
509 root_data: RootOperationData,
510 ) -> Result<Box<dyn OpStore>, StoreLoadError> {
511 let op_store_type = read_store_type("operation", store_path.join("type"))?;
512 let op_store_factory = self.op_store_factories.get(&op_store_type).ok_or_else(|| {
513 StoreLoadError::UnsupportedType {
514 store: "operation",
515 store_type: op_store_type.clone(),
516 }
517 })?;
518 Ok(op_store_factory(settings, store_path, root_data)?)
519 }
520
521 pub fn add_op_heads_store(&mut self, name: &str, factory: OpHeadsStoreFactory) {
522 self.op_heads_store_factories
523 .insert(name.to_string(), factory);
524 }
525
526 pub fn load_op_heads_store(
527 &self,
528 settings: &UserSettings,
529 store_path: &Path,
530 ) -> Result<Box<dyn OpHeadsStore>, StoreLoadError> {
531 let op_heads_store_type = read_store_type("operation heads", store_path.join("type"))?;
532 let op_heads_store_factory = self
533 .op_heads_store_factories
534 .get(&op_heads_store_type)
535 .ok_or_else(|| StoreLoadError::UnsupportedType {
536 store: "operation heads",
537 store_type: op_heads_store_type.clone(),
538 })?;
539 Ok(op_heads_store_factory(settings, store_path)?)
540 }
541
542 pub fn add_index_store(&mut self, name: &str, factory: IndexStoreFactory) {
543 self.index_store_factories.insert(name.to_string(), factory);
544 }
545
546 pub fn load_index_store(
547 &self,
548 settings: &UserSettings,
549 store_path: &Path,
550 ) -> Result<Box<dyn IndexStore>, StoreLoadError> {
551 let index_store_type = read_store_type("index", store_path.join("type"))?;
552 let index_store_factory = self
553 .index_store_factories
554 .get(&index_store_type)
555 .ok_or_else(|| StoreLoadError::UnsupportedType {
556 store: "index",
557 store_type: index_store_type.clone(),
558 })?;
559 Ok(index_store_factory(settings, store_path)?)
560 }
561
562 pub fn add_submodule_store(&mut self, name: &str, factory: SubmoduleStoreFactory) {
563 self.submodule_store_factories
564 .insert(name.to_string(), factory);
565 }
566
567 pub fn load_submodule_store(
568 &self,
569 settings: &UserSettings,
570 store_path: &Path,
571 ) -> Result<Box<dyn SubmoduleStore>, StoreLoadError> {
572 let submodule_store_type = read_store_type("submodule_store", store_path.join("type"))?;
573 let submodule_store_factory = self
574 .submodule_store_factories
575 .get(&submodule_store_type)
576 .ok_or_else(|| StoreLoadError::UnsupportedType {
577 store: "submodule_store",
578 store_type: submodule_store_type.clone(),
579 })?;
580
581 Ok(submodule_store_factory(settings, store_path)?)
582 }
583}
584
585pub fn read_store_type(
586 store: &'static str,
587 path: impl AsRef<Path>,
588) -> Result<String, StoreLoadError> {
589 let path = path.as_ref();
590 fs::read_to_string(path)
591 .context(path)
592 .map_err(|source| StoreLoadError::ReadError { store, source })
593}
594
595#[derive(Debug, Error)]
596pub enum RepoLoaderError {
597 #[error(transparent)]
598 Backend(#[from] BackendError),
599 #[error(transparent)]
600 Index(#[from] IndexError),
601 #[error(transparent)]
602 IndexStore(#[from] IndexStoreError),
603 #[error(transparent)]
604 OpHeadsStoreError(#[from] OpHeadsStoreError),
605 #[error(transparent)]
606 OpStore(#[from] OpStoreError),
607 #[error(transparent)]
608 TransactionCommit(#[from] TransactionCommitError),
609}
610
611#[derive(Clone)]
614pub struct RepoLoader {
615 settings: UserSettings,
616 store: Arc<Store>,
617 op_store: Arc<dyn OpStore>,
618 op_heads_store: Arc<dyn OpHeadsStore>,
619 index_store: Arc<dyn IndexStore>,
620 submodule_store: Arc<dyn SubmoduleStore>,
621}
622
623impl RepoLoader {
624 pub fn new(
625 settings: UserSettings,
626 store: Arc<Store>,
627 op_store: Arc<dyn OpStore>,
628 op_heads_store: Arc<dyn OpHeadsStore>,
629 index_store: Arc<dyn IndexStore>,
630 submodule_store: Arc<dyn SubmoduleStore>,
631 ) -> Self {
632 Self {
633 settings,
634 store,
635 op_store,
636 op_heads_store,
637 index_store,
638 submodule_store,
639 }
640 }
641
642 pub fn init_from_file_system(
646 settings: &UserSettings,
647 repo_path: &Path,
648 store_factories: &StoreFactories,
649 ) -> Result<Self, StoreLoadError> {
650 let merge_options =
651 MergeOptions::from_settings(settings).map_err(|err| BackendLoadError(err.into()))?;
652 let store = Store::new(
653 store_factories.load_backend(settings, &repo_path.join("store"))?,
654 Signer::from_settings(settings)?,
655 merge_options,
656 );
657 let root_op_data = RootOperationData {
658 root_commit_id: store.root_commit_id().clone(),
659 };
660 let op_store = Arc::from(store_factories.load_op_store(
661 settings,
662 &repo_path.join("op_store"),
663 root_op_data,
664 )?);
665 let op_heads_store =
666 Arc::from(store_factories.load_op_heads_store(settings, &repo_path.join("op_heads"))?);
667 let index_store =
668 Arc::from(store_factories.load_index_store(settings, &repo_path.join("index"))?);
669 let submodule_store = Arc::from(
670 store_factories.load_submodule_store(settings, &repo_path.join("submodule_store"))?,
671 );
672 Ok(Self {
673 settings: settings.clone(),
674 store,
675 op_store,
676 op_heads_store,
677 index_store,
678 submodule_store,
679 })
680 }
681
682 pub fn settings(&self) -> &UserSettings {
683 &self.settings
684 }
685
686 pub fn store(&self) -> &Arc<Store> {
687 &self.store
688 }
689
690 pub fn index_store(&self) -> &Arc<dyn IndexStore> {
691 &self.index_store
692 }
693
694 pub fn op_store(&self) -> &Arc<dyn OpStore> {
695 &self.op_store
696 }
697
698 pub fn op_heads_store(&self) -> &Arc<dyn OpHeadsStore> {
699 &self.op_heads_store
700 }
701
702 pub fn submodule_store(&self) -> &Arc<dyn SubmoduleStore> {
703 &self.submodule_store
704 }
705
706 pub async fn load_at_head(&self) -> Result<Arc<ReadonlyRepo>, RepoLoaderError> {
707 let op = op_heads_store::resolve_op_heads(
708 self.op_heads_store.as_ref(),
709 &self.op_store,
710 async |op_heads| -> Result<Operation, RepoLoaderError> {
711 assert!(op_heads.len() > 1);
712 let workspace_name = None;
713 let transaction_description = Some("reconcile divergent operations");
714 let transaction_attributes = [];
715 let (merged_repo, _num_rebased) = self
716 .merge_operations(
717 op_heads,
718 workspace_name,
719 transaction_description,
720 transaction_attributes,
721 )
722 .await?;
723 Ok(merged_repo.operation().clone())
724 },
725 )
726 .await?;
727 let view = op.view().await?;
728 self.finish_load(op, view).await
729 }
730
731 #[instrument(skip(self))]
732 pub async fn load_at(&self, op: &Operation) -> Result<Arc<ReadonlyRepo>, RepoLoaderError> {
733 let view = op.view().await?;
734 self.finish_load(op.clone(), view).await
735 }
736
737 pub fn create_from(
738 &self,
739 operation: Operation,
740 view: View,
741 index: Box<dyn ReadonlyIndex>,
742 ) -> Arc<ReadonlyRepo> {
743 let repo = ReadonlyRepo {
744 loader: self.clone(),
745 operation,
746 index,
747 change_id_index: OnceCell::new(),
748 view,
749 };
750 Arc::new(repo)
751 }
752
753 pub async fn root_operation(&self) -> Operation {
758 self.load_operation(self.op_store.root_operation_id())
759 .await
760 .expect("failed to read root operation")
761 }
762
763 pub async fn load_operation(&self, id: &OperationId) -> OpStoreResult<Operation> {
765 let data = self.op_store.read_operation(id).await?;
766 Ok(Operation::new(self.op_store.clone(), id.clone(), data))
767 }
768
769 pub async fn merge_operations(
774 &self,
775 operations: Vec<Operation>,
776 workspace_name: Option<&WorkspaceName>,
777 transaction_description: Option<&str>,
778 transaction_attributes: impl IntoIterator<Item = (String, String)>,
779 ) -> Result<(Arc<ReadonlyRepo>, usize), RepoLoaderError> {
780 match &operations[..] {
786 [] => {
787 let root_operation = self.root_operation().await;
788 let root_repo = self.load_at(&root_operation).await?;
789 return Ok((root_repo, 0));
790 }
791 [op] => {
792 let repo = self.load_at(op).await?;
793 return Ok((repo, 0));
794 }
795 _ => {}
796 }
797
798 let mut num_rebased = 0;
799 let to_operation_ids =
800 |ops: &[Operation]| ops.iter().map(|op| op.id().clone()).collect_vec();
801 let operation_ids = to_operation_ids(&operations);
802
803 let mut merged_operations: HashMap<Vec<OperationId>, Operation> = HashMap::new();
805 let mut closest_common_ancestors: HashMap<_, Vec<Operation>> = HashMap::new();
808
809 let mut tx = self.load_at(&operations[0]).await?.start_transaction();
810 if let Some(workspace_name) = workspace_name {
811 tx.set_workspace_name(workspace_name);
812 }
813 for (key, value) in transaction_attributes {
814 tx.set_attribute(key, value);
815 }
816 let mut stack = vec![(1, operations, tx)];
817
818 while let Some((index, operations, mut tx)) = stack.pop() {
819 assert!(operations.len() > 1);
820 assert!(index <= operations.len());
821 if index == operations.len() {
822 let tx_description = transaction_description.map_or_else(
825 || format!("merge {} operations", operations.len()),
826 |tx_description| tx_description.to_string(),
827 );
828 let merged_repo = tx.write(tx_description).await?.leave_unpublished();
829 merged_operations.insert(
830 to_operation_ids(&operations),
831 merged_repo.operation().clone(),
832 );
833 continue;
834 }
835
836 let other_op = &operations[index];
837
838 let ancestor_ops = match closest_common_ancestors
842 .entry((to_operation_ids(tx.parent_ops()), other_op.id().clone()))
843 {
844 Entry::Occupied(occupied_entry) => occupied_entry.into_mut(),
845 Entry::Vacant(vacant_entry) => {
846 let ancestor_ops = op_walk::closest_common_ancestors(
847 tx.parent_ops().to_vec(),
848 [other_op.clone()],
849 )
850 .await?;
851 vacant_entry.insert(ancestor_ops.clone())
852 }
853 };
854 assert!(!ancestor_ops.is_empty());
855
856 let ancestor_op = if let [ancestor_op] = ancestor_ops.as_slice() {
857 Some(ancestor_op)
859 } else {
860 let ancestor_op_ids = ancestor_ops.iter().map(|op| op.id().clone()).collect_vec();
863 merged_operations.get(&ancestor_op_ids)
864 };
865
866 if let Some(merged_ancestor_op) = ancestor_op {
867 tx.merge_operation(merged_ancestor_op, other_op).await?;
870 num_rebased += tx.repo_mut().rebase_descendants().await?;
871 stack.push((index + 1, operations, tx));
873 continue;
874 }
875
876 stack.push((index, operations, tx));
880 let new_tx = self.load_at(&ancestor_ops[0]).await?.start_transaction();
883 stack.push((1, ancestor_ops.clone(), new_tx));
884 }
885
886 let merged_operation = merged_operations.get(&operation_ids).cloned().unwrap();
888 Ok((self.load_at(&merged_operation).await?, num_rebased))
889 }
890
891 async fn finish_load(
892 &self,
893 operation: Operation,
894 view: View,
895 ) -> Result<Arc<ReadonlyRepo>, RepoLoaderError> {
896 let index = self
897 .index_store
898 .get_index_at_op(&operation, &self.store)
899 .await?;
900 let repo = ReadonlyRepo {
901 loader: self.clone(),
902 operation,
903 index,
904 change_id_index: OnceCell::new(),
905 view,
906 };
907 Ok(Arc::new(repo))
908 }
909}
910
911#[derive(Clone, Debug, PartialEq, Eq)]
912enum Rewrite {
913 Rewritten(CommitId),
916 Divergent(Vec<CommitId>),
919 Abandoned(Vec<CommitId>),
922}
923
924impl Rewrite {
925 fn new_parent_ids(&self) -> &[CommitId] {
926 match self {
927 Self::Rewritten(new_parent_id) => std::slice::from_ref(new_parent_id),
928 Self::Divergent(new_parent_ids) => new_parent_ids.as_slice(),
929 Self::Abandoned(new_parent_ids) => new_parent_ids.as_slice(),
930 }
931 }
932}
933
934pub struct MutableRepo {
935 base_repo: Arc<ReadonlyRepo>,
936 index: Box<dyn MutableIndex>,
937 view: View,
938 commit_predecessors: BTreeMap<CommitId, Vec<CommitId>>,
943 parent_mapping: HashMap<CommitId, Rewrite>,
952}
953
954impl MutableRepo {
955 pub fn new(base_repo: Arc<ReadonlyRepo>, index: &dyn ReadonlyIndex, view: &View) -> Self {
956 let mut_index = index.start_modification();
957 Self {
958 base_repo,
959 index: mut_index,
960 view: view.clone(),
961 commit_predecessors: Default::default(),
962 parent_mapping: Default::default(),
963 }
964 }
965
966 pub fn base_repo(&self) -> &Arc<ReadonlyRepo> {
967 &self.base_repo
968 }
969
970 pub fn mutable_index(&self) -> &dyn MutableIndex {
971 self.index.as_ref()
972 }
973
974 pub(crate) fn is_backed_by_default_index(&self) -> bool {
975 self.index.downcast_ref::<DefaultMutableIndex>().is_some()
976 }
977
978 pub fn has_changes(&self) -> bool {
979 !(self.commit_predecessors.is_empty()
980 && self.parent_mapping.is_empty()
981 && self.view() == &self.base_repo.view)
982 }
983
984 pub async fn consume(
985 mut self,
986 ) -> IndexResult<(
987 Box<dyn MutableIndex>,
988 View,
989 BTreeMap<CommitId, Vec<CommitId>>,
990 )> {
991 self.normalize_heads().await?;
992 Ok((self.index, self.view, self.commit_predecessors))
993 }
994
995 pub fn new_commit(&mut self, parents: Vec<CommitId>, tree: MergedTree) -> CommitBuilder<'_> {
997 let settings = self.base_repo.settings();
998 DetachedCommitBuilder::for_new_commit(self, settings, parents, tree).attach(self)
999 }
1000
1001 pub fn rewrite_commit(&mut self, predecessor: &Commit) -> CommitBuilder<'_> {
1003 let settings = self.base_repo.settings();
1004 DetachedCommitBuilder::for_rewrite_from(self, settings, predecessor).attach(self)
1005 }
1008
1009 pub(crate) fn set_predecessors(&mut self, id: CommitId, predecessors: Vec<CommitId>) {
1010 self.commit_predecessors.insert(id, predecessors);
1011 }
1012
1013 pub fn set_rewritten_commit(&mut self, old_id: CommitId, new_id: CommitId) {
1020 assert_ne!(old_id, *self.store().root_commit_id());
1021 self.parent_mapping
1022 .insert(old_id, Rewrite::Rewritten(new_id));
1023 }
1024
1025 pub fn set_divergent_rewrite(
1033 &mut self,
1034 old_id: CommitId,
1035 new_ids: impl IntoIterator<Item = CommitId>,
1036 ) {
1037 assert_ne!(old_id, *self.store().root_commit_id());
1038 self.parent_mapping.insert(
1039 old_id.clone(),
1040 Rewrite::Divergent(new_ids.into_iter().collect()),
1041 );
1042 }
1043
1044 pub fn record_abandoned_commit(&mut self, old_commit: &Commit) {
1054 assert_ne!(old_commit.id(), self.store().root_commit_id());
1055 self.record_abandoned_commit_with_parents(
1057 old_commit.id().clone(),
1058 old_commit.parent_ids().iter().cloned(),
1059 );
1060 }
1061
1062 pub fn record_abandoned_commit_with_parents(
1068 &mut self,
1069 old_id: CommitId,
1070 new_parent_ids: impl IntoIterator<Item = CommitId>,
1071 ) {
1072 assert_ne!(old_id, *self.store().root_commit_id());
1073 self.parent_mapping.insert(
1074 old_id,
1075 Rewrite::Abandoned(new_parent_ids.into_iter().collect()),
1076 );
1077 }
1078
1079 pub fn has_rewrites(&self) -> bool {
1080 !self.parent_mapping.is_empty()
1081 }
1082
1083 pub fn new_parents(&self, old_ids: &[CommitId]) -> Vec<CommitId> {
1090 self.rewritten_ids_with(old_ids, |rewrite| !matches!(rewrite, Rewrite::Divergent(_)))
1091 }
1092
1093 async fn normalize_heads(&mut self) -> IndexResult<()> {
1094 self.view
1095 .normalize_heads(
1096 self.index.as_index(),
1097 self.base_repo.store().root_commit_id(),
1098 )
1099 .await
1100 }
1101
1102 fn rewritten_ids_with(
1103 &self,
1104 old_ids: &[CommitId],
1105 mut predicate: impl FnMut(&Rewrite) -> bool,
1106 ) -> Vec<CommitId> {
1107 assert!(!old_ids.is_empty());
1108 let mut new_ids = Vec::with_capacity(old_ids.len());
1109 let mut to_visit = old_ids.iter().rev().collect_vec();
1110 let mut visited = HashSet::new();
1111 while let Some(id) = to_visit.pop() {
1112 if !visited.insert(id) {
1113 continue;
1114 }
1115 match self.parent_mapping.get(id).filter(|&v| predicate(v)) {
1116 None => {
1117 new_ids.push(id.clone());
1118 }
1119 Some(rewrite) => {
1120 let replacements = rewrite.new_parent_ids();
1121 assert!(
1122 !replacements.is_empty(),
1127 "Found empty value for key {id:?} in the parent mapping",
1128 );
1129 to_visit.extend(replacements.iter().rev());
1130 }
1131 }
1132 }
1133 assert!(
1134 !new_ids.is_empty(),
1135 "new ids become empty because of cycle in the parent mapping"
1136 );
1137 debug_assert!(new_ids.iter().all_unique());
1138 new_ids
1139 }
1140
1141 fn resolve_rewrite_mapping_with(
1145 &self,
1146 mut predicate: impl FnMut(&Rewrite) -> bool,
1147 ) -> BackendResult<HashMap<CommitId, Vec<CommitId>>> {
1148 let sorted_ids = dag_walk::topo_order_forward(
1149 self.parent_mapping.keys(),
1150 |&id| id,
1151 |&id| match self.parent_mapping.get(id).filter(|&v| predicate(v)) {
1152 None => &[],
1153 Some(rewrite) => rewrite.new_parent_ids(),
1154 },
1155 |id| {
1156 BackendError::Other(
1157 format!("Cycle between rewritten commits involving commit {id}").into(),
1158 )
1159 },
1160 )?;
1161 let mut new_mapping: HashMap<CommitId, Vec<CommitId>> = HashMap::new();
1162 for old_id in sorted_ids {
1163 let Some(rewrite) = self.parent_mapping.get(old_id).filter(|&v| predicate(v)) else {
1164 continue;
1165 };
1166 let lookup = |id| new_mapping.get(id).map_or(slice::from_ref(id), |ids| ids);
1167 let new_ids = match rewrite.new_parent_ids() {
1168 [id] => lookup(id).to_vec(), ids => ids.iter().flat_map(lookup).unique().cloned().collect(),
1170 };
1171 debug_assert_eq!(
1172 new_ids,
1173 self.rewritten_ids_with(slice::from_ref(old_id), &mut predicate)
1174 );
1175 new_mapping.insert(old_id.clone(), new_ids);
1176 }
1177 Ok(new_mapping)
1178 }
1179
1180 pub async fn update_rewritten_references(
1183 &mut self,
1184 options: &RewriteRefsOptions,
1185 ) -> BackendResult<()> {
1186 self.update_all_references(options).await?;
1187 self.update_heads()
1188 .await
1189 .map_err(|err| err.into_backend_error())?;
1190 Ok(())
1191 }
1192
1193 async fn update_all_references(&mut self, options: &RewriteRefsOptions) -> BackendResult<()> {
1194 let rewrite_mapping = self.resolve_rewrite_mapping_with(|_| true)?;
1195 self.update_local_bookmarks(&rewrite_mapping, options)
1196 .await
1197 .map_err(|err| BackendError::Other(err.into()))?;
1199 self.update_wc_commits(&rewrite_mapping).await?;
1200 Ok(())
1201 }
1202
1203 async fn update_local_bookmarks(
1204 &mut self,
1205 rewrite_mapping: &HashMap<CommitId, Vec<CommitId>>,
1206 options: &RewriteRefsOptions,
1207 ) -> IndexResult<()> {
1208 let changed_branches = self
1209 .view()
1210 .local_bookmarks()
1211 .flat_map(|(name, target)| {
1212 target.added_ids().filter_map(|id| {
1213 let change = rewrite_mapping.get_key_value(id)?;
1214 Some((name.to_owned(), change))
1215 })
1216 })
1217 .collect_vec();
1218 for (bookmark_name, (old_commit_id, new_commit_ids)) in changed_branches {
1219 let should_delete = options.delete_abandoned_bookmarks
1220 && matches!(
1221 self.parent_mapping.get(old_commit_id),
1222 Some(Rewrite::Abandoned(_))
1223 );
1224 let old_target = RefTarget::normal(old_commit_id.clone());
1225 let new_target = if should_delete {
1226 RefTarget::absent()
1227 } else {
1228 let ids = itertools::intersperse(new_commit_ids, old_commit_id)
1229 .map(|id| Some(id.clone()));
1230 RefTarget::from_merge(MergeBuilder::from_iter(ids).build())
1231 };
1232
1233 self.merge_local_bookmark(&bookmark_name, &old_target, &new_target)
1234 .await?;
1235 }
1236 Ok(())
1237 }
1238
1239 async fn update_wc_commits(
1240 &mut self,
1241 rewrite_mapping: &HashMap<CommitId, Vec<CommitId>>,
1242 ) -> BackendResult<()> {
1243 let changed_wc_commits = self
1244 .view()
1245 .wc_commit_ids()
1246 .iter()
1247 .filter_map(|(name, commit_id)| {
1248 let change = rewrite_mapping.get_key_value(commit_id)?;
1249 Some((name.to_owned(), change))
1250 })
1251 .collect_vec();
1252 let mut recreated_wc_commits: HashMap<&CommitId, Commit> = HashMap::new();
1253 for (name, (old_commit_id, new_commit_ids)) in changed_wc_commits {
1254 let abandoned_old_commit = matches!(
1255 self.parent_mapping.get(old_commit_id),
1256 Some(Rewrite::Abandoned(_))
1257 );
1258 let new_wc_commit = if !abandoned_old_commit {
1259 self.store().get_commit_async(&new_commit_ids[0]).await?
1261 } else if let Some(commit) = recreated_wc_commits.get(old_commit_id) {
1262 commit.clone()
1263 } else {
1264 let new_commit_futures = new_commit_ids
1265 .iter()
1266 .map(async |id| self.store().get_commit_async(id).await);
1267 let new_commits = try_join_all(new_commit_futures).await?;
1268 let merged_parents_tree = merge_commit_trees(self, &new_commits).await?;
1269 let commit = self
1270 .new_commit(new_commit_ids.clone(), merged_parents_tree)
1271 .write()
1272 .await?;
1273 recreated_wc_commits.insert(old_commit_id, commit.clone());
1274 commit
1275 };
1276 self.edit(name, &new_wc_commit)
1277 .await
1278 .map_err(|err| match err {
1279 EditCommitError::BackendError(backend_error) => backend_error,
1280 EditCommitError::IndexError(index_error) => {
1282 BackendError::Other(index_error.into())
1283 }
1284 EditCommitError::WorkingCopyCommitNotFound(_)
1285 | EditCommitError::RewriteRootCommit(_) => panic!("unexpected error: {err:?}"),
1286 })?;
1287 }
1288 Ok(())
1289 }
1290
1291 async fn update_heads(&mut self) -> Result<(), RevsetEvaluationError> {
1292 let old_commits_expression =
1293 RevsetExpression::commits(self.parent_mapping.keys().cloned().collect())
1294 .intersection(&RevsetExpression::visible_heads().ancestors());
1295 let heads_to_add_expression = old_commits_expression
1296 .parents()
1297 .minus(&old_commits_expression);
1298 let heads_to_add: Vec<_> = heads_to_add_expression
1299 .evaluate(self)?
1300 .stream()
1301 .try_collect()
1302 .await?;
1303
1304 let mut view = self.view().store_view().clone();
1305 for commit_id in self.parent_mapping.keys() {
1306 view.head_ids.remove(commit_id);
1307 }
1308 view.head_ids.extend(heads_to_add);
1309 self.set_view(view);
1310 self.normalize_heads()
1312 .await
1313 .map_err(|err| RevsetEvaluationError::Other(Box::new(err)))?;
1314 Ok(())
1315 }
1316
1317 pub async fn find_descendants_for_rebase(
1320 &self,
1321 roots: Vec<CommitId>,
1322 immutable: &Arc<ResolvedRevsetExpression>,
1323 ) -> BackendResult<Vec<Commit>> {
1324 let to_visit_revset = RevsetExpression::commits(roots)
1325 .descendants()
1326 .minus(immutable)
1327 .minus(&RevsetExpression::commits(
1328 self.parent_mapping.keys().cloned().collect(),
1329 ))
1330 .evaluate(self)
1331 .map_err(|err| err.into_backend_error())?;
1332 let to_visit = to_visit_revset
1333 .stream()
1334 .commits(self.store())
1335 .try_collect()
1336 .await
1337 .map_err(|err| err.into_backend_error())?;
1338 Ok(to_visit)
1339 }
1340
1341 async fn order_commits_for_rebase(
1344 &self,
1345 to_visit: Vec<Commit>,
1346 new_parents_map: &HashMap<CommitId, Vec<CommitId>>,
1347 ) -> BackendResult<Vec<Commit>> {
1348 let to_visit_set: HashSet<CommitId> =
1349 to_visit.iter().map(|commit| commit.id().clone()).collect();
1350 let mut visited = HashSet::new();
1351 let store = self.store();
1354 dag_walk_async::topo_order_reverse(
1355 to_visit.into_iter().map(Ok),
1356 |commit| commit.id().clone(),
1357 async |commit| -> Vec<BackendResult<Commit>> {
1358 visited.insert(commit.id().clone());
1359 let mut dependents = vec![];
1360 let parent_ids = new_parents_map
1361 .get(commit.id())
1362 .map_or(commit.parent_ids(), |parent_ids| parent_ids);
1363 for parent_id in parent_ids {
1364 let parent = store.get_commit_async(parent_id).await;
1365 let Ok(parent) = parent else {
1366 dependents.push(parent);
1367 continue;
1368 };
1369 if let Some(rewrite) = self.parent_mapping.get(parent.id()) {
1370 for target in rewrite.new_parent_ids() {
1371 if to_visit_set.contains(target) && !visited.contains(target) {
1372 dependents.push(store.get_commit_async(target).await);
1373 }
1374 }
1375 }
1376 if to_visit_set.contains(parent.id()) {
1377 dependents.push(Ok(parent));
1378 }
1379 }
1380 dependents
1381 },
1382 |_| panic!("graph has cycle"),
1383 )
1384 .await
1385 }
1386
1387 pub async fn transform_descendants(
1399 &mut self,
1400 roots: Vec<CommitId>,
1401 callback: impl AsyncFnMut(CommitRewriter) -> BackendResult<()>,
1402 ) -> BackendResult<()> {
1403 self.transform_descendants_with_options(
1404 roots,
1405 &RevsetExpression::none(),
1406 &HashMap::new(),
1407 &RewriteRefsOptions::default(),
1408 callback,
1409 )
1410 .await
1411 }
1412
1413 pub async fn transform_descendants_with_options(
1423 &mut self,
1424 roots: Vec<CommitId>,
1425 immutable: &Arc<ResolvedRevsetExpression>,
1426 new_parents_map: &HashMap<CommitId, Vec<CommitId>>,
1427 options: &RewriteRefsOptions,
1428 callback: impl AsyncFnMut(CommitRewriter) -> BackendResult<()>,
1429 ) -> BackendResult<()> {
1430 let descendants = self.find_descendants_for_rebase(roots, immutable).await?;
1431 self.transform_commits(descendants, new_parents_map, options, callback)
1432 .await
1433 }
1434
1435 pub async fn transform_commits(
1441 &mut self,
1442 commits: Vec<Commit>,
1443 new_parents_map: &HashMap<CommitId, Vec<CommitId>>,
1444 options: &RewriteRefsOptions,
1445 mut callback: impl AsyncFnMut(CommitRewriter) -> BackendResult<()>,
1446 ) -> BackendResult<()> {
1447 let mut to_visit = self
1448 .order_commits_for_rebase(commits, new_parents_map)
1449 .await?;
1450 while let Some(old_commit) = to_visit.pop() {
1451 let parent_ids = new_parents_map
1452 .get(old_commit.id())
1453 .map_or(old_commit.parent_ids(), |parent_ids| parent_ids);
1454 let new_parent_ids = self.new_parents(parent_ids);
1455 let rewriter = CommitRewriter::new(self, old_commit, new_parent_ids);
1456 callback(rewriter).await?;
1457 }
1458 self.update_rewritten_references(options).await?;
1459 Ok(())
1469 }
1470
1471 pub async fn rebase_descendants_with_options(
1489 &mut self,
1490 immutable: &Arc<ResolvedRevsetExpression>,
1491 options: &RebaseOptions,
1492 mut progress: impl FnMut(Commit, RebasedCommit),
1493 ) -> BackendResult<()> {
1494 let roots = self.parent_mapping.keys().cloned().collect();
1495 self.transform_descendants_with_options(
1496 roots,
1497 immutable,
1498 &HashMap::new(),
1499 &options.rewrite_refs,
1500 async |rewriter| {
1501 if rewriter.parents_changed() {
1502 let old_commit = rewriter.old_commit().clone();
1503 let rebased_commit = rebase_commit_with_options(rewriter, options).await?;
1504 progress(old_commit, rebased_commit);
1505 }
1506 Ok(())
1507 },
1508 )
1509 .await?;
1510 self.parent_mapping.clear();
1511 Ok(())
1512 }
1513
1514 pub async fn rebase_descendants(&mut self) -> BackendResult<usize> {
1524 let mut num_rebased = 0;
1525 self.rebase_descendants_with_options(
1526 &RevsetExpression::none(),
1527 &RebaseOptions::default(),
1528 |_old_commit, _rebased_commit| {
1529 num_rebased += 1;
1530 },
1531 )
1532 .await?;
1533 Ok(num_rebased)
1534 }
1535
1536 pub async fn reparent_descendants(&mut self) -> BackendResult<usize> {
1543 let roots = self.parent_mapping.keys().cloned().collect_vec();
1544 let mut num_reparented = 0;
1545 self.transform_descendants(roots, async |rewriter| {
1546 if rewriter.parents_changed() {
1547 let builder = rewriter.reparent();
1548 builder.write().await?;
1549 num_reparented += 1;
1550 }
1551 Ok(())
1552 })
1553 .await?;
1554 self.parent_mapping.clear();
1555 Ok(num_reparented)
1556 }
1557
1558 pub fn set_wc_commit(
1559 &mut self,
1560 name: WorkspaceNameBuf,
1561 commit_id: CommitId,
1562 ) -> Result<(), RewriteRootCommit> {
1563 if &commit_id == self.store().root_commit_id() {
1564 return Err(RewriteRootCommit);
1565 }
1566 self.view.set_wc_commit(name, commit_id);
1567 Ok(())
1568 }
1569
1570 pub async fn remove_wc_commit(&mut self, name: &WorkspaceName) -> Result<(), EditCommitError> {
1571 self.maybe_abandon_wc_commit(name).await?;
1572 self.view.remove_wc_commit(name);
1573 Ok(())
1574 }
1575
1576 fn merge_wc_commit(
1579 &mut self,
1580 name: &WorkspaceName,
1581 base_id: Option<&CommitId>,
1582 other_id: Option<&CommitId>,
1583 ) {
1584 let self_id = self.view.get_wc_commit_id(name);
1585 let new_id = if let Some(resolved) =
1589 trivial_merge(&[self_id, base_id, other_id], SameChange::Accept)
1590 {
1591 resolved.cloned()
1592 } else if self_id.is_none() || other_id.is_none() {
1593 None
1596 } else {
1597 self_id.cloned()
1598 };
1599 match new_id {
1600 Some(id) => self.view.set_wc_commit(name.to_owned(), id),
1601 None => self.view.remove_wc_commit(name),
1602 }
1603 }
1604
1605 pub fn rename_workspace(
1606 &mut self,
1607 old_name: &WorkspaceName,
1608 new_name: WorkspaceNameBuf,
1609 ) -> Result<(), RenameWorkspaceError> {
1610 self.view.rename_workspace(old_name, new_name)
1611 }
1612
1613 pub async fn check_out(
1614 &mut self,
1615 name: WorkspaceNameBuf,
1616 commit: &Commit,
1617 ) -> Result<Commit, CheckOutCommitError> {
1618 let wc_commit = self
1619 .new_commit(vec![commit.id().clone()], commit.tree())
1620 .write()
1621 .await?;
1622 self.edit(name, &wc_commit).await?;
1623 Ok(wc_commit)
1624 }
1625
1626 pub async fn edit(
1627 &mut self,
1628 name: WorkspaceNameBuf,
1629 commit: &Commit,
1630 ) -> Result<(), EditCommitError> {
1631 self.maybe_abandon_wc_commit(&name).await?;
1632 self.add_head(commit).await?;
1633 Ok(self.set_wc_commit(name, commit.id().clone())?)
1634 }
1635
1636 async fn maybe_abandon_wc_commit(
1637 &mut self,
1638 workspace_name: &WorkspaceName,
1639 ) -> Result<(), EditCommitError> {
1640 let is_commit_referenced = |view: &View, commit_id: &CommitId| -> bool {
1641 itertools::chain!(
1642 view.wc_commit_ids()
1643 .iter()
1644 .filter(|&(name, _)| name != workspace_name)
1645 .map(|(_, wc_id)| wc_id),
1646 view.local_bookmarks()
1647 .flat_map(|(_, target)| target.added_ids()),
1648 view.local_tags().flat_map(|(_, target)| target.added_ids()),
1649 )
1650 .any(|id| id == commit_id)
1651 };
1652
1653 let maybe_wc_commit_id = self.view.get_wc_commit_id(workspace_name).cloned();
1654 if let Some(wc_commit_id) = maybe_wc_commit_id {
1655 let wc_commit = self
1656 .store()
1657 .get_commit_async(&wc_commit_id)
1658 .await
1659 .map_err(EditCommitError::WorkingCopyCommitNotFound)?;
1660 self.normalize_heads().await?;
1663 if wc_commit.is_discardable(self).await?
1664 && !is_commit_referenced(&self.view, wc_commit.id())
1665 && self.view().heads().contains(wc_commit.id())
1666 {
1667 self.record_abandoned_commit(&wc_commit);
1671 }
1672 }
1673
1674 Ok(())
1675 }
1676
1677 pub async fn add_head(&mut self, head: &Commit) -> BackendResult<()> {
1680 self.add_heads(slice::from_ref(head)).await
1681 }
1682
1683 pub async fn add_heads(&mut self, heads: &[Commit]) -> BackendResult<()> {
1690 let current_heads = self.view.heads();
1691 match heads {
1695 [] => {}
1696 [head]
1697 if head
1698 .parent_ids()
1699 .iter()
1700 .all(|parent_id| current_heads.contains(parent_id)) =>
1701 {
1702 self.index
1703 .add_commit(head)
1704 .await
1705 .map_err(|err| BackendError::Other(err.into()))?;
1707 self.view
1708 .replace_heads(head.id().clone(), head.parent_ids());
1709 }
1710 _ => {
1711 self.index_commits(heads).await?;
1712 for head in heads {
1713 self.view.add_head(head.id());
1714 }
1715 }
1716 }
1717 Ok(())
1718 }
1719
1720 pub fn remove_head(&mut self, head: &CommitId) {
1721 self.view.remove_head(head);
1722 }
1723
1724 pub async fn index_commits(&mut self, heads: &[Commit]) -> BackendResult<Vec<Commit>> {
1727 let missing_commits = dag_walk_async::topo_order_reverse_ord(
1728 heads
1729 .iter()
1730 .filter_map(|commit| match self.index().has_id(commit.id()) {
1731 Ok(false) => Some(Ok(CommitByCommitterTimestamp(commit.clone()))),
1732 Ok(true) => None,
1733 Err(err) => Some(Err(BackendError::Other(err.into()))),
1735 }),
1736 |CommitByCommitterTimestamp(commit)| commit.id().clone(),
1737 async |CommitByCommitterTimestamp(commit)| {
1738 stream::iter(commit.parent_ids())
1739 .filter_map(async |id| match self.index().has_id(id) {
1740 Ok(false) => Some(
1741 self.store()
1742 .get_commit_async(id)
1743 .await
1744 .map(CommitByCommitterTimestamp),
1745 ),
1746 Ok(true) => None,
1747 Err(err) => Some(Err(BackendError::Other(err.into()))),
1749 })
1750 .collect::<Vec<_>>()
1751 .await
1752 },
1753 |_| panic!("graph has cycle"),
1754 )
1755 .await?;
1756 for CommitByCommitterTimestamp(missing_commit) in missing_commits.iter().rev() {
1757 self.index
1758 .add_commit(missing_commit)
1759 .await
1760 .map_err(|err| BackendError::Other(err.into()))?;
1762 }
1763 let indexed_commits = missing_commits
1764 .into_iter()
1765 .map(|CommitByCommitterTimestamp(commit)| commit)
1766 .collect();
1767 Ok(indexed_commits)
1768 }
1769
1770 pub fn get_local_bookmark(&self, name: &RefName) -> RefTarget {
1771 self.view.get_local_bookmark(name).clone()
1772 }
1773
1774 pub fn set_local_bookmark_target(&mut self, name: &RefName, target: RefTarget) {
1775 for id in target.added_ids() {
1776 self.view.add_head(id);
1777 }
1778 self.view.set_local_bookmark_target(name, target);
1779 }
1780
1781 pub async fn merge_local_bookmark(
1782 &mut self,
1783 name: &RefName,
1784 base_target: &RefTarget,
1785 other_target: &RefTarget,
1786 ) -> IndexResult<()> {
1787 let index = self.index.as_index();
1788 let self_target = self.view.get_local_bookmark(name);
1789 let new_target = merge_ref_targets(index, self_target, base_target, other_target).await?;
1790 self.set_local_bookmark_target(name, new_target);
1791 Ok(())
1792 }
1793
1794 pub fn get_remote_bookmark(&self, symbol: RemoteRefSymbol<'_>) -> RemoteRef {
1795 self.view.get_remote_bookmark(symbol).clone()
1796 }
1797
1798 pub fn set_remote_bookmark(&mut self, symbol: RemoteRefSymbol<'_>, remote_ref: RemoteRef) {
1799 self.view.set_remote_bookmark(symbol, remote_ref);
1800 }
1801
1802 async fn merge_remote_bookmark(
1803 &mut self,
1804 symbol: RemoteRefSymbol<'_>,
1805 base_ref: &RemoteRef,
1806 other_ref: &RemoteRef,
1807 ) -> IndexResult<()> {
1808 let index = self.index.as_index();
1809 let self_ref = self.view.get_remote_bookmark(symbol);
1810 let new_ref = merge_remote_refs(index, self_ref, base_ref, other_ref).await?;
1811 self.view.set_remote_bookmark(symbol, new_ref);
1812 Ok(())
1813 }
1814
1815 pub async fn track_remote_bookmark(&mut self, symbol: RemoteRefSymbol<'_>) -> IndexResult<()> {
1818 let mut remote_ref = self.get_remote_bookmark(symbol);
1819 let base_target = remote_ref.tracked_target();
1820 self.merge_local_bookmark(symbol.name, base_target, &remote_ref.target)
1821 .await?;
1822 remote_ref.state = RemoteRefState::Tracked;
1823 self.set_remote_bookmark(symbol, remote_ref);
1824 Ok(())
1825 }
1826
1827 pub fn untrack_remote_bookmark(&mut self, symbol: RemoteRefSymbol<'_>) {
1829 let mut remote_ref = self.get_remote_bookmark(symbol);
1830 remote_ref.state = RemoteRefState::New;
1831 self.set_remote_bookmark(symbol, remote_ref);
1832 }
1833
1834 pub fn ensure_remote(&mut self, remote_name: &RemoteName) {
1835 self.view.ensure_remote(remote_name);
1836 }
1837
1838 pub fn remove_remote(&mut self, remote_name: &RemoteName) {
1839 self.view.remove_remote(remote_name);
1840 }
1841
1842 pub fn rename_remote(&mut self, old: &RemoteName, new: &RemoteName) {
1843 self.view.rename_remote(old, new);
1844 }
1845
1846 pub fn get_local_tag(&self, name: &RefName) -> RefTarget {
1847 self.view.get_local_tag(name).clone()
1848 }
1849
1850 pub fn set_local_tag_target(&mut self, name: &RefName, target: RefTarget) {
1851 self.view.set_local_tag_target(name, target);
1852 }
1853
1854 pub async fn merge_local_tag(
1855 &mut self,
1856 name: &RefName,
1857 base_target: &RefTarget,
1858 other_target: &RefTarget,
1859 ) -> IndexResult<()> {
1860 let index = self.index.as_index();
1861 let self_target = self.view.get_local_tag(name);
1862 let new_target = merge_ref_targets(index, self_target, base_target, other_target).await?;
1863 self.view.set_local_tag_target(name, new_target);
1864 Ok(())
1865 }
1866
1867 pub fn get_remote_tag(&self, symbol: RemoteRefSymbol<'_>) -> RemoteRef {
1868 self.view.get_remote_tag(symbol).clone()
1869 }
1870
1871 pub fn set_remote_tag(&mut self, symbol: RemoteRefSymbol<'_>, remote_ref: RemoteRef) {
1872 self.view.set_remote_tag(symbol, remote_ref);
1873 }
1874
1875 async fn merge_remote_tag(
1876 &mut self,
1877 symbol: RemoteRefSymbol<'_>,
1878 base_ref: &RemoteRef,
1879 other_ref: &RemoteRef,
1880 ) -> IndexResult<()> {
1881 let index = self.index.as_index();
1882 let self_ref = self.view.get_remote_tag(symbol);
1883 let new_ref = merge_remote_refs(index, self_ref, base_ref, other_ref).await?;
1884 self.view.set_remote_tag(symbol, new_ref);
1885 Ok(())
1886 }
1887
1888 pub async fn track_remote_tag(&mut self, symbol: RemoteRefSymbol<'_>) -> IndexResult<()> {
1890 let mut remote_ref = self.get_remote_tag(symbol);
1891 let base_target = remote_ref.tracked_target();
1892 self.merge_local_tag(symbol.name, base_target, &remote_ref.target)
1893 .await?;
1894 remote_ref.state = RemoteRefState::Tracked;
1895 self.set_remote_tag(symbol, remote_ref);
1896 Ok(())
1897 }
1898
1899 pub fn untrack_remote_tag(&mut self, symbol: RemoteRefSymbol<'_>) {
1901 let mut remote_ref = self.get_remote_tag(symbol);
1902 remote_ref.state = RemoteRefState::New;
1903 self.set_remote_tag(symbol, remote_ref);
1904 }
1905
1906 pub fn get_git_ref(&self, name: &GitRefName) -> RefTarget {
1907 self.view.get_git_ref(name).clone()
1908 }
1909
1910 pub fn set_git_ref_target(&mut self, name: &GitRefName, target: RefTarget) {
1911 self.view.set_git_ref_target(name, target);
1912 }
1913
1914 async fn merge_git_ref(
1915 &mut self,
1916 name: &GitRefName,
1917 base_target: &RefTarget,
1918 other_target: &RefTarget,
1919 ) -> IndexResult<()> {
1920 let index = self.index.as_index();
1921 let self_target = self.view.get_git_ref(name);
1922 let new_target = merge_ref_targets(index, self_target, base_target, other_target).await?;
1923 self.view.set_git_ref_target(name, new_target);
1924 Ok(())
1925 }
1926
1927 pub fn git_head(&self) -> RefTarget {
1928 self.view.git_head().clone()
1929 }
1930
1931 pub fn set_git_head_target(&mut self, target: RefTarget) {
1932 self.view.set_git_head_target(target);
1933 }
1934
1935 pub fn set_view(&mut self, data: op_store::View) {
1936 let head_normalized = false;
1937 self.view.set_view(data, head_normalized);
1938 }
1939
1940 pub async fn merge(
1941 &mut self,
1942 base_repo: &ReadonlyRepo,
1943 other_repo: &ReadonlyRepo,
1944 ) -> Result<(), RepoLoaderError> {
1945 self.index.merge_in(base_repo.readonly_index())?;
1950 self.index.merge_in(other_repo.readonly_index())?;
1951
1952 self.normalize_heads().await?;
1953
1954 self.merge_view(&base_repo.view, &other_repo.view).await?;
1955 Ok(())
1956 }
1957
1958 pub fn merge_index(&mut self, other_repo: &ReadonlyRepo) -> IndexResult<()> {
1959 self.index.merge_in(other_repo.readonly_index())
1960 }
1961
1962 async fn merge_view(&mut self, base: &View, other: &View) -> Result<(), RepoLoaderError> {
1963 let changed_wc_commits = diff_named_commit_ids(base.wc_commit_ids(), other.wc_commit_ids());
1964 for (name, (base_id, other_id)) in changed_wc_commits {
1965 self.merge_wc_commit(name, base_id, other_id);
1966 }
1967
1968 let base_heads = base.heads().iter().cloned().collect_vec();
1969 let own_heads = self.view().heads().iter().cloned().collect_vec();
1970 let other_heads = other.heads().iter().cloned().collect_vec();
1971
1972 if self.is_backed_by_default_index() {
1979 self.record_rewrites(&base_heads, &own_heads).await?;
1980 self.record_rewrites(&base_heads, &other_heads).await?;
1981 } else {
1984 for removed_head in base.heads().difference(other.heads()) {
1985 self.view.remove_head(removed_head);
1986 }
1987 }
1988 for added_head in other.heads().difference(base.heads()) {
1989 self.view.add_head(added_head);
1990 }
1991
1992 let changed_local_bookmarks =
1993 diff_named_ref_targets(base.local_bookmarks(), other.local_bookmarks());
1994 for (name, (base_target, other_target)) in changed_local_bookmarks {
1995 self.merge_local_bookmark(name, base_target, other_target)
1996 .await?;
1997 }
1998
1999 let changed_local_tags = diff_named_ref_targets(base.local_tags(), other.local_tags());
2000 for (name, (base_target, other_target)) in changed_local_tags {
2001 self.merge_local_tag(name, base_target, other_target)
2002 .await?;
2003 }
2004
2005 let changed_git_refs = diff_named_ref_targets(base.git_refs(), other.git_refs());
2006 for (name, (base_target, other_target)) in changed_git_refs {
2007 self.merge_git_ref(name, base_target, other_target).await?;
2008 }
2009
2010 let changed_remote_bookmarks =
2011 diff_named_remote_refs(base.all_remote_bookmarks(), other.all_remote_bookmarks());
2012 for (symbol, (base_ref, other_ref)) in changed_remote_bookmarks {
2013 self.merge_remote_bookmark(symbol, base_ref, other_ref)
2014 .await?;
2015 }
2016
2017 let changed_remote_tags =
2018 diff_named_remote_refs(base.all_remote_tags(), other.all_remote_tags());
2019 for (symbol, (base_ref, other_ref)) in changed_remote_tags {
2020 self.merge_remote_tag(symbol, base_ref, other_ref).await?;
2021 }
2022
2023 let new_git_head_target = merge_ref_targets(
2024 self.index(),
2025 self.view().git_head(),
2026 base.git_head(),
2027 other.git_head(),
2028 )
2029 .await?;
2030 self.set_git_head_target(new_git_head_target);
2031
2032 Ok(())
2033 }
2034
2035 async fn record_rewrites(
2038 &mut self,
2039 old_heads: &[CommitId],
2040 new_heads: &[CommitId],
2041 ) -> BackendResult<()> {
2042 let mut removed_changes: HashMap<ChangeId, Vec<CommitId>> = HashMap::new();
2043 {
2044 let mut stream = revset::walk_revs(self, old_heads, new_heads)
2045 .map_err(|err| err.into_backend_error())?
2046 .commit_change_ids();
2047 while let Some((commit_id, change_id)) = stream
2048 .try_next()
2049 .await
2050 .map_err(|err| err.into_backend_error())?
2051 {
2052 removed_changes
2053 .entry(change_id)
2054 .or_default()
2055 .push(commit_id);
2056 }
2057 }
2058 if removed_changes.is_empty() {
2059 return Ok(());
2060 }
2061
2062 let mut rewritten_changes = HashSet::new();
2063 let mut rewritten_commits: HashMap<CommitId, Vec<CommitId>> = HashMap::new();
2064 {
2065 let mut stream = revset::walk_revs(self, new_heads, old_heads)
2066 .map_err(|err| err.into_backend_error())?
2067 .commit_change_ids();
2068 while let Some((commit_id, change_id)) = stream
2069 .try_next()
2070 .await
2071 .map_err(|err| err.into_backend_error())?
2072 {
2073 if let Some(old_commits) = removed_changes.get(&change_id) {
2074 for old_commit in old_commits {
2075 rewritten_commits
2076 .entry(old_commit.clone())
2077 .or_default()
2078 .push(commit_id.clone());
2079 }
2080 }
2081 rewritten_changes.insert(change_id);
2082 }
2083 }
2084 for (old_commit, new_commits) in rewritten_commits {
2085 if new_commits.len() == 1 {
2086 self.set_rewritten_commit(
2087 old_commit.clone(),
2088 new_commits.into_iter().next().unwrap(),
2089 );
2090 } else {
2091 self.set_divergent_rewrite(old_commit.clone(), new_commits);
2092 }
2093 }
2094
2095 for (change_id, removed_commit_ids) in &removed_changes {
2096 if !rewritten_changes.contains(change_id) {
2097 for id in removed_commit_ids {
2098 let commit = self.store().get_commit_async(id).await?;
2099 self.record_abandoned_commit(&commit);
2100 }
2101 }
2102 }
2103
2104 Ok(())
2105 }
2106}
2107
2108impl Repo for MutableRepo {
2109 fn base_repo(&self) -> &ReadonlyRepo {
2110 &self.base_repo
2111 }
2112
2113 fn store(&self) -> &Arc<Store> {
2114 self.base_repo.store()
2115 }
2116
2117 fn op_store(&self) -> &Arc<dyn OpStore> {
2118 self.base_repo.op_store()
2119 }
2120
2121 fn index(&self) -> &dyn Index {
2122 self.index.as_index()
2123 }
2124
2125 fn view(&self) -> &View {
2126 &self.view
2127 }
2128
2129 fn submodule_store(&self) -> &Arc<dyn SubmoduleStore> {
2130 self.base_repo.submodule_store()
2131 }
2132
2133 fn resolve_change_id_prefix(
2134 &self,
2135 prefix: &HexPrefix,
2136 ) -> IndexResult<PrefixResolution<ResolvedChangeTargets>> {
2137 let change_id_index = self.index.change_id_index(&mut self.view().heads().iter());
2138 change_id_index.resolve_prefix(prefix)
2139 }
2140
2141 fn shortest_unique_change_id_prefix_len(&self, target_id: &ChangeId) -> IndexResult<usize> {
2142 let change_id_index = self.index.change_id_index(&mut self.view().heads().iter());
2143 change_id_index.shortest_unique_prefix_len(target_id)
2144 }
2145}
2146
2147#[derive(Debug, Error)]
2149#[error("Cannot rewrite the root commit")]
2150pub struct RewriteRootCommit;
2151
2152#[derive(Debug, Error)]
2154pub enum EditCommitError {
2155 #[error("Current working-copy commit not found")]
2156 WorkingCopyCommitNotFound(#[source] BackendError),
2157 #[error(transparent)]
2158 RewriteRootCommit(#[from] RewriteRootCommit),
2159 #[error(transparent)]
2160 BackendError(#[from] BackendError),
2161 #[error(transparent)]
2162 IndexError(#[from] IndexError),
2163}
2164
2165#[derive(Debug, Error)]
2167pub enum CheckOutCommitError {
2168 #[error("Failed to create new working-copy commit")]
2169 CreateCommit(#[from] BackendError),
2170 #[error("Failed to edit commit")]
2171 EditCommit(#[from] EditCommitError),
2172}