git-coherent
v0.1.6
Published
Synchronised git operations across sibling repos opted-in via .git-coherent marker
Readme
git-coherent
Synchronised git operations across opted-in sibling repositories. A halfway house between a monorepo and fully independent polyrepos: each project keeps its own .git and its own remote, but you can commit, switch branches, push, and inspect status across the whole group with one command.
Mental model
~/some-group/
├─ project-a/ ← git repo, has .git-coherent
├─ project-b/ ← git repo, has .git-coherent
├─ standalone/ ← git repo, NO .git-coherent → ignored
└─ git-coherent/ ← git repo, has .git-coherent (this tool itself)A group is a directory whose children opt in by placing an empty .git-coherent marker file at their repo root. No central registry, no manifest — the file system is the source of truth.
The anchor is the deepest .git-coherent ancestor of your current working directory — i.e. the project you're "inside" right now. Its current branch is the target branch for synchronised commits.
The Coherent-Id is a timestamp + hex stamp injected into each commit's trailer when you run git coherent commit. It lets you reconstruct what was committed together across repos, independent of commit messages or order.
Install
# option 1 — npm (global)
cd ~/okneigres-repos/git-coherent
npm install -g .
# option 2 — symlink into ~/.local/bin (no npm)
./install.shBoth git coherent <cmd> (git's plugin mechanism) and gitc <cmd> (short alias) will work after install.
Quick start
# step 1: git-coherent init
cd ~/some-group/project-a
git-coherent init
# → creates .git-coherent marker
# → if package.json present: adds "git-coherent": "*" to devDependencies
git add .git-coherent package.json && git commit -m "join coherent group"
# step 2: npm install — triggers git-coherent's own postinstall
npm install
# git-coherent's postinstall:
# • wires three hooks (prepare, postinstall, dependencies) into your
# package.json — all set to node -e "import('git-coherent/link-packages.js')"
# • runs the linker once so symlinks land immediately
# any subsequent `npm i <anything>` will re-symlink via the wired hooks.
# repeat for project-b, project-c, ...
# see the state
gitc status
# create a feature branch in the anchor repo as usual
cd ~/some-group/project-a
git checkout -b feature/login
# edit code in project-a AND project-b...
# commit everything dirty in one go
# project-b will be switched to feature/login first (since it's dirty
# and on a different branch); clean repos are left alone.
gitc commit -am "add login UI and API"
# push everything
gitc push -u origin HEADCommands
| command | what it does |
|---|---|
| init | create the .git-coherent marker in the current repo. If it's a Node project, also add "git-coherent": "*" to devDependencies. The hook wiring + initial linking happen automatically on the next npm install — git-coherent's own postinstall script does that. Principle: "in package.json → hooks wired" |
| status / st | per-member: current branch, dirty state, ahead/behind, anchor marker; highlights which members would be switched on next commit |
| commit / ci -m "msg" [-a] | commit every dirty member with one message + shared Coherent-Id trailer; switches dirty members to the anchor's branch first if needed (creates it if missing); clean members are skipped |
| checkout / co <ref> | switch every member to <ref> (refuses if any tree is dirty); skips members where the branch doesn't exist |
| checkout / co -b <ref> | create branch <ref> in every member |
| diff [args...] | per-member git diff, skipping members with no diff |
| push [args...], pull [args...] | run in every member |
| exec -- <cmd>... | run any command in every member |
Semantics
Discovery
From cwd, walk up until a directory either contains a .git-coherent (anchor case → group root is the parent) or contains a child with .git-coherent (cwd-is-root case → group root is cwd). Members of the group = direct children of group root that have both .git/ and .git-coherent.
Commit rule
The anchor's current branch is the target. For each member:
- clean → skip (even if on a different branch).
- dirty, same branch → commit.
- dirty, different branch → switch (or create) to target, then commit.
A Coherent-Id trailer ties them together. Atomicity is best-effort: if commit N fails, commits 1..N-1 are already in place; the operation aborts and tells you which one.
Checkout rule
git coherent checkout <ref> requires every member to have a clean working tree (so the switch can't fail mid-way). -b creates the branch in every member; if it already exists in some, those just switch.
No hooks, no enforcement
git-coherent doesn't install hooks or block plain git commit. Soloing a change in one repo is legitimate — that's why the marker is per-project and the trailer is the explicit signal of "this was part of a multi-repo change". Visibility comes from gitc status, not from blocks.
License
MIT.
