v0.4.0 · Open source · Written in Go
Virtual monorepo made simple.
Keep every repository where it is. List them in a plain-text
gitjoin.txt, run one command, and work across all of
them as one tree.
go install github.com/bep/gitjoin@latest
One file. One command. One tree.
A gitjoin workspace is an ordinary Git repo with a few text files in it. gitjoin fills in the rest.
# Lines starting with # are comments.
github.com/bep/gitjoin
github.com/bep/grrep
github.com/bep/s3deploy$ gitjoin
Updated: 2 repos
- go/apps/grrep (pulled)
- sites/gitjoin.com (pulled)
Cloned: 2 repos
- go/libs/godartsass
- go/libs/helpers
Removed: 2 repos
- go/apps/oldtool
- sites/oldsite.com
Skipped (uncommitted changes): 2 repos
- go/apps/s3deploy (2 modified)
- sites/grrep.com (1 added)/public/
# Managed by gitjoin - do not edit this section
/gitjoin/
/grrep/
/s3deploy/
# End gitjoin managed sectionMonorepo ergonomics. No migration.
Your repositories keep their own history, owners, CI and release cycles. gitjoin only decides where they live on disk.
Plain-text manifest
One repository per line,
#for comments. Adding or removing a repo is a one-line diff, not a Git operation.Clone, pull, prune
One command brings the tree in line with the manifests. Only repos gitjoin cloned are ever removed.
Safe by default
Repos with uncommitted changes or on a feature branch are skipped and reported, never touched.
--forcewhen you mean itStash, switch to the default branch, pull, unstash. If the unstash conflicts, the stash is left intact.
Nested and partial
gitjoin.txtfiles are found recursively. Start in any subdirectory to sync only that subtree.Shared context
Drop an
AGENTS.mdorfirstup.envnext to a group of repos and it applies to all of them, outside their history.Peers, not pins
Every repo stays on its default branch and remains fully independent. No detached HEADs.
Parallel
Repos are synced concurrently, at least four at a time, or one per CPU core if you have more.
Separate repos are right. Until you need all of them at once.
- Share one
AGENTS.mdacross every Go repository. - Share API keys across all AWS applications with firstupdotenv.
- Update dependencies in all Go repos in one go.
- Prompt an AI agent to make changes across repos and open the PRs.
- Search everything with grrep, which understands gitjoin boundaries.
Submodules pin dependencies. gitjoin gathers peers.
Need a reproducible, version-pinned tree? Use submodules, that is what they are for. Need an umbrella over many repos you actively develop? That is gitjoin.
| Aspect | Git submodules | gitjoin |
|---|---|---|
| Relationship | Pinned dependencies | Independent peers |
| A child repo changes | Commit in the parent | Nothing to commit |
| Checkout | Detached HEAD at a pinned commit | Default branch, kept up to date |
| Add or remove a repo | git submodule add / deinit | Edit one line |
| Built for | Reproducible, pinned trees | A workspace you actively develop |