Create .atomicignore and initialize vault AFTER git import + materialize. This runs post-import so the import's materialize step can't stomp the vault files' tracked state. The sequence is: 1. Create .atomicignore (auto-detect project type) → add → record 2. Create .vault/ with defaults → add → record 3. Status is clean.
(
repo: &mut Repository,
workdir: &std::path::Path,
kind: Option<&str>,
no_vault: bool,
)
| 637 | /// 2. Create .vault/ with defaults → add → record |
| 638 | /// 3. Status is clean. |
| 639 | fn init_atomicignore_and_vault( |
| 640 | repo: &mut Repository, |
| 641 | workdir: &std::path::Path, |
| 642 | kind: Option<&str>, |
| 643 | no_vault: bool, |
| 644 | ) -> CliResult<()> { |
| 645 | // Step 1: .atomicignore |
| 646 | { |
| 647 | let ignore_path = workdir.join(".atomicignore"); |
| 648 | if !ignore_path.exists() { |
| 649 | // Use explicit --kind if provided, otherwise auto-detect from project files |
| 650 | let ignore_content = if let Some(k) = kind { |
| 651 | super::super::init::get_ignore_template(k).unwrap_or(".atomic\n.git\n") |
| 652 | } else if workdir.join("Cargo.toml").exists() { |
| 653 | super::super::init::get_ignore_template("rust").unwrap_or(".atomic\n.git\n") |
| 654 | } else if workdir.join("package.json").exists() { |
| 655 | super::super::init::get_ignore_template("node").unwrap_or(".atomic\n.git\n") |
| 656 | } else if workdir.join("go.mod").exists() { |
| 657 | super::super::init::get_ignore_template("go").unwrap_or(".atomic\n.git\n") |
| 658 | } else if workdir.join("setup.py").exists() || workdir.join("pyproject.toml").exists() { |
| 659 | super::super::init::get_ignore_template("python").unwrap_or(".atomic\n.git\n") |
| 660 | } else { |
| 661 | ".atomic\n.git\n" |
| 662 | }; |
| 663 | let _ = std::fs::write(&ignore_path, ignore_content); |
| 664 | } |
| 665 | |
| 666 | let _ = repo.add( |
| 667 | ".atomicignore", |
| 668 | atomic_repository::TrackingOptions::default(), |
| 669 | ); |
| 670 | let header = atomic_core::change::ChangeHeader::new("Initialize repository"); |
| 671 | match repo.record(header, atomic_repository::RecordOptions::default()) { |
| 672 | Ok(_) => print_info("Recorded .atomicignore"), |
| 673 | Err(atomic_repository::RecordError::NothingToRecord) => {} |
| 674 | Err(e) => log::warn!("Failed to record .atomicignore: {}", e), |
| 675 | } |
| 676 | } |
| 677 | |
| 678 | // Step 2: Vault (unless --no-vault) |
| 679 | if no_vault { |
| 680 | return Ok(()); |
| 681 | } |
| 682 | |
| 683 | match repo.init_vault() { |
| 684 | Ok(()) => { |
| 685 | print_info("Initialized vault at .vault/"); |
| 686 | |
| 687 | // Add all vault files |
| 688 | fn add_dir_recursive(repo: &Repository, dir: &std::path::Path) { |
| 689 | if let Ok(entries) = std::fs::read_dir(dir) { |
| 690 | for entry in entries.flatten() { |
| 691 | let path = entry.path(); |
| 692 | if path.is_dir() { |
| 693 | add_dir_recursive(repo, &path); |
| 694 | } else if path.is_file() { |
| 695 | if let Ok(rel) = path.strip_prefix(repo.root()) { |
| 696 | let rel_str = rel.to_string_lossy().replace('\\', "/"); |
no test coverage detected