Safe multi-repo Git status, checkpoint, commit, and push for repo families.
Project description
Gites
Gites is a safe multi-repo Git CLI for developers who manage many related repositories outside a monorepo. It gives a repo family one short name, shows a single table of branch/dirty/ahead/behind state, and can commit and push the eligible repositories with one deterministic checkpoint command.
Use it when you have a directory full of Git repos and need a practical way to
inspect, checkpoint, and push them without hand-running git status, git commit, and git push in every folder.
The interface is intentionally context-like: register a directory as a named
instance, list the instances, select the active one, then run short commands
against it. If you are used to Docker contexts or named environments, gites
applies that same small mental model to repo families.
Why Gites
- Define a directory of repositories as a named instance, then select it from a list.
- One command shows a table for every repo in a saved root.
- One command previews or applies a bulk Git checkpoint.
- Unsafe repos are refused instead of force-pushed or silently modified.
- Large repo roots are inspected in parallel with timeouts.
- Local run ledgers stay ignored and private.
- Works well for WSL users who keep large Git repo families on native Linux
paths instead of slow
/mnt/c/...checkouts.
Typical use cases include multi-repo project families, research/code archives, documentation surface repos, generated repo sets, and teams that want some of the operational convenience of a monorepo without merging repositories together.
The name carries the idea: Git plus easy, and also gites as in small houses
or lodgings. A gites root is meant to feel like a modest home for related
repositories: each repo keeps its own room, while the front door gives you one
place to check what changed and send the whole house home safely.
Install
For regular CLI use, pipx is recommended:
pipx install gites
pipx upgrade gites --pip-args="--no-cache-dir"
pip also works:
pip install gites
For local development:
pip install -e .
Simple Workflow
The normal workflow is to register a repo root once, give it a short name, and then operate on that named object.
Register the current directory as a repo root:
cd ~/repos/work
gites init --name work --branch main
Or register an explicit path:
gites init ~/repos/work --name work --branch main
List saved roots:
gites dirs
Switch active root:
gites use work
Show the current repo-state table for a saved root:
gites view
gites view work
gites status work
gites work
Viewing a named instance prints the selected directory, optional progress, and then a single table for the repositories inside that instance:
$ gites view work
dir: work root: ~/repos/work branch: main
untracked scan: skipped (use --untracked for full scan)
Inspecting 4 repos with 15 worker(s)...
[1/4] api-service -> noop
[2/4] web-app -> sync
[3/4] docs-site -> noop
[4/4] local-tooling -> refuse
repo branch ahead behind dirty untracked action reason
------------- ------ ----- ------ ----- --------- ------ --------------------------------
api-service main 0 0 no no noop working tree clean
web-app main 1 0 yes no sync
docs-site main 0 0 no no noop working tree clean
local-tooling main 0 0 no no refuse missing origin remote
view, status, and object shortcuts inspect repositories in parallel, show
progress by default, use 15 workers, apply a 60 second per-Git-command timeout,
and skip expensive untracked-file enumeration unless requested:
gites view work
gites view work --untracked
gites view work --no-progress
gites view work --jobs 30 --timeout 120
Preview what would be pushed:
gites push
gites push work
push defaults to a dry-run. Its output summarizes clean repositories in one
line and expands only the repositories that would sync, refuse, or fail:
$ gites push work
dir: work root: ~/repos/work branch: main mode: dry-run
No commit was made. Add -m/--message to apply.
run_id: 2b3389c7-6cf7-4cb6-86d5-2a7fdcf8d6b9
applied: no
summary: clean=2, would_sync=1, refused=1, failed=0
clean: 2 repo(s) had no changes.
would sync:
- web-app: 3 file(s): 2 modified, 1 untracked; head 287d9c3ecebc
refused:
- local-tooling: no file changes; missing origin remote
Apply with a deterministic commit message:
gites push work -m "chore: checkpoint repo family 2026-05-11"
The saved directory config lives outside the repo at ~/.config/gites/config.json.
Table Output
The status table is meant to be the main decision surface:
repo branch ahead behind dirty untracked action reason
-------------------- ------ ----- ------ ----- --------- ------ ------------------
api-service main 0 0 no no noop working tree clean
web-app main 1 0 yes no sync
local-tooling main 0 0 no no refuse missing origin remote
Actions:
noop: clean and already aligned with upstreamsync: eligible for commit and pushrefuse: not safe to modify automatically; read the reason column
gites refuses local-only repositories because it cannot safely push them until
they have an origin remote and an upstream branch.
WSL Guidance
For large repo roots on WSL, prefer native Linux paths such as:
~/repos/work
Avoid using /mnt/c/... as the active root for very large repositories.
Windows-mounted paths can make git status and git commit slow because Git
must perform many metadata checks through the WSL-to-Windows filesystem bridge.
The same repo can be much faster when cloned or moved under the native WSL
filesystem.
Explicit Workflow
The lower-level plan and sync commands remain available for scripts and
one-off roots. Most interactive use should prefer view and push.
Preview repositories under a root directory:
gites plan --root ~/repos/work --branch main
Dry-run a checkpoint:
gites sync --root ~/repos/work --branch main --dry-run
Apply a checkpoint with an explicit commit message:
gites sync --root ~/repos/work \
--branch main \
--apply \
--message "chore: checkpoint repo family 2026-05-10"
Read local run ledgers:
gites ledger list --root ~/repos/work
gites ledger show RUN_ID --root ~/repos/work
Ledgers are written under .gites/ledgers/ inside the selected root. That directory is intentionally ignored by Git.
Safety Rules
gites sync --apply refuses a repository when it detects:
- detached
HEAD - merge, rebase, cherry-pick, or revert in progress
- unresolved conflicts
- wrong branch
- missing
origin - missing upstream branch
- branch behind upstream
- branch diverged from upstream
- protected path changes such as
.env,secrets/,private/, orinternal/ - changed files larger than the configured size limit
- missing commit message in apply mode
Gites never force-pushes by default.
Manifest Files
Real manifests should stay local and ignored, for example my_gites.json or gites.local.json.
Create a local template:
gites config init my_gites.json
Validate a manifest:
gites config validate my_gites.json
Use a family from a manifest:
gites sync --manifest my_gites.json \
--family default \
--dry-run
A sanitized public example is available at examples/example.gites.json.
Development
Run tests:
python -m unittest discover -v
Privacy
Do not commit real manifests, ledgers, credentials, ChatGPT exports, private notes, or local editor state. The repository .gitignore blocks the intended local-only paths.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gites-0.5.7.tar.gz.
File metadata
- Download URL: gites-0.5.7.tar.gz
- Upload date:
- Size: 21.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2e8c704990ab491a0c0127b385b49a413ae5704bff2dcac9574997b952464735
|
|
| MD5 |
145ed45b05e40082e8776edb37111332
|
|
| BLAKE2b-256 |
42bea9f0d42802fd8f2e1546bb62f05131a69f57e01ba161cf886d20e15143f0
|
File details
Details for the file gites-0.5.7-py3-none-any.whl.
File metadata
- Download URL: gites-0.5.7-py3-none-any.whl
- Upload date:
- Size: 19.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fb9371c99efa7cea88a4a97fc318dd2fbc3d60ee587f6344297d3188829185be
|
|
| MD5 |
37e3258cc3bdbaea9368ea367b0455ba
|
|
| BLAKE2b-256 |
f21cf450442eabe2dba70beac98dc288cf77a5d148bf7eae6471b8c04ebcc961
|