Skip to main content

git_side/commands/
auto.rs

1use colored::Colorize;
2
3use crate::error::{Error, Result};
4use crate::git;
5use crate::side_repo::SideRepo;
6use crate::tracked::TrackedPaths;
7
8/// Auto-commit: sync all tracked paths using the last main repo commit message.
9///
10/// # Errors
11///
12/// Returns an error if no paths are tracked, staging fails, or commit fails.
13pub fn run() -> Result<()> {
14    let repo = SideRepo::open()?;
15
16    if !repo.is_initialized() {
17        return Err(Error::NoTrackedPaths);
18    }
19
20    // Load tracked paths
21    let tracked = TrackedPaths::load(&repo)?;
22
23    if tracked.is_empty() {
24        return Err(Error::NoTrackedPaths);
25    }
26
27    // Expand directories to files
28    let files = tracked.expand(&repo.work_tree);
29
30    // Get the raw tracked paths for staging (we stage the tracked paths, not expanded files)
31    let tracked_paths: Vec<_> = tracked.paths().iter().cloned().collect();
32
33    // Two-pass staging:
34    // Pass 1: update tracked files (modifications + deletions) — errors ignored
35    repo.stage_update(&tracked_paths);
36
37    // Pass 2: add new files
38    repo.stage_new(&tracked_paths)?;
39
40    // Stage .side-tracked file itself (self-aware versioning)
41    repo.stage_tracked_file()?;
42
43    // Get last commit message from main repo
44    let message = git::last_commit_message()?;
45
46    if message.trim().is_empty() {
47        return Err(Error::GitCommandFailed(
48            "no commit message found in main repo".to_string(),
49        ));
50    }
51
52    // Commit (will return NothingToCommit if nothing changed)
53    match repo.commit(&message) {
54        Ok(()) => {
55            println!(
56                "{} {}",
57                "Auto-committed:".green().bold(),
58                message.lines().next().unwrap_or(&message)
59            );
60            println!(
61                "  {} file(s) synced",
62                files.len().to_string().cyan()
63            );
64        }
65        Err(Error::NothingToCommit) => {
66            println!("{}", "Nothing to commit (side repo is up to date).".yellow());
67        }
68        Err(e) => return Err(e),
69    }
70
71    Ok(())
72}