Hand-rolled setup
80+ lines of git init → writeFile → commit per test. Drift between tests is inevitable.
npm install --save-dev @gfargo/git-scenarios simple-gitEvery git tool — TUIs, IDEs, CLIs, linters — behaves differently against different repo states. Testing those behaviors means:
Hand-rolled setup
80+ lines of git init → writeFile → commit per test. Drift between tests is inevitable.
Checked-in fixtures
Real .git directories in your repo. Bloats the tree, breaks on updates, no programmatic access.
Mocking git
Tests verify “my code called the right command” — not “my code does the right thing in this state.”
Docker containers
Pre-baked images with git state. Heavy, slow, CI-only. Not interactive-test-friendly.
@gfargo/git-scenarios gives you real git repos in any state with one line of code:
import { spinUpScenario } from '@gfargo/git-scenarios'
// One line — real repo, real refs, real worktreeconst repo = await spinUpScenario('mid-merge-conflict')// repo is mid-merge with src/widget.ts conflicted, MERGE_HEAD setOr compose your own state from atoms:
import { chain, addCommit, switchToBranch, startMerge, createTempGitRepo } from '@gfargo/git-scenarios'
const repo = await createTempGitRepo()await chain( addCommit({ message: 'base', files: { 'x.ts': 'base\n' } }), switchToBranch('feat/theirs'), addCommit({ message: 'theirs', files: { 'x.ts': 'theirs\n' } }), switchToBranch('main'), addCommit({ message: 'ours', files: { 'x.ts': 'ours\n' } }), startMerge('feat/theirs'),)(repo)27 curated scenarios
Branch states, merge/rebase/cherry-pick/revert conflicts, bisect, stash, worktrees, submodules, shallow clones, large histories. All deterministic. Browse all →
50+ composable atoms
Build any git state from small, typed building blocks. chain() them together. Write your own — they’re just functions. Atom reference →
Jest adapter
describeWithScenario('name', (getRepo) => { ... }) — zero-boilerplate test setup with automatic cleanup. Setup guide →
Tool-agnostic CLI
npx git-scenarios create mid-merge-conflict --run "lazygit" — materialize any scenario and launch your tool against it. CLI docs →
Custom registration
registerScenario(myScenario) — your custom scenarios work with spinUpScenario, fromScenario, and the CLI. Learn more →
Dual CJS/ESM
Ships both formats. Use import or require — both work. TypeScript-first with full type declarations. Install →
# Spin up a merge conflict, launch lazygit against itnpx git-scenarios create mid-merge-conflict --run "lazygit"
# List all 27 scenariosnpx git-scenarios list
# Describe a specific scenario's contractsnpx git-scenarios describe feature-pr-readyOriginally extracted from coco, an AI-powered git CLI/TUI with 16 specialized views. Every view needed deterministic git states to test against. After writing the same git init + writeFile + commit setup 47 times, the scenario library was born.
Now it’s a standalone package for anyone building git tools — TUIs, IDE extensions, CLI utilities, linters, formatters, or anything that reads repo state.
Read the docs
Browse scenarios
Atom reference
Source code