Usage

Table of Contents


Configuration File

ghorgsync is configured with a .ghorgsync YAML file placed in the directory where your repositories live. This is the same directory where you run the command.

Configuration Options

Option Type Default Description
organization string (required) GitHub organization name to sync
include_public boolean true Include public repositories
include_private boolean true Include private repositories
include_archived boolean false Include archived repositories
exclude_repos array [] Repository names or regex patterns to exclude

Exclude Patterns

The exclude_repos list supports both exact names and regular expressions. Patterns are matched against the repository name only (not the full URL or organization-qualified path).

exclude_repos:
  - legacy-repo          # exact match
  - "^sandbox-"          # regex: repos starting with "sandbox-"
  - "-archive$"          # regex: repos ending with "-archive"

Invalid regex patterns produce a clear configuration error that identifies the offending pattern.

Configuration Validation

  • organization is required; the command exits with an error if it is missing or empty.
  • Setting both include_public and include_private to false is invalid.
  • Invalid YAML produces a clear error message.

Command-Line Flags

ghorgsync [flags]
Flag Description
--help Print usage information and exit
--version Print version and exit
--verbose Enable verbose output (show per-repository processing detail)
--no-color Disable color output
--clone Clone-only mode: only clone missing repositories (see Clone-Only Mode)
--status Status mode: show only dirty repos and branch drift (see Status Mode)

Mode Flags

The --clone and --status flags are mode flags that change the sync behavior. Mode flags are mutually exclusive; if multiple mode flags are provided, the command exits with an error.

Runtime Behavior

Startup Gate

The command only runs when the required dotfile named after the executable, .ghorgsync, exists in the current working directory. If the dotfile is missing, the command prints a short message and exits successfully (0) without performing any API calls, scans, or git operations.

Sync Workflow

When invoked, ghorgsync performs the following steps:

  1. Load configuration from .ghorgsync and validate it.
  2. Resolve authentication and connect to the GitHub API. See Installation for configuring authentication.
  3. Fetch the organization repository list including default branch metadata.
  4. Filter repositories by visibility (include_public/include_private), archived status (include_archived), and exclusion patterns.
  5. Scan the local directory and classify child entries (see Local Directory Classification).
  6. Clone missing repositories.
  7. Process existing repositories (fetch, audit, conditionally checkout and pull).
  8. Report findings (collisions, unknown folders, excluded-but-present).
  9. Print a summary line with counts.

During the repository clone/process phase, ghorgsync shows a live progress bar on TTY output to indicate completion across managed repositories. The progress bar scales to the full terminal width and uses smooth Unicode block characters (▏▎▍▌▋▊▉█) for high-resolution progress feedback. The layout shows the repo label and a padded counter on the left, a proportional bar in the center, and a color-coded percentage on the right:

  repo   3/10 [█████████████████▋                                         ]  30%

Clone-Only Mode

When invoked with --clone, ghorgsync runs a streamlined workflow focused exclusively on cloning missing repositories:

  1. Load configuration and resolve authentication (same as default mode).
  2. Fetch the organization repository list and filter repositories (same as default mode).
  3. Scan the local directory to identify which included repositories are missing.
  4. Clone missing repositories only.
  5. Print a summary line with counts.

What is skipped compared to the default workflow:

  • Processing existing repositories (fetch, dirty check, checkout, pull) is entirely skipped.
  • Collisions, unknown folders, and excluded-but-present findings are not reported.
  • The progress bar only covers missing repositories to clone.

This mode is useful when you know a new repository has been added to the organization and you want to quickly pull it down without waiting for every existing repository to be fetched and checked.

Status Mode

When invoked with --status, ghorgsync runs a read-only workflow that reports which repositories are dirty or not on their default branch:

  1. Load configuration and resolve authentication (same as default mode).
  2. Fetch the organization repository list and filter repositories (same as default mode).
  3. Scan the local directory to identify which included repositories exist locally.
  4. Check each existing repository for dirty state and branch drift.
  5. Print only repositories that are dirty or not on their default branch.
  6. Print a summary line with counts.

What is skipped compared to the default workflow:

  • No git operations that modify the repository (no fetch, no checkout, no pull).
  • Missing repositories are not cloned.
  • Collisions, unknown folders, and excluded-but-present findings are not reported.
  • Repositories that are clean and on their default branch produce no output.

For dirty repositories, the colorized output from git status --short is displayed, showing staged and unstaged changes with git’s native color coding. For repositories on a non-default branch (but otherwise clean), the current and default branches are shown.

This mode is useful for quickly surveying which repositories need attention without modifying anything.

Per-Repository Processing

