Skip to main content

Git repository synchronization tool for teams

Project description

repo-sync-kitty

Git repository synchronization tool for teams. Keep multiple git repositories in sync across machines using a declarative TOML manifest.

Features

  • Manifest-driven: Define repositories in a single TOML file
  • Safe pulls: Multiple precondition checks before pulling (dirty state, wrong branch, unpushed commits)
  • Parallel operations: Configurable concurrency for faster syncs
  • Multiple remotes: Support for GitHub, GitLab, Bitbucket, and custom git servers
  • Rich output: Progress bars, colored status tables, and detailed summaries

Installation

Homebrew (macOS)

brew tap vladistan/gizmos
brew install repo-sync-kitty

PyPI

pip install repo-sync-kitty

From source

# Using uv (recommended)
cd tools/repo-sync-kitty
uv sync
uv run repo-sync-kitty --help

# Or install globally with pip
pip install .

Quick Start

  1. Initialize a manifest in your projects directory:
# Create an empty template
repo-sync-kitty init -o manifest.toml

# Or scan an existing directory for repos
repo-sync-kitty init --scan-dir ~/Projects -o manifest.toml
  1. Validate your manifest:
repo-sync-kitty check -m manifest.toml
  1. Sync your repositories:
# Dry run first
repo-sync-kitty sync -m manifest.toml --dry-run

# Actually sync
repo-sync-kitty sync -m manifest.toml
  1. Check status anytime:
repo-sync-kitty status -m manifest.toml

Commands

sync - Clone and update repositories

repo-sync-kitty sync [OPTIONS]

Options:
  -m, --manifest PATH    Path to manifest.toml
  --fetch-only           Only fetch, don't clone or pull
  --clone-only           Only clone missing repos
  --pull                 Pull changes after fetch (if safe)
  -n, --dry-run          Show what would be done
  -v, --verbose          Show detailed output instead of progress bar
  -j, --parallelism INT  Override parallelism setting

Examples:

# Clone missing repos and fetch all
repo-sync-kitty sync -m manifest.toml

# Clone missing repos only
repo-sync-kitty sync -m manifest.toml --clone-only

# Fetch and pull (when safe)
repo-sync-kitty sync -m manifest.toml --pull

# Verbose output with 2 parallel workers
repo-sync-kitty sync -m manifest.toml -v -j 2

status - Show repository status

repo-sync-kitty status [OPTIONS]

Options:
  -m, --manifest PATH   Path to manifest.toml
  -v, --verbose         Show all repos (not just issues)
  --show-deleted        Include deleted repos in output

Output shows:

  • Missing repos (not cloned)
  • Dirty repos (uncommitted changes)
  • Wrong branch
  • Ahead/behind remote
  • Detached HEAD state

check - Validate manifest

repo-sync-kitty check [OPTIONS]

Options:
  -m, --manifest PATH   Path to manifest.toml

Validates manifest syntax, checks that all referenced remotes exist, and displays a summary of configuration.

fix-detached - Fix detached HEAD states

repo-sync-kitty fix-detached [OPTIONS]

Options:
  -m, --manifest PATH    Path to manifest.toml
  -n, --dry-run          Show what would be done without making changes
  -v, --verbose          Show detailed output instead of progress bar
  -j, --parallelism INT  Number of parallel workers

Examples:

# Dry run to see what would be fixed
repo-sync-kitty fix-detached -m manifest.toml --dry-run

# Fix detached HEADs
repo-sync-kitty fix-detached -m manifest.toml

Safely fixes detached HEAD states left by git-repo. For each detached repo:

  1. Checks for loose files - aborts if there are untracked, modified, or staged files
  2. Finds branch at HEAD - checks if HEAD points to a branch tip
  3. Checks out the branch - only if HEAD is at a branch tip

This is safe for repos previously maintained by git-repo, which leaves repos in detached HEAD state pointing at branch tips.

init - Create new manifest

repo-sync-kitty init [OPTIONS]

Options:
  -o, --output PATH     Output path for manifest.toml (default: manifest.toml)
  --scan-dir PATH       Scan directory for existing repos
  --scan-forge NAME     Scan forge for repos (not yet implemented)
  --org NAME            Organization/user to scan on forge
  -f, --force           Overwrite existing manifest

