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,
)
| 746 | /// 2. Create .vault/ with defaults → add → record |
| 747 | /// 3. Status is clean. |
| 748 | fn init_atomicignore_and_vault( |
| 749 | repo: &mut Repository, |
| 750 | workdir: &std::path::Path, |
| 751 | kind: Option<&str>, |
| 752 | no_vault: bool, |
| 753 | ) -> CliResult<()> { |
| 754 | // Step 1: .atomicignore |
| 755 | { |
| 756 | let ignore_path = workdir.join(".atomicignore"); |
| 757 | if !ignore_path.exists() { |
| 758 | // Use explicit --kind if provided, otherwise auto-detect from project files |
| 759 | let ignore_content = if let Some(k) = kind { |
| 760 | super::super::init::get_ignore_template(k).unwrap_or(".atomic\n.git\n") |
| 761 | } else if workdir.join("Cargo.toml").exists() { |
| 762 | super::super::init::get_ignore_template("rust").unwrap_or(".atomic\n.git\n") |
| 763 | } else if workdir.join("package.json").exists() { |
| 764 | super::super::init::get_ignore_template("node").unwrap_or(".atomic\n.git\n") |
| 765 | } else if workdir.join("go.mod").exists() { |
| 766 | super::super::init::get_ignore_template("go").unwrap_or(".atomic\n.git\n") |
| 767 | } else if workdir.join("setup.py").exists() || workdir.join("pyproject.toml").exists() { |
| 768 | super::super::init::get_ignore_template("python").unwrap_or(".atomic\n.git\n") |
| 769 | } else { |
| 770 | ".atomic\n.git\n" |
| 771 | }; |
| 772 | let _ = std::fs::write(&ignore_path, ignore_content); |
| 773 | } |
| 774 | |
| 775 | let _ = repo.add( |
| 776 | ".atomicignore", |
| 777 | atomic_repository::TrackingOptions::default(), |
| 778 | ); |
| 779 | let header = atomic_core::change::ChangeHeader::new("Initialize repository"); |
| 780 | match repo.record(header, atomic_repository::RecordOptions::default()) { |
| 781 | Ok(_) => print_info("Recorded .atomicignore"), |
| 782 | Err(atomic_repository::RecordError::NothingToRecord) => {} |
| 783 | Err(e) => log::warn!("Failed to record .atomicignore: {}", e), |
| 784 | } |
| 785 | } |
| 786 | |
| 787 | // Step 2: Vault (unless --no-vault) |
| 788 | if no_vault { |
| 789 | return Ok(()); |
| 790 | } |
| 791 | |
| 792 | match repo.init_vault() { |
| 793 | Ok(()) => { |
| 794 | print_info("Initialized vault at .vault/"); |
| 795 | |
| 796 | // Add all vault files |
| 797 | fn add_dir_recursive(repo: &Repository, dir: &std::path::Path) { |
| 798 | if let Ok(entries) = std::fs::read_dir(dir) { |
| 799 | for entry in entries.flatten() { |
| 800 | let path = entry.path(); |
| 801 | if path.is_dir() { |
| 802 | add_dir_recursive(repo, &path); |
| 803 | } else if path.is_file() { |
| 804 | if let Ok(rel) = path.strip_prefix(repo.root()) { |
| 805 | let rel_str = rel.to_string_lossy().replace('\\', "/"); |
no test coverage detected