Vetrix Docs

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

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.enabled admin setting, which is off by default. While disabled, every AccountTransfer endpoint returns 404, 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