Examples:

# Create empty template
repo-sync-kitty init

# Scan ~/Projects for git repos and generate manifest
repo-sync-kitty init --scan-dir ~/Projects -o my-manifest.toml

add - Add repository to manifest

repo-sync-kitty add REMOTE SLUG [OPTIONS]

Arguments:
  REMOTE               Remote name (must exist in manifest)
  SLUG                 Repository slug (e.g., 'owner/repo')

Options:
  -m, --manifest PATH  Path to manifest.toml
  -p, --path PATH      Local path (defaults to repo name from slug)
  -b, --branch NAME    Branch to track

Examples:

# Add repo with default path
repo-sync-kitty add origin octocat/Hello-World -m manifest.toml

# Add repo with custom path and branch
repo-sync-kitty add origin owner/repo -p libs/myrepo -b develop

import-repo - Import from git-repo manifest

repo-sync-kitty import-repo SOURCE [OPTIONS]

Arguments:
  SOURCE               Path to git-repo manifest XML file (e.g., default.xml)

Options:
  -o, --output PATH    Output path for manifest.toml (default: manifest.toml)
  -r, --root PATH      Root path for repos (default: parent of source file)
  -f, --force          Overwrite existing manifest

Examples:

# Import from default.xml in current directory
repo-sync-kitty import-repo default.xml

# Import with custom output path
repo-sync-kitty import-repo ~/repo/default.xml -o my-manifest.toml

# Import and set custom root path
repo-sync-kitty import-repo default.xml -r ~/Projects/myteam -o manifest.toml

This command converts Google's git-repo manifest format (XML) to repo-sync-kitty's TOML format. The importer handles:

  • Multiple remotes with different base URLs
  • Default remote and branch settings
  • Per-project remote and branch overrides
  • Stripping .git suffix from project names

scan - List repositories from forge

repo-sync-kitty scan FORGE [OPTIONS]

Arguments:
  FORGE                Forge to scan (github, gitlab)

Options:
  --org, -o NAME       Organization/user to scan (required)
  --token, -t TOKEN    API token for authentication
  -m, --manifest PATH  Path to manifest.toml (for comparison)
  -r, --remote NAME    Remote to use when adding repos
  --missing            Only show repos not already in manifest
  --add                Add scanned repos to manifest (requires -r)

Examples:

# Scan public GitHub repos
repo-sync-kitty scan github --org octocat

# Scan with token (required for private repos)
repo-sync-kitty scan github --org myorg --token $GH_TOKEN

# Compare against manifest (shows checkmarks for enrolled repos)
repo-sync-kitty scan github --org myorg -m manifest.toml

# Show only repos not in manifest
repo-sync-kitty scan github --org myorg -m manifest.toml --missing

# Add missing repos to manifest
repo-sync-kitty scan github --org myorg -m manifest.toml -r origin --add

Note: For GitHub, the token is checked in order: -t option → GH_TOKEN env var → GITHUB_TOKEN env var. A token is required to see private repositories.

Manifest Format

Basic Structure

[common]
root_path = "~/Projects/my-team"
branch = "main"
remote = "origin"
parallelism = 4
timeout = 300

[remotes]
origin = { base_url = "https://github.com/" }
gitlab = { base_url = "https://gitlab.com/", branch = "master" }

[projects]
"libs/repo1" = { slug = "owner/repo1" }
"libs/repo2" = { slug = "owner/repo2", branch = "develop" }

Common Section

Field Type Default Description
root_path string required Base directory for all repos
branch string "main" Default branch to track
remote string required Default remote name
parallelism int 4 Max concurrent operations
timeout int 300 Operation timeout in seconds

Remotes Section

Supports two formats:

Compact (inline):

[remotes]
ghpub = { base_url = "https://github.com/" }
mine = { base_url = "ssh://git@github.com/myuser/", branch = "develop" }

Expanded (multi-line):

