use std::path::Path;
use crate::error::{AgitError, Result};
use crate::git::GitRepository;
use crate::storage::{FileObjectStore, FileRefStore, GitObjectStore, GitRefStore};
mod branch_sync;
mod commit_pipeline;
mod migration;
pub mod reconcile;
mod sanitize;
mod synthesizer;
pub use branch_sync::*;
pub use commit_pipeline::*;
pub use migration::*;
pub use reconcile::RewindResult;
pub use sanitize::*;
pub use synthesizer::*;
pub fn ensure_sync(project_root: &Path, agit_dir: &Path) -> Result<Option<EnsureSyncResult>> {
let sync = BranchSync::new(project_root, agit_dir)?;
let result = sync.ensure_branch_sync()?;
let branch = match &result {
EnsureSyncResult::AlreadyInSync { branch } => branch.clone(),
EnsureSyncResult::SwitchedToExisting { new_branch, .. } => new_branch.clone(),
EnsureSyncResult::ForkedToNew { new_branch, .. } => new_branch.clone(),
};
check_rewind(project_root, agit_dir, &branch)?;
match result {
EnsureSyncResult::AlreadyInSync { .. } => Ok(None),
_ => Ok(Some(result)),
}
}
pub fn check_conflicted_state(git: &GitRepository) -> Result<()> {
if git.is_merging()? {
return Err(AgitError::ConflictedState {
operation: "Merge".to_string(),
});
}
if git.is_rebasing()? {
return Err(AgitError::ConflictedState {
operation: "Rebase".to_string(),
});
}
Ok(())
}
fn check_rewind(project_root: &Path, agit_dir: &Path, branch: &str) -> Result<()> {
use git2::Repository;
let git = GitRepository::open(project_root)?;
let repo = Repository::discover(project_root)?;
let is_v2 = matches!(detect_version(agit_dir, &repo), StorageVersion::V2GitNative);
let rewind_result = if is_v2 {
let objects = GitObjectStore::new(project_root);
let refs = GitRefStore::new(project_root);
reconcile::reconcile_rewind(&git, &objects, &refs, branch)?
} else {
let objects = FileObjectStore::new(agit_dir);
let refs = FileRefStore::new(agit_dir);
reconcile::reconcile_rewind(&git, &objects, &refs, branch)?
};
match rewind_result {
RewindResult::Rewound { orphaned_count, .. } => {
eprintln!("Warning: Git history rewound. Snapped agit HEAD back to valid ancestor.");
if orphaned_count > 0 {
eprintln!(
" {} orphaned neural commit(s) left as objects (not deleted).",
orphaned_count
);
}
},
RewindResult::NoValidAncestor { .. } => {
eprintln!("Warning: Git history rewound but no valid agit ancestor found.");
eprintln!(" This branch's neural history may be orphaned.");
},
RewindResult::MigratedAmend {
new_git_hash,
new_neural_hash,
..
} => {
eprintln!("🔄 Detected git amend. Migrated memory to new hash.");
eprintln!(
" New git hash: {}",
&new_git_hash[..7.min(new_git_hash.len())]
);
eprintln!(
" New neural hash: {}",
&new_neural_hash[..7.min(new_neural_hash.len())]
);
},
RewindResult::NoRewindNeeded => {
},
}
Ok(())
}