Implement tree reconciliation toggle and enhance git functionality

- Introduced a constant to enable or disable periodic tree reconciliation after VFS events, addressing a persistent drift bug that caused infinite re-snapshot loops on large projects.
- Updated the `ChangeProcessor` to conditionally execute tree reconciliation based on the new constant, improving performance during file modifications.
- Enhanced the git module by adding new functions for shallow cloning and checking if files are staged, streamlining git operations.
- Refactored the `InitCommand` to utilize the new git functions for repository initialization and cloning, improving clarity and reducing redundancy.

These changes aim to optimize file change handling and enhance git integration within the project.
This commit is contained in:
Joe 2026-03-01 18:16:03 -06:00
parent 1a03554ee8
commit 76b5d8bc75
7 changed files with 248 additions and 373 deletions

View file

@ -23,6 +23,12 @@ use crate::{
},
};
/// Set to `true` to enable periodic tree reconciliation after VFS events.
/// Currently disabled: the per-event VFS handler handles file changes correctly,
/// and the reconciler has a persistent drift bug that causes an infinite
/// 12-14s re-snapshot loop on large projects.
const ENABLE_TREE_RECONCILIATION: bool = false;
/// Wrapper that displays a path relative to a project root directory.
struct RelPath<'a> {
path: &'a Path,
@ -156,18 +162,20 @@ impl ChangeProcessor {
}
}
// Schedule a reconciliation 200ms from now if one isn't pending.
if reconcile_at.is_none() {
reconcile_at = Some(Instant::now() + Duration::from_millis(200));
}
if ENABLE_TREE_RECONCILIATION {
// Schedule a reconciliation 200ms from now if one isn't pending.
if reconcile_at.is_none() {
reconcile_at = Some(Instant::now() + Duration::from_millis(200));
}
// If the deadline has passed, reconcile now. This check runs
// inside the VFS branch because during sustained event bursts,
// the `default` branch never fires (the VFS channel is never
// idle long enough).
if reconcile_at.is_some_and(|d| Instant::now() >= d) {
task.reconcile_tree();
reconcile_at = None;
// If the deadline has passed, reconcile now. This check runs
// inside the VFS branch because during sustained event bursts,
// the `default` branch never fires (the VFS channel is never
// idle long enough).
if reconcile_at.is_some_and(|d| Instant::now() >= d) {
task.reconcile_tree();
reconcile_at = None;
}
}
},
recv(tree_mutation_receiver) -> patch_set => {
@ -175,12 +183,19 @@ impl ChangeProcessor {
},
recv(critical_error_receiver) -> err => {
if let Ok(memofs::WatcherCriticalError::RescanRequired) = err {
log::warn!(
"VFS watcher lost events (RescanRequired). \
Triggering full tree reconciliation."
);
task.reconcile_tree();
reconcile_at = None;
if ENABLE_TREE_RECONCILIATION {
log::warn!(
"VFS watcher lost events (RescanRequired). \
Triggering full tree reconciliation."
);
task.reconcile_tree();
reconcile_at = None;
} else {
log::warn!(
"VFS watcher lost events (RescanRequired). \
Tree reconciliation is disabled; some changes may be missed."
);
}
}
},
recv(shutdown_receiver) -> _ => {
@ -190,10 +205,12 @@ impl ChangeProcessor {
default(timeout) => {
task.process_pending_recoveries();
// If a reconciliation deadline has passed, run it now.
if reconcile_at.is_some_and(|d| Instant::now() >= d) {
task.reconcile_tree();
reconcile_at = None;
if ENABLE_TREE_RECONCILIATION {
// If a reconciliation deadline has passed, run it now.
if reconcile_at.is_some_and(|d| Instant::now() >= d) {
task.reconcile_tree();
reconcile_at = None;
}
}
},
}