Usage
Table of Contents
- Configuration File
- Command-Line Flags
- Runtime Behavior
- Submodule Support
- Output Semantics
- Exit Codes
- Local Directory Classification
- Branch Drift
- Dirty Repository Reporting
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 |
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
organizationis required; the command exits with an error if it is missing or empty.- Setting both
include_publicandinclude_privatetofalseis 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 |
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:
- Load configuration from
.ghorgsyncand validate it. - Resolve authentication and connect to the GitHub API. See Installation for configuring authentication.
- Fetch the organization repository list including default branch metadata.
- Filter repositories by visibility (
include_public/include_private) and exclusion patterns. - Scan the local directory and classify child entries (see Local Directory Classification).
- Clone missing repositories.
- Process existing repositories (fetch, audit, conditionally checkout and pull).
- Report findings (collisions, unknown folders, excluded-but-present).
- 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.
Per-Repository Processing
For each included repository that exists locally:
- Fetch: always performed (safe operation).
- Submodule initialization:
git submodule update --init --recursiveis run after every fetch to initialize any uninitialized submodules, preventing them from appearing as untracked files and causing a false dirty state. - Check dirty state: detects staged changes, unstaged changes, and untracked files.
- If dirty:
- Do not checkout or pull.
- Report the dirty state with current branch, default branch, changed files, and line counts.
- 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 --recursiveagain 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, nogit clean -fd, no force checkouts. fetchis 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-submodulesso submodules are initialized immediately. - Existing repositories:
git submodule update --init --recursiveis 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 --recursiveis 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. 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. Non-TTY output remains line-oriented for scripting/log capture.
Color can be disabled by:
- Passing
--no-color - Setting the
NO_COLORenvironment 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.
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