A CLI tool that selectively mirrors remote Git repositories to local paths based on YAML configuration.
- Selective sync — choose exactly which branches and tags to mirror using exact names, wildcards (
*), or regex patterns - Pruning — detect and remove local branches/tags that no longer match any configured pattern
- Stale pruning — optionally remove inactive branches that have no new commits in a specified period (e.g., last 6 months);
prune_staleonly takes effect whenpruneis also enabled — stale branches are skipped before branch sync when both are set - Daemon mode — run as a foreground polling service with per-repo poll intervals
- SSH and HTTPS auth — private repos via SSH key, public repos via anonymous HTTPS
- Working tree checkout — optionally keep a working tree checked out on a specific branch or tag
- OpenVox mode — create per-branch/tag directories with sanitized names, ideal for Puppet environments
- Lightweight clones — repos are initialized empty and only configured refs are fetched
# Install
go install github.com/obmondo/gfetch/cmd/gfetch@latest
# Create a config file
cat <<'EOF' > config.yaml
repos:
my-repo:
url: https://github.com/example/repo.git
local_path: /var/repos/my-repo
poll_interval: 5m
branches:
- main
EOF
# Run a one-shot sync
gfetch syncOr run with Docker:
docker run -v /path/to/config.yaml:/home/gfetch/config.yaml \
-v /var/repos:/var/repos \
ghcr.io/obmondo/gfetch daemongit clone https://github.com/obmondo/gfetch.git
cd gfetch
go build -o gfetch ./cmd/gfetchgo install github.com/obmondo/gfetch/cmd/gfetch@latestPre-built binaries for Linux and macOS (amd64/arm64) are available via GitHub Releases. Each release includes a checksums.txt for verification.
A pre-built image is published to the GitHub Container Registry on every tagged release.
# Pull the latest image
docker pull ghcr.io/obmondo/gfetch
# Run the daemon with config and repo storage mounted
docker run -v /path/to/config.yaml:/home/gfetch/config.yaml \
-v /var/repos:/var/repos \
ghcr.io/obmondo/gfetch daemonTo build locally:
docker build -t gfetch .
# With version info
docker build --build-arg VERSION=1.0.0 \
--build-arg COMMIT=$(git rev-parse --short HEAD) \
--build-arg DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ) \
-t gfetch .gfetch reads a YAML config file (default: config.yaml in the current directory). Use a defaults: key to share settings across multiple repositories.
defaults:
ssh_key_path: /home/gfetch/.ssh/id_rsa
poll_interval: 10m
prune: true # remove branches/tags no longer matching any pattern
prune_stale: true # remove branches with no commits in 6 months (requires prune: true)
stale_age: 180d # supports d (days)
# TODO: Add integration tests for real SSH Git repositories.
# TODO: Implement concurrent syncing for OpenVox mode to improve performance and reliability.
# TODO: Add configurable concurrency limit per repository.
repos:
my-service:
url: git@github.com:obmondo/my-service.git
branches:
- main
- /^release-.*/ # regex pattern
tags:
- "*" # wildcard matches all tags
internal-tool:
url: git@github.com:org/tool.git
prune_stale: false # override default for this repo
branches:
- mainSee docs/configuration.md for the full configuration reference, including all fields, pattern syntax, auth methods, and validation rules.
| Flag | Default | Description |
|---|---|---|
--config, -c |
config.yaml |
Path to config file |
--log-level |
info |
Log level: debug, info, warn, error |
One-shot sync of all repos (or a specific repo).
gfetch sync # sync all repos
gfetch sync --repo my-service # sync a specific repo
gfetch sync --prune # sync and remove obsolete branches/tags
gfetch sync --prune-stale # sync and remove branches with no commits in 6 months
gfetch sync --stale-age 30d # custom threshold for stale pruning
gfetch sync --prune --dry-run # show what would be pruned without deleting
gfetch sync --prune --prune-stale # also skips stale branches before branch sync| Flag | Default | Description |
|---|---|---|
--repo |
(empty) | Sync only the named repo |
--prune |
false |
Delete local branches/tags that no longer match any pattern |
--prune-stale |
false |
Delete local branches with no commits in the last 6 months; with --prune, stale branches are skipped before branch sync |
--stale-age |
180d |
Custom age threshold for stale pruning (e.g., 30d) |
--dry-run |
false |
Show what would be pruned without actually deleting |
Run as a foreground polling daemon. Each repo syncs immediately on start, then polls at its configured poll_interval. Shuts down gracefully on SIGINT or SIGTERM.
gfetch daemon
gfetch daemon --config /etc/gfetch/config.yaml --log-level debugPruning is controlled via prune and prune_stale config fields per-repo. Set prune: true in config to enable obsolete-ref pruning; prune_stale: true (also requires prune: true) to additionally prune inactive branches. The daemon does not reload config on changes — restart it to pick up new configuration.
Validate the config file and exit.
gfetch validate-config
gfetch validate-config -c /path/to/config.yamlPrint the fully resolved configuration as YAML. Loads the config, applies defaults, validates, and outputs the result to stdout.
gfetch cat
gfetch cat -c /path/to/config.yamlPrint version information.
$ gfetch version
gfetch dev (commit: none, built: unknown)Version, commit, and build date are injected at build time via ldflags when using GoReleaser or a manual build with -ldflags.
TBD