ghq for the files git shouldn't see: externalize any git-ignored path to storage you already sync, never to git. A capture tool, not a config-distribution tool.
ihq ("ignored headquarters") moves git-ignored files and directories out of a
checkout into a store kept outside git, leaving a symlink behind. While working
in a repo (often with an AI agent) you accumulate notes, scratch, .env files,
and artifacts you want beside the code but never committed, not for the team and
not on GitHub. ihq keeps them in a store whose path is derived from the repo's
identity, the same way ghq derives a checkout
path from a remote URL.
Two planes:
- The store is
$IHQ_ROOT/<host>/<user>/<repo>/: a mirror tree holding your externalized paths, each at its own repo-relative location. Lives in your synced folder, shared across machines. Each managed directory carries an empty.ihqdirmarker, so the managed set is derived by scanning the store with no separate index to keep in sync. - The links are the
ihqsymlinks plus their.git/info/excludeentries. Per-checkout and per-machine, never committed.
ihq migrate externalizes a path on the first machine; ihq link re-attaches it
on every other.
ihq does not sync. Point the root at a folder something already syncs (Dropbox,
iCloud, Syncthing, a NAS mount) and backup comes for free.
pip install ihqOr with uv:
uv tool install ihqRequires POSIX (macOS, Linux); it relies on symlinks.
ihq migrate <path> moves an existing file or directory into the store and drops
a symlink in its place, added to .git/info/exclude so git never sees it:
$ echo "scratch notes" > scratch.md
$ ihq migrate scratch.md
linked /home/you/code/labelme/scratch.md -> /home/you/ihq/github.com/wkentaro/labelme/scratch.mdThe path keeps working in place; its bytes now live in your synced store. Nested
paths work too (ihq migrate backend/.env). The path must not be tracked by git:
externalizing a committed file would change it for the whole team, so ihq
refuses.
migrate only moves content that already exists. To start something fresh,
create it first, then migrate. ihq detects the type from disk, so use touch
for a file or mkdir for a directory:
$ touch .env && ihq migrate .env
$ mkdir notes && ihq migrate notesThe store syncs over, so other checkouts just re-attach. ihq link with no
argument links every path the store has but this checkout does not:
$ ihq link
linked /home/you/code/labelme/scratch.md -> /home/you/ihq/github.com/wkentaro/labelme/scratch.md
linked /home/you/code/labelme/notes -> /home/you/ihq/github.com/wkentaro/labelme/notesOr link one path: ihq link scratch.md. link never creates store content; if
the store does not have the path it errors (run ihq migrate first). This is the
guard that catches a typo'd remote or an un-synced store instead of producing
junk.
ihq unlink <path> removes one symlink and its exclude entry; ihq unlink --all
does every path on this checkout. It never touches the store, so your content
stays safe in the synced root:
$ ihq unlink scratch.md
unlinked /home/you/code/labelme/scratch.mdihq list shows every managed path for this repo and its status on this
checkout, the same wherever in the repo you run it. * is linked here, a space
is in the store but not linked here, ! is a link here whose store slot is gone.
Read-only:
$ ihq list
* scratch.md /home/you/ihq/github.com/wkentaro/labelme/scratch.md
backend/.env /home/you/ihq/github.com/wkentaro/labelme/backend/.envThe root is resolved like ghq, in order:
IHQ_ROOT env -> git config ihq.root -> ~/ihq
ihq root prints it, the same way ghq root does. It needs no repo, so it works
anywhere:
$ ihq root
/home/you/ihq
$ cd "$(ihq root)"repoverlay uses the same mechanism
(a symlink plus .git/info/exclude) but the opposite data model. It distributes
one shared bundle of files into many repos; ihq captures each repo's own unique
git-ignored paths out to a synced store.
- Capture, not distribute: content flows out of the repo, not config in.
- Zero config: the store path is derived from repo identity, not named.
- Few verbs:
migrate,link, andunlinkare all that change anything;rootandlistonly print.
ihq manages links and the derived store; it never syncs, clones, or touches the
network. Backup is delegated entirely to whatever already syncs your root.
MIT. Modeled on and crediting ghq.