A CLI tool for managing multiple Git repositories as a unified workspace. Define your repos in gitjoin.txt files, and Gitjoin will clone, pull, and prune them for you.
Install via:
go install github.com/bep/gitjoin@latest
If you have hundreds of Git repositories across different technologies and domains, keeping them in separate repositories makes sense β until you need to operate on or configure all (or a subset) of them as a whole.
Examples:
- Share a common
AGENTS.mdacross all Go repositories. - Share common API keys across all AWS applications.
- Update dependencies in all Go repos (or a subset using
--paths "go/**/foo"). - Prompt an AI agent to make changes across repos and create PRs.
Git Submodules track a specific commit in each sub-repo and embed that reference in the parent. This is the right tool when you need a pinned, reproducible dependency tree β but it's the wrong tool when your goal is a workspace of independent repos you want to keep up to date.
Gitjoin treats the listed repos as peers, not dependencies:
- No commit in the parent repo when a child repo changes.
- No detached-HEAD checkouts β every repo stays on its default branch.
- Adding or removing a repo is a one-line edit in
gitjoin.txt, not a Git operation. - Shared configuration files (
AGENTS.md,firstup.env, β¦) sit alongside the repos without being wired into their history.
If you need version-pinning, use submodules. If you need a convenient umbrella for many repos you actively develop, Gitjoin is a better fit.
.
βββ go
β βββ AGENTS.md
β βββ apps
β β βββ gitjoin.txt
β βββ firstup.env
β βββ libs
β βββ gitjoin.txt
βββ sites
βββ AGENTS.md
βββ firstup.env
βββ gitjoin.txt
gitjoin.txtβ one Git repository path per line (e.g.github.com/bep/s3deploy). Lines starting with#are comments.firstup.envβ environment variables for that branch (see firstupdotenv), typically referencingop://paths so you can commit this to Git.AGENTS.mdβ AI agent guide for that branch.- Cloned repo content is automatically added to
.gitignore.
Running gitjoin from the workspace root syncs all repositories defined in gitjoin.txt files recursively: clones missing repos, pulls updates for existing ones, and removes repos no longer listed. Note that you can start at any subdirectory with a gitjoin.txt to sync just that subtree.
| Flag | Description |
|---|---|
--force |
Force sync (see below) |
--quiet |
Suppress output |
--paths |
Glob filter for repo paths (e.g. "go/**/foo") |
| Condition | Action |
|---|---|
| Repo on non-default branch | Skip, warn in summary |
| Repo with uncommitted changes | Skip, warn in summary |
| Clean repo on default branch | Pull |
For repos that would normally be skipped:
- Stash uncommitted changes (if any)
- Switch to default branch
- Pull
- Unstash (if stashed)
If unstash fails due to conflicts, warn and leave stash intact.