[remotes.mine]
base_url = "ssh://git@github.com/myuser/"
branch = "develop"
parallelism = 2
timeout = 600
Field Type Default Description
base_url string required Base URL for clone URLs
branch string inherited Default branch for this remote
parallelism int inherited Max concurrent ops for this remote
timeout int inherited Timeout for this remote's operations

Projects Section

Compact:

[projects]
"libs/linkml" = { slug = "linkml/linkml", remote = "ghpub" }
"infra" = { slug = "infra", branch = "develop" }

Expanded:

[projects."libs/linkml"]
slug = "linkml/linkml"
remote = "ghpub"
branch = "main"
Field Type Default Description
slug string required Repository slug (owner/repo)
path string key Local path relative to root_path
remote string inherited Remote to use
branch string inherited Branch to track
status string "active" One of: active, archived, deleted

Inheritance

Values inherit in this order: project → remote → common

branch: project.branch → remote.branch → common.branch
parallelism: remote.parallelism → common.parallelism
timeout: remote.timeout → common.timeout

URL Construction

Clone URLs are constructed as: {remote.base_url}{project.slug}.git

Examples:

  • https://github.com/ + linkml/linkmlhttps://github.com/linkml/linkml.git
  • ssh://git@github.com/myuser/ + infrassh://git@github.com/myuser/infra.git

Safety Checks

Before pulling, repo-sync-kitty checks:

  1. Correct branch: Current branch matches expected
  2. Clean state: No uncommitted changes
  3. No staged files: Nothing in the index
  4. No in-progress operations: Not rebasing, merging, or cherry-picking
  5. Not detached: HEAD is attached to a branch
  6. Not ahead: No unpushed commits

If any check fails, the repo is skipped with a warning.

Environment Variables

Variable Description
GH_TOKEN GitHub API token for scan command (preferred)
GITHUB_TOKEN GitHub API token for scan command (fallback)
GITLAB_TOKEN GitLab API token for scan command
SENTRY_DSN Optional Sentry DSN for error tracking

Exit Codes

Code Meaning
0 Success
1 One or more operations failed
2 Invalid manifest or configuration

Development

# Install with dev dependencies
uv sync --extra dev

# Run tests
uv run pytest

# Run with coverage
uv run pytest --cov=src --cov-report=term-missing

# Lint
uv run ruff check src/ tests/

# Type check
uv run mypy src/

Troubleshooting

"Not safe to pull" warnings

This means one of the safety checks failed. Run status -v to see details:

repo-sync-kitty status -m manifest.toml -v

Common causes:

  • Uncommitted changes → commit or stash them
  • Wrong branch → checkout the expected branch
  • Unpushed commits → push your changes first
  • In-progress rebase → complete or abort the rebase

"Remote not found" errors

The remote referenced in a project doesn't exist in the [remotes] section. Add it or fix the reference.

Slow syncs

Try increasing parallelism:

repo-sync-kitty sync -m manifest.toml -j 8

Or set it in your manifest:

[common]
parallelism = 8

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

repo_sync_kitty-0.2.1.tar.gz (179.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

repo_sync_kitty-0.2.1-py3-none-any.whl (58.7 kB view details)

Uploaded Python 3

File details

Details for the file repo_sync_kitty-0.2.1.tar.gz.

File metadata

  • Download URL: repo_sync_kitty-0.2.1.tar.gz
  • Upload date:
  • Size: 179.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for repo_sync_kitty-0.2.1.tar.gz
Algorithm Hash digest
SHA256 8c55c4c15753a7f74c785a4384629b2274caa2f484afda1b7a2e8d83ae0b2228
MD5 3859dc20399069e76d8ff31aeeca0ff4
BLAKE2b-256 d335f97374816232baae24d08a7554a1a3f650f6072a8647a4dc1434dae43aec

See more details on using hashes here.

File details

Details for the file repo_sync_kitty-0.2.1-py3-none-any.whl.

File metadata

File hashes

Hashes for repo_sync_kitty-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 81bfd1cbb8a0572c00635dc92c8e772a197d8f00685fe3b12f18d1870649afce
MD5 a68702ce80c9ab732348a1d197189ccb
BLAKE2b-256 6e6931185075685d0ba3ed1efd10fb69c57e18331237f92877e21268e10d8710

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page