Skip to content

barelyhuman/git-tree-state

Repository files navigation

git-tree-state

Incremental git file status for a repository. Performs one full git status snapshot at startup, then keeps a cached per-file map in sync via filesystem events and scoped porcelain refreshes.

Install

npm install git-tree-state

One-shot APIs

import { getRepoGitState, getFileGitState } from 'git-tree-state';

const allDirty = await getRepoGitState('/path/to/repo');
const oneFile = await getFileGitState('/path/to/repo', 'src/app.ts');

Watcher API

Filesystem events are dirty hints only. The watcher debounces changed paths, runs scoped git status --porcelain=v2 -z -- <paths>, compares against the cache, and emits change only when the computed git state actually changes. Git metadata (index, HEAD, refs) is watched separately, so commands like git add, git commit, git reset, and checkout also trigger semantic updates.

import { createGitStateWatcher } from 'git-tree-state';

const watcher = await createGitStateWatcher('/path/to/repo', {
  debounceMs: 100,
  ignored: ['**/dist/**'],
});

console.log(watcher.getState());

const unsubscribe = watcher.on('change', (changes) => {
  for (const change of changes) {
    console.log(change.path, change.previous, '->', change.current);
  }
});

// Force a resync if watcher events may have been dropped:
await watcher.refresh();

await watcher.close();
unsubscribe();

Performance model

Operation Cost
Startup One full git status --porcelain=v2 -z
File edit Debounced batch of scoped status calls for dirty paths only
Git metadata change (git add, commit, reset, checkout) Debounced full status refresh
Listener Fires only on semantic GitState transitions (including dirty → clean)

Use refresh() to force a resync after missed watcher events or external operations you do not trust the watcher to catch.

Types

type GitState = {
  status:
    | 'added'
    | 'modified'
    | 'deleted'
    | 'renamed'
    | 'copied'
    | 'unknown';
  staged: boolean;
  unstaged: boolean;
  path: string;
  oldPath?: string;
};

type GitStateChange = {
  path: string;
  previous?: GitState;
  current?: GitState;
};

Simulation harness

For scenario-style tests and local inspection, use the test-support simulation harness in src/test-support/simulator.ts. It runs real git and filesystem operations against createGitStateWatcher() and renders a terminal tree with per-file git state badges.

npm test -- src/simulation.test.ts
npm run simulate

Set GIT_TREE_STATE_SIM_PRINT=1 to print tree snapshots after each step (npm run simulate enables this automatically).

Development

npm install
npm test
npm run build
npm run simulate

CI and release

CI

Every push and pull request to main runs .github/workflows/ci.yml: npm ci, build, and test on Node 20 and 22.

Release (manual staged publish)

Releases are triggered manually via .github/workflows/release.yml using npm staged publishing.

1. Start the workflow

In GitHub: Actions → Release → Run workflow, enter the version (e.g. 1.2.3 or 1.2.3-beta.1 — no v prefix).

The workflow will:

  1. Run tests on Node 22
  2. Set package.json version to the input you provided
  3. Build the package
  4. Run npm stage publish (uploads to npm’s staging queue; not installable yet)

2. Approve on npm

A maintainer with 2FA must approve before the version goes live:

  • npmjs.com → package → Staged Packages → Approve, or
  • npm stage approve git-tree-state@<version>

Prerequisites

Requirement Notes
Trusted publishing Configure on npm for this repo/workflow; use stage-only so CI can npm stage publish but not npm publish
npm CLI ≥ 11.15.0 Release job upgrades npm globally before staging
Node ≥ 22.14.0 Release job uses Node 22
Package on registry Staging requires an existing package; publish 0.1.0 manually once if needed
2FA on npm Required for the approval step (CI cannot approve)

Provenance

The release workflow sets id-token: write for OIDC. With trusted publishing configured on npm, provenance attestations are generated automatically when staging — no NPM_TOKEN or --provenance flag in the workflow.

Releases

No releases published

Packages

 
 
 

Contributors