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
View on GitHub
workspace
1 plain-text manifest format
2 flags, --force and --quiet
0 commits in the parent repo
4+ repos synced in parallel
How it works

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.

go/apps/gitjoin.txt
# Lines starting with # are comments.
github.com/bep/gitjoin
github.com/bep/grrep
github.com/bep/s3deploy
Features

Monorepo 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.

  • --force when you mean it

    Stash, switch to the default branch, pull, unstash. If the unstash conflicts, the stash is left intact.

  • Nested and partial

    gitjoin.txt files are found recursively. Start in any subdirectory to sync only that subtree.

  • Shared context

    Drop an AGENTS.md or firstup.env next 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.

Why

Separate repos are right. Until you need all of them at once.

  • Share one AGENTS.md across 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.
vs. Git submodules

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.

AspectGit submodulesgitjoin
RelationshipPinned dependenciesIndependent peers
A child repo changesCommit in the parentNothing to commit
CheckoutDetached HEAD at a pinned commitDefault branch, kept up to date
Add or remove a repogit submodule add / deinitEdit one line
Built forReproducible, pinned treesA workspace you actively develop
Get started

Join your repos.

go install github.com/bep/gitjoin@latest
bep/gitjoin