limb 0.1.0

A focused CLI for git worktree management
Documentation
//! Implements `limb update`. Fetch + fast-forward every worktree.

use anyhow::Result;

use crate::cli::UpdateArgs;
use crate::context::Context;
use crate::worktree;

/// Runs `limb update`.
///
/// By default: `git fetch --all --prune` once, then `merge --ff-only
/// @{upstream}` in each non-bare worktree that has a branch. `--fetch-only`
/// skips the fast-forward pass; `--ff-only` skips the fetch.
/// Fast-forward failures are reported as `skip` and do not abort.
///
/// # Errors
///
/// Returns an error if the repo cannot be resolved or the initial fetch
/// fails. Per-worktree fast-forward failures are non-fatal.
pub fn run(ctx: &Context, args: &UpdateArgs) -> Result<()> {
    let repo = ctx.repo()?;

    let dim = crate::style::DIM;
    let ok = crate::style::OK;
    let warn = crate::style::WARN;

    if !args.ff_only {
        if !ctx.quiet {
            let verb = if args.dry_run { "would" } else { "" };
            anstream::eprintln!("{dim}{verb} fetch --all --prune{dim:#}");
        }
        if !args.dry_run {
            worktree::fetch(&repo, ctx.quiet)?;
        }
    }

    if !args.fetch_only {
        let trees = worktree::list(&repo)?;
        for w in &trees {
            if w.bare || w.branch.is_none() {
                continue;
            }
            if args.dry_run {
                if !ctx.quiet {
                    anstream::eprintln!("{dim}would ff {}{dim:#}", w.name);
                }
                continue;
            }
            if !ctx.quiet {
                anstream::eprint!("{dim}→ ff {} ... {dim:#}", w.name);
            }
            match worktree::fast_forward(&w.path, ctx.quiet) {
                Ok(()) => {
                    if !ctx.quiet {
                        anstream::eprintln!("{ok}ok{ok:#}");
                    }
                }
                Err(e) => {
                    if !ctx.quiet {
                        anstream::eprintln!("{warn}skip{warn:#} ({e})");
                    }
                }
            }
        }
    }
    Ok(())
}