Examples
Table of Contents
Configuration Examples
Basic Configuration
Sync all repositories (public and private) in an organization:
organization: my-org
Public Repositories Only
Exclude private repositories from syncing:
organization: my-org
include_private: false
With Exclusion Patterns
Exclude specific repos by exact name and regex patterns:
organization: my-org
exclude_repos:
- legacy-repo
- "^sandbox-"
- "-archive$"
- "^test-.*-tmp$"
This configuration excludes:
legacy-repo(exact match)- Any repo starting with
sandbox-(e.g.,sandbox-experiments) - Any repo ending with
-archive(e.g.,old-service-archive) - Any repo matching
test-*-tmp(e.g.,test-api-tmp)
Including Archived Repositories
By default, archived repositories are ignored. To include them:
organization: my-org
include_archived: true
With this setting, archived repositories are cloned and synced like any other repository. Without it (the default), archived repositories are skipped and any existing local directories for them are reported as excluded-but-present.
Example Output
The examples below show the stable log lines and summary output. In an interactive terminal (TTY), ghorgsync also renders a live progress bar during repository processing. The progress bar uses smooth Unicode block characters and scales to the terminal width:
repo 3/10 [█████████████████▋ ] 30%
The transient progress line is omitted from the remaining examples below for readability.
Clean Run
When all repositories are already up to date and on their default branches, ghorgsync produces minimal output:
Summary:
total: 5 | cloned: 0 | updated: 0 | dirty: 0 | branch-drift: 0 | unknown: 0 | excluded-but-present: 0 | errors: 0
Cloned Repositories
When new repositories are found in the organization that don’t exist locally:
repo my-app [cloned]
repo api-service [cloned]
Summary:
total: 5 | cloned: 2 | updated: 0 | dirty: 0 | branch-drift: 0 | unknown: 0 | excluded-but-present: 0 | errors: 0
Updated Repositories
When existing repositories have new commits on their default branch:
repo api-service [updated]
Summary:
total: 5 | cloned: 0 | updated: 1 | dirty: 0 | branch-drift: 0 | unknown: 0 | excluded-but-present: 0 | errors: 0
Dirty Repository
When a repository has staged or unstaged changes, checkout and pull are skipped:
repo web-frontend [dirty] on feature-branch (default: main)
checkout/pull skipped due to dirty working tree
[unstaged] src/index.ts
[staged] package.json
+15 -3 lines
Summary:
total: 5 | cloned: 0 | updated: 0 | dirty: 1 | branch-drift: 0 | unknown: 0 | excluded-but-present: 0 | errors: 0
The output shows:
- The current branch and default branch
- Why checkout/pull was skipped
- Each changed file with its staged/unstaged status
- A summary of line additions and deletions
Branch Drift Detected and Corrected
When a clean repository is not on its default branch, ghorgsync checks out the default branch and pulls:
repo docs-site [branch-drift: checked out main, updated]
Summary:
total: 5 | cloned: 0 | updated: 1 | dirty: 0 | branch-drift: 1 | unknown: 0 | excluded-but-present: 0 | errors: 0
If the repository was dirty and on the wrong branch, drift is reported but no correction is made:
repo docs-site [dirty] on feature-docs (default: main)
checkout/pull skipped due to dirty working tree
[unstaged] docs/guide.md
+8 -2 lines
Summary:
total: 5 | cloned: 0 | updated: 0 | dirty: 1 | branch-drift: 0 | unknown: 0 | excluded-but-present: 0 | errors: 0
Unknown Folder Warning
When a directory exists locally that doesn’t correspond to any repository in the organization:
folder personal-project [unknown]
Summary:
total: 5 | cloned: 0 | updated: 0 | dirty: 0 | branch-drift: 0 | unknown: 1 | excluded-but-present: 0 | errors: 0
Excluded-but-Present Warning
When a directory exists locally for a repository that is excluded by configuration:
folder old-tool [excluded-but-present]
Summary:
total: 5 | cloned: 0 | updated: 0 | dirty: 0 | branch-drift: 0 | unknown: 0 | excluded-but-present: 1 | errors: 0
Combined Output
A typical run with multiple findings:
repo my-app [cloned]
repo api-service [updated]
repo web-frontend [dirty] on feature-branch (default: main)
checkout/pull skipped due to dirty working tree
[unstaged] src/index.ts
[staged] package.json
+15 -3 lines
repo docs-site [branch-drift: checked out main, updated]
folder personal-project [unknown]
folder old-tool [excluded-but-present]
Summary:
total: 8 | cloned: 1 | updated: 1 | dirty: 1 | branch-drift: 1 | unknown: 1 | excluded-but-present: 1 | errors: 0
Clone-Only Mode
Using --clone to quickly clone only missing repositories without processing existing ones:
$ ghorgsync --clone
repo new-service [cloned]
repo new-library [cloned]
Summary:
total: 10 | cloned: 2 | updated: 0 | dirty: 0 | branch-drift: 0 | unknown: 0 | excluded-but-present: 0 | errors: 0
When all repositories are already cloned locally, --clone finishes quickly with no output:
$ ghorgsync --clone
Summary:
total: 10 | cloned: 0 | updated: 0 | dirty: 0 | branch-drift: 0 | unknown: 0 | excluded-but-present: 0 | errors: 0
This mode skips all per-repository processing (fetch, dirty check, checkout, pull) and directory auditing (collisions, unknown folders, excluded-but-present), making it significantly faster when you only need to pull down new repositories.
Status Mode
Using --status to check which repositories are dirty or not on their default branch:
$ ghorgsync --status
repo web-frontend [dirty] on feature-branch (default: main)
M src/index.ts
?? new-file.txt
repo docs-site [branch-drift] on feature-docs (default: main)
Summary:
total: 10 | dirty: 1 | branch-drift: 1
The file status lines show the output of git status --short with its native color coding. The two-character prefix (M, ??, A, etc.) follows git’s standard format where the first column indicates staged changes and the second column indicates unstaged changes.
When all repositories are clean and on their default branches, --status produces minimal output:
$ ghorgsync --status
Summary:
total: 10 | dirty: 0 | branch-drift: 0
A dirty repository on a non-default branch is reported as dirty (not branch-drift):
$ ghorgsync --status
repo web-frontend [dirty] on feature-branch (default: main)
M src/index.ts
A staged-file.ts
Summary:
total: 10 | dirty: 1 | branch-drift: 0
This mode performs no git operations that modify repositories — no fetch, checkout, or pull. It is purely read-only and safe to run at any time.
Troubleshooting
Missing Dotfile
If you run ghorgsync in a directory without a .ghorgsync file:
No .ghorgsync configuration file found in the current directory.
The command exits with code 0. Create a .ghorgsync file with at least the organization field to proceed.
Authentication Errors
If no GitHub token is available and the gh CLI is not authenticated:
system auth [error] failed to list repositories: 401 Unauthorized
Fix by setting a token or authenticating with gh:
export GITHUB_TOKEN=ghp_your_token_here
# or
gh auth login
Configuration Errors
If the configuration file is invalid:
system config [error] organization is required
system config [error] invalid exclude pattern "[bad-regex": error parsing regexp: missing closing ]: `[bad-regex`
system config [error] at least one of include_public or include_private must be true
These errors exit with code 1. Fix the .ghorgsync file and re-run.
Repositories with Submodules
Repositories that contain git submodules are handled automatically. On clone, submodules are initialized via --recurse-submodules. For existing repositories, git submodule update --init --recursive is run after every fetch so that uninitialized submodule directories do not appear as untracked files and cause a false dirty report.
If a submodule remote is unreachable, the repository is reported as a submodule-error:
repo my-app [submodule-error] git submodule update: ...
Fix the underlying submodule remote issue (network access, SSH keys, token scope) and re-run.