Skip to content

Repository files navigation

git-fi

A git plugin that maintains a temporary integration branch named fi. Merge multiple in-progress feature branches together to detect conflicts early and test features in collaboration — before they land on main.

Documentation & install | Specification

This README is for working on git-fi itself. To install and use it, see the documentation site.

Local development

Requires Node.js >= 22 and git >= 2.13.0.

The Node floor is the engines field in package.json, and it tracks active LTS: 22 is the oldest line still supported upstream, and CI runs both LTS lines plus Current. Raising it means moving engines and the CI matrix together.

The git floor tracks the newest git feature the code calls rather than a support policy. Today that feature is git branch -r --format=, which backs the batched branch listing (PERF-01) and which git gained in 2.13.0; every other invocation is older. Reaching for a newer git feature means raising the floor in PRE-02 and src/git.ts together, and naming the feature that moved it so the next person doesn't have to re-derive the number.

git clone https://github.com/gettyimages/git-fi.git
cd git-fi
npm install                 # dev dependencies (tsx, typescript)

Day-to-day, git-fi runs straight from source — no global install needed:

npm start -- --help         # run src/ directly via tsx
npm run build               # compile TypeScript to dist/
npm test                    # build, then run the integration suite

With just installed, just lists the same tasks under shorter names — just run --help, just build, just test. The recipes delegate to the npm scripts rather than restating them, so package.json stays the one place a command is defined; CI and prepublishOnly call npm directly either way.

npm test is the primary feedback loop: it drives the compiled binary against throwaway git repositories (a bare origin plus a working clone), exercising real git fetch/merge/push behavior end-to-end. scripts/run-tests.mjs hands node's runner explicit paths rather than a glob, so a pattern that stops matching fails loudly instead of reporting a green suite that ran nothing.

CI runs the suite on Linux and Windows across Node 22, 24, and 26 — both active LTS lines plus Current. Windows is in the matrix because git-fi behaves differently where the platform has no POSIX file modes: it stores the token without setting or checking 0600 (AUTH-04), and --update has to reach npm through the shell there (UPDATE-05).

When something is slow, --debug traces every git command with its elapsed time (OPTION-11) — which is how the fetch's --no-tags came about (PRE-04). How much that flag saves depends on the server, so measure with --debug in the repository in question rather than assuming.

The implementation follows SPEC.md, which defines every requirement with a unique ID and includes mermaid diagrams for the major flows.

Trying your local build

To run the checkout as git fi in other repositories for a while:

npm run trial:on            # build, npm link, load this copy's completion
npm run trial:off           # unlink, restore the published version

trial:on symlinks the checkout onto your PATH, so later npm run builds take effect without reinstalling. It also runs install-completions --write .trial/completions and appends a marked block to ~/.zshrc that puts that directory on your fpath — the same command, writing the same two files, that a user installs with (COMPLETE-06), so a trial exercises the shipped install path rather than a shortcut around it. Only ~/.zshrc is touched; under bash you get the linked binary and wire the completion yourself. trial:off deletes the block and .trial/, then reinstalls @gettyimages/git-fi from npm. Open a new terminal after either one.

If git fi runs something other than what you expect, which -a git-fi lists every git-fi on your PATH in resolution order.

The published package — npm install -g @gettyimages/git-fi, documented on the docs site — is the official install for end users. Reach for it here mainly to test the distribution itself; local development runs from source.

Project Structure

SPEC.md        Behavioral specification
STATUS.md      Requirement coverage
justfile       Task runner wrapping the npm scripts
src/           TypeScript implementation
test/          Integration suite (Node test runner)
docs/          Docsify documentation site
scripts/       Build-time generators, the npm postinstall, the trial:on/off helper
man/           Generated man page (git-fi.1)
completions/   Generated bash + zsh completions (_git-fi, _git_fi, git-fi.bash)

The man page and shell completions are generated by scripts/gen-docs.ts, which draws the flag list from src/help.ts — the single source of truth for git-fi's flags. The completion logic itself lives in real shell files under scripts/completion/ (*.tmpl); the generator injects the flag list and stamps a banner. npm run build regenerates the outputs (via npm run gen:docs); those under man/ and completions/ are committed, so edit src/help.ts (flags) or scripts/completion/*.tmpl (completion logic) and rebuild rather than editing the generated files by hand. npm test and CI both run npm run verify:generated, which fails naming any committed artifact that no longer matches what the generator would write, so stale generated files surface before review rather than during it.

Three completion files ship because git fi is dispatched by two different providers: _git-fi drives zsh's built-in _git; git-fi.bash (defining _git_fi, git-completion style) drives git's own completion wrapper in bash; and _git_fi is the same _git_fi body on the zsh fpath, for git's wrapper under zsh. The git-native body (git-fi.bash.tmpl) is shared by the last two, so they can't drift. Each file has an install-completions target that prints it — bash, zsh, zsh-git respectively — and --write <dir> installs the zsh pair onto an fpath directory (COMPLETE-06); adding a file here means adding its target in src/install-completions.ts.

A global npm install copies the zsh pair into <npm prefix>/share/zsh/site-functions from scripts/postinstall.mjs (COMPLETE-07), so completion works with no extra step on the setups that carry that directory on their fpath. It's plain .mjs and lists the two filenames itself because npm runs postinstall before prepare, so dist/ doesn't exist yet on a fresh clone; a test pins its file list to what --write installs. It exits 0 on any failure — a non-zero postinstall fails npm install -g outright — and does nothing for a local install.

Contributing

Bug reports and pull requests are welcome on GitHub.

License

MIT — Copyright (c) 2017-2026 Getty Images.

Releases

Used by

Contributors

Languages