From 97be1d1ca3fa8764cedcff5dbc092b1cefd1acfa Mon Sep 17 00:00:00 2001 From: Test Date: Fri, 6 Mar 2026 15:19:25 +0100 Subject: [PATCH] fix: write .gitignore on vault init to exclude .DS_Store macOS creates .DS_Store files in every folder which were being tracked by git, causing constant conflicts when vaults are synced across machines. init_repo() now writes a .gitignore before the first commit with: - .DS_Store, .AppleDouble, .LSOverride - ._ thumbnail files - Common editor artifacts (.vscode/, .idea/, *.swp) The file is only written if one doesn't already exist, so user-customized .gitignore files are respected. Two new Rust tests verify the behavior. --- src-tauri/src/git.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src-tauri/src/git.rs b/src-tauri/src/git.rs index 3564faa4..4984788f 100644 --- a/src-tauri/src/git.rs +++ b/src-tauri/src/git.rs @@ -18,6 +18,18 @@ pub fn init_repo(path: &str) -> Result<(), String> { run_git(dir, &["init"])?; ensure_author_config(dir)?; + + // Write .gitignore before the first commit so macOS metadata files + // are never tracked and don't cause conflicts across machines. + let gitignore_path = dir.join(".gitignore"); + if !gitignore_path.exists() { + std::fs::write( + &gitignore_path, + "# macOS\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Thumbnails\n._*\n\n# Editors\n.vscode/\n.idea/\n*.swp\n*.swo\n", + ) + .map_err(|e| format!("Failed to write .gitignore: {}", e))?; + } + run_git(dir, &["add", "."])?; run_git(dir, &["commit", "-m", "Initial vault setup"])?; @@ -927,6 +939,35 @@ mod tests { ); } + #[test] + fn test_init_repo_creates_gitignore_with_ds_store() { + let dir = TempDir::new().unwrap(); + let vault = dir.path().join("new-vault"); + fs::create_dir_all(&vault).unwrap(); + fs::write(vault.join("note.md"), "# Test\n").unwrap(); + + init_repo(vault.to_str().unwrap()).unwrap(); + + let gitignore = vault.join(".gitignore"); + assert!(gitignore.exists(), ".gitignore should be created by init_repo"); + let content = fs::read_to_string(&gitignore).unwrap(); + assert!(content.contains(".DS_Store"), ".gitignore should exclude .DS_Store"); + } + + #[test] + fn test_init_repo_does_not_overwrite_existing_gitignore() { + let dir = TempDir::new().unwrap(); + let vault = dir.path().join("new-vault"); + fs::create_dir_all(&vault).unwrap(); + fs::write(vault.join("note.md"), "# Test\n").unwrap(); + fs::write(vault.join(".gitignore"), "custom-rule\n").unwrap(); + + init_repo(vault.to_str().unwrap()).unwrap(); + + let content = fs::read_to_string(vault.join(".gitignore")).unwrap(); + assert_eq!(content, "custom-rule\n", "existing .gitignore should not be overwritten"); + } + #[test] fn test_get_file_history_with_commits() { let dir = setup_git_repo();