Admin: Git Storage
This document covers the on-disk layout for Git repositories, backup strategies, and repository migration.
Disk layout
/data/ # git.repo_root in vetrix.toml
repos/
<owner>/
<repo>.git/ # bare Git repository
HEAD
config
objects/
pack/
...
refs/
heads/
tags/
blobs/ # storage.blob_dir — CI artifacts, registry files
artifacts/
<pipeline-id>/
<job-id>/
registry/
containers/
npm/
pypi/
go/
ssh_host_ed25519_key # SSH server host key
ssh_host_ed25519_key.pub
Each repository is stored as a standard bare Git repository. You can interact with them using any standard Git tooling:
git -C /data/repos/myorg/myrepo.git log --oneline
Configuration
[git]
repo_root = "/data/repos"
ssh_listen = "0.0.0.0:22"
ssh_host_key_path = "/data/ssh_host_ed25519_key"
[storage]
blob_dir = "/data/blobs"
Disk usage monitoring
The admin health endpoint reports disk usage:
curl https://<vetrix-host>/api/v1/admin/health \
-H "Authorization: Bearer <admin-token>"
{
"disk": {
"path": "/data",
"total_gb": 500.0,
"free_gb": 320.5,
"used_pct": 35.9
}
}
Alert if used_pct exceeds 80%. At 90%, Git operations may begin failing.
Repository garbage collection
Git repositories accumulate loose objects over time. Run GC periodically to pack and prune:
# Per-repository
git -C /data/repos/<owner>/<repo>.git gc --auto
# All repositories
find /data/repos -name "*.git" -type d -exec git -C {} gc --auto \;
Configure automatic GC via cron in vetrix.toml:
[git]
gc_cron = "0 3 * * *" # daily at 3 AM
Backups
Filesystem snapshot (recommended)
For consistent backups, pause writes briefly by enabling maintenance mode, take a filesystem snapshot (LVM, ZFS, cloud volume snapshot), then disable maintenance mode:
# Enable maintenance mode
curl -X PUT https://<vetrix-host>/api/v1/admin/settings/maintenance.enabled \
-H "Authorization: Bearer <admin-token>" -d '"true"'
# Take snapshot (example: LVM)
lvcreate --snapshot --name vetrix-data-snap --size 10G /dev/vg0/vetrix-data
# Disable maintenance mode
curl -X PUT https://<vetrix-host>/api/v1/admin/settings/maintenance.enabled \
-H "Authorization: Bearer <admin-token>" -d '"false"'
rsync backup
Git bare repositories are safe to rsync while the server is running because Git writes are atomic at the ref level:
rsync -avz --delete /data/repos/ backup-host:/backups/vetrix/repos/
pg_dump $DATABASE_URL | gzip > /backups/vetrix/db-$(date +%Y%m%d).sql.gz
Run the database dump and repo rsync close together in time to minimize divergence.
What to back up
| Path | Importance | Notes |
|---|---|---|
/data/repos/ |
Critical | All Git repository data |
| Database | Critical | Issues, PRs, users, settings, tokens (hashed) |
/data/blobs/ |
Important | CI artifacts, registry packages |
/data/ssh_host_* |
Low | Host key — lose this and clients will see host key warning |
vetrix.toml |
Low | Config is recoverable from documentation |
Migrating a repository
Import from another Git host
# Clone bare from source
git clone --mirror https://github.com/org/repo.git /tmp/repo.git
# Create the repo in Vetrix (via API)
curl -X POST https://<vetrix-host>/api/v1/repos \
-H "Authorization: Bearer <admin-token>" \
-d '{"name": "repo", "namespace": "org"}'
# Push all refs to Vetrix
cd /tmp/repo.git
git remote set-url origin git@<vetrix-host>:org/repo.git
git push --mirror origin
Moving between namespaces
Repository ownership is moved between namespaces with the admin AccountTransfer tool, not a single synchronous request. Before relying on it, be aware of a few properties that affect operator expectations:
- It is gated by the
transfer.enabledadmin setting, which is off by default. While disabled, every AccountTransfer endpoint returns404, as if the surface did not exist. - It runs as a multi-phase orchestrator (preflight, confirm, execute, verify) rather than one atomic call, and the filesystem rename and the database update are separate steps within that flow.
- It is one-way past a certain point: once the execute step has committed, a later failure during verification is not rolled back on the filesystem side. Recovering from that state requires manual reconciliation from the manifest archive captured earlier in the flow.
- Existing collaborator and group grants on the moved repository are dropped as part of the transfer; the new owner has to re-grant access.
For the endpoint reference, request/response shapes, failure classes, and
recovery procedures, see repo-transfer.md.
Orphaned repository cleanup
Repositories deleted via API have their on-disk directory moved to a .trash/<timestamp>-<repo>.git subdirectory of repo_root and scheduled for permanent deletion after 30 days.
To list trashed repositories:
ls -la /data/repos/.trash/
To restore a trashed repository, move it back and recreate the database record via the API.
To purge immediately:
vetrix admin purge-trash