Multi-repo workflow tool for synchronized branches, linked PRs, and atomic merges.
Manage multiple related repositories as a single workspace with synchronized branches, linked pull requests, and atomic merges.
Inspired by Android's repo tool, gitgrip brings manifest-based multi-repo management to any project.
- Manifest-based configuration - Define all your repos in a single YAML file
- Composable workspaces - Inherit repos, scripts, hooks, and env from shared gripspace repositories
- Multi-platform support - Works with GitHub, GitLab, Azure DevOps, and Bitbucket (even mixed in one workspace)
- Synchronized branches - Create and checkout branches across all repos at once
- Linked PRs - Create pull requests that reference each other across repos
- Atomic merges - All-or-nothing merge strategy ensures repos stay in sync
- Status dashboard - See the state of all repos at a glance
brew tap laynepenney/tap
brew install gitgripcargo install gitgripPre-built binaries for Linux, macOS (Intel & Apple Silicon), and Windows are available on the releases page.
git clone https://github.com/laynepenney/gitgrip.git
cd gitgrip
cargo build --release
# Binary is at target/release/gr (or gr.exe on Windows)
# Install to ~/.cargo/bin:
cargo install --path .Create a new repo to hold your workspace config (e.g., my-workspace), then add a gripspace.yml:
version: 1
manifest:
url: git@github.com:your-org/my-workspace.git
repos:
frontend:
url: git@github.com:your-org/frontend.git
path: ./frontend
default_branch: main
backend:
url: git@github.com:your-org/backend.git
path: ./backend
default_branch: main
shared:
url: git@github.com:your-org/shared-libs.git
path: ./shared
default_branch: main
settings:
pr_prefix: "[cross-repo]"
merge_strategy: all-or-nothingFrom a manifest URL:
gr init git@github.com:your-org/my-workspace.gitFrom existing local directories:
# Auto-scan current directory for git repos
gr init --from-dirs
# Scan specific directories
gr init --from-dirs --dirs ./frontend ./backend
# Interactive mode - preview and edit manifest before saving
gr init --from-dirs --interactiveThis creates .gitgrip/spaces/main/gripspace.yml (with legacy .gitgrip/manifests/manifest.yaml compatibility).
# Check status of all repos
gr status
# Create a feature branch across all repos
gr branch feature/new-feature
# Make changes, commit in each repo, then create linked PRs
gr pr create --title "Add new feature"
# Sync all repos with latest from remote
gr sync| Command | Description |
|---|---|
gr init <url> |
Initialize workspace from manifest repo |
gr init --from-dirs |
Initialize workspace from existing local directories |
gr sync |
Pull latest from all repos (parallel by default) |
gr sync --sequential |
Pull repos one at a time |
gr status |
Show status of all repos |
gr branch [name] |
Create or list branches |
gr checkout <branch> |
Checkout branch across repos |
gr checkout -b <branch> |
Create and checkout branch in one command |
gr add [files] |
Stage changes across repos |
gr diff |
Show diff across repos |
gr commit -m "msg" |
Commit across repos |
gr push |
Push across repos |
gr pr create |
Create linked PRs |
gr pr status |
Show PR status |
gr pr merge |
Merge all linked PRs |
gr pr checks |
Show CI check status |
gr pr diff |
Show PR diff |
gr repo add <url> |
Add a new repository to workspace |
gr repo list |
List all repositories |
gr repo remove <name> |
Remove a repository |
gr group list |
List all groups and repos |
gr group add <group> <repos> |
Add repos to a group |
gr group remove <group> <repos> |
Remove repos from a group |
gr manifest schema |
Show manifest schema specification |
gr forall -c "cmd" |
Run command in each repo |
gr tree add <branch> |
Create a worktree-based workspace |
gr tree list |
List all griptrees |
gr tree remove <branch> |
Remove a griptree |
gr tree return |
Return to griptree base branch, sync, and optionally prune feature branch |
gr pull |
Pull latest changes across repos |
gr rebase |
Rebase across repos |
gr rebase --upstream |
Rebase onto per-repo upstream (griptree-aware) |
gr grep <pattern> |
Search across all repos |
gr prune |
Clean up merged branches (dry-run) |
gr prune --execute |
Delete merged branches |
gr gc |
Run garbage collection across repos |
gr cherry-pick <sha> |
Cherry-pick commits across repos |
gr ci run/list/status |
CI/CD pipeline operations |
gr link |
Manage file links |
gr run <script> |
Run workspace scripts |
gr env |
Show environment variables |
gr bench |
Run performance benchmarks |
gr completions <shell> |
Generate shell completions |
Initialize a new workspace by cloning the manifest repository and all defined repos.
Initialize a workspace from existing local git repositories. Discovers repos, extracts remote URLs and default branches, and generates a manifest.
| Option | Description |
|---|---|
--from-dirs |
Create workspace from existing directories |
--dirs <paths> |
Specific directories to scan (default: all subdirs) |
-i, --interactive |
Preview manifest and confirm before writing |
Features:
- Auto-detects remote URLs and default branches
- Handles duplicate directory names with auto-suffixing
- Initializes manifest as a git repository with initial commit
- In interactive mode, edit the generated YAML before saving
Pull latest changes from the manifest and all repositories. Syncs in parallel by default for faster performance.
| Option | Description |
|---|---|
--sequential |
Sync repos one at a time (slower but ordered output) |
--group <name> |
Only sync repos in this group |
-f, --force |
Force sync even with local changes |
--reset-refs |
Hard-reset reference repos to configured upstream branches |
Show status of all repositories including branch, changes, and sync state.
Checkout a branch across all repos. Can also create branches with the -b flag.
| Option | Description |
|---|---|
-b |
Create branch if it doesn't exist |
--base |
Checkout the griptree base branch (griptree workspaces only) |
Create a new branch across all repositories, or list existing branches. Manifest repo is always included.
| Option | Description |
|---|---|
-r, --repo <repos...> |
Only operate on specific repos |
-d, --delete |
Delete the branch |
-m, --move |
Move commits to new branch |
Create linked PRs across repos with changes.
| Option | Description |
|---|---|
-t, --title <title> |
PR title |
-b, --body <body> |
PR body |
-d, --draft |
Create as draft |
--push |
Push branches first |
Merge all linked PRs atomically.
| Option | Description |
|---|---|
-m, --method <method> |
merge, squash, or rebase |
-f, --force |
Merge even if checks pending |
-u, --update |
Update branch from base if behind, then retry merge |
--auto |
Enable auto-merge (merges when all checks pass) |
Add a new repository to the workspace. Parses the URL, updates the manifest, and optionally clones the repo.
| Option | Description |
|---|---|
--path <path> |
Local path (default: ./<repo-name>) |
--name <name> |
Name in manifest (default: from URL) |
--branch <branch> |
Default branch (default: main) |
--no-clone |
Only update manifest, skip cloning |
If the workspace is on a feature branch, the new repo will be checked out to that branch automatically.
Run a command in each repository (like AOSP's repo forall).
| Option | Description |
|---|---|
-c, --command |
Command to run (required) |
-r, --repo <repos...> |
Only run in specific repos |
--include-manifest |
Include manifest repo |
--continue-on-error |
Continue if command fails |
Environment variables available in command:
REPO_NAME- Repository nameREPO_PATH- Absolute path to repoREPO_URL- Repository URL
The workspace file (gripspace.yml) defines your workspace:
version: 1
# Inherit from shared gripspace repositories (optional)
gripspaces:
- url: git@github.com:your-org/base-workspace.git
rev: main # Pin to branch/tag/commit (default: remote HEAD)
manifest:
url: git@github.com:your-org/workspace.git
# Generate files from gripspace + local parts
composefile:
- dest: CLAUDE.md
parts:
- gripspace: base-workspace
src: CODI.md
- src: LOCAL_DOCS.md
repos:
repo-name:
url: git@github.com:your-org/repo.git
path: ./local-path
default_branch: main
settings:
pr_prefix: "[cross-repo]"
merge_strategy: all-or-nothingCompose workspaces from shared base configurations using gripspaces:. Gripspace repos are cloned into .gitgrip/spaces/ and their manifests are merged into the local workspace.
What gets merged: repos, scripts, env, hooks, linkfiles, and copyfiles. Local values always win on conflict. Resolution is recursive (max depth 5) with cycle detection.
gripspaces:
- url: git@github.com:org/platform-base.git # Shared infra repos + hooks
- url: git@github.com:org/frontend-tools.git # Frontend tooling scripts
rev: v2.0.0 # Pin to a specific version- all-or-nothing - All linked PRs must be approved before any can merge
- independent - PRs can be merged independently
gitgrip supports multiple hosting platforms. The platform is auto-detected from the repository URL.
| Platform | URL Patterns |
|---|---|
| GitHub | git@github.com:org/repo.git, https://github.com/org/repo.git |
| GitLab | git@gitlab.com:group/repo.git, https://gitlab.com/group/repo.git |
| Azure DevOps | git@ssh.dev.azure.com:v3/org/project/repo, https://dev.azure.com/org/project/_git/repo |
| Bitbucket | git@bitbucket.org:org/repo.git, https://bitbucket.org/org/repo.git |
Each platform requires its own authentication:
GitHub:
export GITHUB_TOKEN=your-token
# or
gh auth loginGitLab:
export GITLAB_TOKEN=your-token
# or
glab auth loginAzure DevOps:
export AZURE_DEVOPS_TOKEN=your-pat
# or
az loginBitbucket:
export BITBUCKET_TOKEN=your-app-passwordA single manifest can contain repos from different platforms:
repos:
frontend:
url: git@github.com:org/frontend.git
path: ./frontend
backend:
url: git@gitlab.com:org/backend.git
path: ./backend
infra:
url: https://dev.azure.com/org/project/_git/infra
path: ./infraFor GitHub Enterprise, GitLab self-hosted, or Azure DevOps Server, add a platform config:
repos:
internal:
url: git@gitlab.company.com:team/repo.git
path: ./internal
platform:
type: gitlab
baseUrl: https://gitlab.company.comWork on multiple branches simultaneously without switching. Griptrees use git worktrees to create parallel workspace directories.
# Create a griptree for a feature branch
gr tree add feat/new-feature
# Creates a sibling directory with all repos on that branch:
# ../feat-new-feature/
# ├── frontend/
# ├── backend/
# └── shared/
# Work in the griptree
cd ../feat-new-feature
gr status
# List all griptrees
gr tree list
# Lock to prevent accidental removal
gr tree lock feat/new-feature
# Remove when done (branches are preserved)
gr tree remove feat/new-featureUpstream Tracking:
Each griptree records per-repo upstream defaults so repos can track different branches:
# tree add sets branch tracking to each repo's configured upstream
gr tree add feat/new-feature
# Sync uses per-repo upstream when on the griptree base branch
# and repairs missing upstream tracking automatically
gr sync
# Rebase onto each repo's configured upstream
gr rebase --upstream
# Return to the griptree base branch
gr checkout --base
# Optional all-in-one post-merge return flow
gr tree return --autostash --prune-current --prune-remoteBenefits:
- No branch switching required
- Shared git objects (fast creation, minimal disk usage)
- Independent working directories
- Per-repo upstream tracking (different repos can target different branches)
Use gr as the primary command:
gr status
gr sync
gr branch feature/fooThe long form gitgrip also works.
Generate shell completions for tab completion:
# Bash
gr completions bash > ~/.local/share/bash-completion/completions/gr
# Or add to ~/.bashrc:
eval "$(gr completions bash)"
# Zsh
gr completions zsh > ~/.zfunc/_gr
# Or add to ~/.zshrc:
eval "$(gr completions zsh)"
# Fish
gr completions fish > ~/.config/fish/completions/gr.fish
# PowerShell
gr completions powershell >> $PROFILESupported shells: bash, zsh, fish, elvish, powershell
- Git
- Platform CLI (optional, for token auth fallback):
- GitHub:
ghCLI - GitLab:
glabCLI - Azure DevOps:
azCLI
- GitHub:
Additional documentation is available in the docs/ folder:
- MANIFEST.md - Complete manifest reference with examples
- SKILL.md - Exportable skill file for AI assistants
- TELEMETRY.md - Telemetry, tracing, and benchmarks
View the manifest schema from the CLI:
gr manifest schema # YAML format
gr manifest schema --format json # JSON format
gr manifest schema --format markdown # Markdown tablegitgrip includes a skill file for AI coding assistants (Claude Code, Codex, etc.).
Copy the skill file to your workspace:
mkdir -p .claude/skills/gitgrip
cp docs/SKILL.md .claude/skills/gitgrip/SKILL.mdOr copy from an existing gitgrip workspace.
The skill file teaches AI assistants to:
- Use
grcommands instead of rawgitcommands - Follow multi-repo workflow patterns
- Create proper linked PRs across repos
- Manage branches and sync correctly
This project was originally written in TypeScript and published to npm as gitgrip. It was rewritten in Rust for better performance and additional features.
MIT