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