LyAhn 717ae0addb feat(cli): add scan and sync commands
- discover nested Git repositories and skip dependency and build directories
- add scan and sync commands with root, exclude, jobs, timeout, JSON, strict, and confirmation options
- block detached heads, missing remotes, active Git operations, and dirty worktrees
- exclude nested repositories from their parent's dirty-worktree check
- recheck repository safety before running hub sync
- add discovery, safety, sync, JSON, and output tests
- set the embedded version to 0.1.1 and document installation and usage
2026-09-06 18:29:50 +01:00
2026-09-06 18:29:50 +01:00
2026-09-06 18:29:50 +01:00

Stack Sync

stack-sync safely runs hub sync across every Git repository in a workspace. It is designed for directory trees such as JezzWTF where the root may not be a repository and a parent repository may contain deliberately untracked, nested repositories.

The interface is deliberately a CLI rather than a full-screen TUI: every run produces a reviewable plan, it works over SSH and in automation, and its JSON output can drive a future TUI or GUI without putting safety logic in the presentation layer.

Safety model

Before a repository is eligible, Stack Sync verifies that it:

  • is on a branch (not a detached HEAD);
  • has at least one remote;
  • has no merge, rebase, cherry-pick, revert, or bisect in progress;
  • has no modified, staged, deleted, conflicted, or untracked files.

Untracked paths that are themselves discovered nested Git repositories are excluded from the parent repository's dirty check. All other untracked files still block it.

Stack Sync never runs git stash, git reset, git clean, git commit, or any other command that saves or discards work. A repository is checked again immediately before hub sync to reduce the chance of a change slipping in between the plan and apply phases. Blocked repositories are skipped; use --strict to abort the whole run if even one is blocked.

Stack Sync intentionally preserves hub sync semantics. That means hub may delete a local branch when its upstream branch has been deleted and it considers the local branch merged. It warns instead when it finds unpushed or apparently unmerged commits. The interactive confirmation calls this out; review hub help sync before using --yes in automation.

Build and install

Requires Go 1.24 or newer, Git, and hub.

cd stack-sync
go test ./...
go build -o stack-sync .
install -Dm755 stack-sync ~/.local/bin/stack-sync

Usage

Scan the current workspace. This is read-only and is the default command:

stack-sync scan --root ~/Coding/jwtf
# equivalent:
stack-sync --root ~/Coding/jwtf

Review the same plan, confirm it, and sync every eligible repository:

stack-sync sync --root ~/Coding/jwtf

For automation, suppress the prompt and optionally require the entire workspace to be clean:

stack-sync sync --root ~/Coding/jwtf --yes --strict

Useful options:

--jobs 4             maximum concurrent inspections or syncs
--timeout 5m         per-repository hub sync timeout
--exclude temp       skip a directory name anywhere in the tree
--exclude Org/old    skip a root-relative path
--json               emit structured output

Dependency caches, build outputs, and tool-managed directories such as node_modules, target, .claude, and .codex are skipped during discovery by default. These exclusions only affect repository discovery; they never make real changes inside a discovered repository disappear from its dirty-worktree check.

Exit codes are 0 for a successful scan or sync (planned dirty repositories may be safely skipped), 1 for an operational/sync failure, 2 for invalid or unconfirmed non-interactive use, and 3 when strict mode refuses the plan or a previously eligible repository fails its immediate pre-sync safety check.

S
Description
Safely discover and synchronize every Git repository in a nested workspace
Readme 151 KiB
Languages
Go 100%