For each included repository that exists locally:

  1. Fetch: always performed (safe operation).
  2. Submodule initialization: git submodule update --init --recursive is run after every fetch to initialize any uninitialized submodules, preventing them from appearing as untracked files and causing a false dirty state.
  3. Check dirty state: detects staged changes, unstaged changes, and untracked files.
  4. If dirty:
    • Do not checkout or pull.
    • Report the dirty state with current branch, default branch, changed files, and line counts.
  5. If clean:
    • If not on the default branch, checkout the default branch (branch drift correction).
    • Pull with fast-forward-only semantics (--ff-only).
    • Run git submodule update --init --recursive again to update submodule pointers to match any new commits brought in by the pull.
    • Report whether the repo was updated or already current.

Non-Destructive Guarantees

ghorgsync enforces hard constraints that must never be violated:

  • Never deletes directories: unknown folders and excluded-but-present repos are reported but left untouched.
  • Never discards local changes: dirty repos are skipped for checkout/pull operations.
  • Never runs destructive git commands: no git reset --hard, no git clean -fd, no force checkouts.
  • fetch is always considered safe and is always performed.
  • git submodule update --init --recursive (without --force) is safe and will not overwrite local changes inside submodule directories.

Submodule Support

ghorgsync handles repositories that contain git submodules:

  • Clone: new repositories are cloned with --recurse-submodules so submodules are initialized immediately.
  • Existing repositories: git submodule update --init --recursive is run after every fetch, before the dirty check. This ensures that uninitialized submodule directories are initialized and do not appear as untracked files causing a false dirty state.
  • After pull: git submodule update --init --recursive is run again after a successful pull to update submodule pointers to the commits referenced by the new parent-repo state.

If submodule initialization fails (for example, due to a network error fetching a submodule remote), the error is reported as a submodule-error and processing of that repository stops. Other repositories continue normally.

Output Semantics

Quiet Default

By default, ghorgsync only prints:

  • Actions taken: cloned, updated, branch checkout/pull
  • Findings: dirty repos, branch drift, unknown folders, excluded-but-present, collisions, errors
  • Summary line: counts for all categories

Repositories that are already up to date with no notable events produce no output.

When stdout is a TTY, a live progress bar is shown during repository processing. The progress bar uses the repo label with a padded counter, a smooth Unicode block bar that spans the terminal width, and a percentage indicator. If an action or finding needs to be logged, the progress line is temporarily cleared, the log message is printed, and the progress bar is redrawn beneath it so the progress indicator remains at the bottom of the active output.

Verbose Mode

Use --verbose to see additional per-repository processing detail, such as the total number of repositories found and filtered.

Color Control

Output uses ANSI color codes to signal status categories when stdout is a TTY. Color improves readability but text labels are always present so output remains legible without color.

The live progress bar uses the same color settings and is only rendered as an updating line when stdout is a TTY. It adapts to the terminal width, using smooth Unicode block characters for fractional progress. Non-TTY output remains line-oriented for scripting/log capture.

Color can be disabled by:

  • Passing --no-color
  • Setting the NO_COLOR environment variable (any value)

Exit Codes

Code Meaning
0 Command completed successfully, including runs with audit findings (dirty repos, branch drift, unknown folders, missing config dotfile)
1 Command failed due to configuration error, authentication/API failure, or other operational error

Audit findings are user-facing warnings, not command failures.

Local Directory Classification

ghorgsync inspects immediate child entries of the current working directory (non-recursive) and classifies each one:

Classification Description
Managed Corresponds to an included GitHub repository. Cloned if missing; synced/audited if present.
Unknown A directory that does not match any repository (included or excluded) in the organization.
Excluded-but-present A directory matching a repository excluded by name or pattern. Reported but not modified.
Collision A managed repo path exists but is not a usable git clone (e.g., a regular file, non-git directory, or remote mismatch). Reported and skipped.

Hidden entries (starting with .) are skipped during scanning. The exception being repositories with names that start with a dot, which are valid and processed normally.

Archived Repositories

GitHub repositories can be archived, making them read-only. ghorgsync treats archived repositories based on the include_archived configuration setting:

  • Default (include_archived: false): Archived repositories are ignored entirely. They are not cloned and are not synced. If a local directory exists for an archived repository, it is classified as excluded-but-present and reported accordingly.
  • Opt-in (include_archived: true): Archived repositories are treated like any other repository — cloned if missing, and synced (fetch/audit) if present.

Branch Drift

A repository is in branch drift when its current branch differs from the default branch (as defined by GitHub metadata). Default branch names are per-repository and are never assumed.

  • Dirty repo with drift: reported as informational; no automatic correction since checkout is unsafe.
  • Clean repo with drift: the default branch is checked out and pulled; the correction is logged.

Dirty Repository Reporting

When a repository has a dirty working tree, the output includes:

  • Repository name
  • Current branch and default branch
  • Indication that checkout/pull was skipped
  • List of changed file paths with staged/unstaged distinction
  • Line-count summary (additions/deletions) when available