repoforge 0.1.0

Repository archive discovery and safe refresh helpers for thesa
Documentation

RepoForge

RepoForge provides repository archive discovery and safe refresh helpers used by thesa.

The crate is intentionally focused. It scans an archive root for Git worktrees, derives stable owner/repo slugs from GitHub remotes or archive paths, and refreshes clones with git pull --ff-only without touching dirty worktrees.

Install

[dependencies]
repoforge = "0.1"

The package and library crate name are both repoforge.

Archive Layout

RepoForge is designed for archive trees like this:

archives/
  octocat/
    Hello-World/
      .git/
  rust-lang/
    rust/
      .git/

When remote.origin.url is a GitHub URL, the slug is derived from the remote. For example https://github.com/octocat/Hello-World.git becomes octocat/Hello-World.

If there is no GitHub remote, RepoForge falls back to the path layout. For example archives/octocat/Hello-World becomes octocat/Hello-World.

Discovery

use std::path::Path;

let archives = repoforge::discover_git_archives(Path::new("./archives"), None)?;
for archive in archives {
    println!("{} -> {}", archive.slug, archive.path.display());
}
# Ok::<(), repoforge::RepoForgeError>(())

Use a filter to limit results by slug or path:

let archives = repoforge::discover_git_archives(
    std::path::Path::new("./archives"),
    Some("octocat"),
)?;
# Ok::<(), repoforge::RepoForgeError>(())

Discovery is recursive but stops descending when it finds a Git worktree. .git, .thesa, and target directories are skipped.

Refresh

let archives = repoforge::discover_git_archives(std::path::Path::new("./archives"), None)?;
let summary = repoforge::refresh_git_archives(&archives, 4);

println!(
    "updated={} unchanged={} failed={}",
    summary.updated,
    summary.unchanged,
    summary.failed.len()
);

if summary.has_failures() {
    for failure in &summary.failed {
        eprintln!("{}: {}", failure.slug, failure.message);
    }
}
# Ok::<(), repoforge::RepoForgeError>(())

Refresh behavior:

  • Runs git status --porcelain before pulling.
  • Dirty worktrees fail fast and are not pulled.
  • Runs git pull --ff-only for clean worktrees.
  • Reports Updated when HEAD changes.
  • Reports Unchanged when the pull succeeds without changing HEAD.
  • Uses bounded concurrency with refresh_git_archives.

Slug Helpers

assert_eq!(
    repoforge::parse_github_remote_slug("git@github.com:octocat/Hello-World.git"),
    Some("octocat/Hello-World".to_string())
);

Supported GitHub remote forms include HTTPS and SSH:

  • https://github.com/owner/repo.git
  • http://github.com/owner/repo.git
  • git@github.com:owner/repo.git
  • ssh://git@github.com/owner/repo.git

Safety Contract

RepoForge does not delete, reset, checkout, stash, or force-pull anything. It only uses read-only Git inspection commands plus git pull --ff-only after confirming the worktree is clean.

Callers such as thesa remain responsible for archive metadata sidecars, checksums, and higher-level reporting.