npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

patchy-cli

v0.0.27

Published

A CLI tool for managing Git patch workflows.

Readme

Patchy 🩹

A CLI for generating and applying patches to git repositories.

Why Patchy?

For long-lived git forks with no plans to merge upstream:

  • A git fork stores your changes as commits.
  • Patches store them as .diff

Patch files are a clean way to store long-lived changes - human-readable, easy to review and version. But managing them can be cumbersome.

Patchy makes managing patches easy: make changes to a clone → save them as patches → reapply anytime.

How it works

patchy init sets up your project:

├── patchy.json              ← config (source: github.com/org/repo, base: v2.1.0)
├── clones/
│   └── upstream-repo/       ← a clone of the source repo - your working copy
└── patches/                 ← empty for now - your patches live here

The workflow:

  1. Make changes directly in clones/upstream-repo/
  2. Run patchy generate to generate patches:
patches/
└── 001-feature-name/
    ├── src/file.ts.diff     ← edits to existing files
    └── src/newFile.ts       ← new files (no .diff suffix)
  1. Run patchy apply to reapply your patches to clones/upstream-repo/ anytime

See the example walkthrough for a step-by-step guide.

Getting started

Installation

curl -fsSL https://raw.githubusercontent.com/richardgill/patchy/main/install | bash
# follow instructions
patchy

Or via npm:

npm install -g patchy-cli
patchy

Or use directly without installing:

npx patchy-cli@latest

Initialize Patchy

Run this command to initialize Patchy in your project folder:

patchy init

patchy.json reference

{
  // Git URL or local file path to clone from.
  "source_repo": "https://github.com/example/repo.git", // Override: --source-repo | env: PATCHY_SOURCE_REPO
  // Directory containing patch files.
  "patches_dir": "./patches/", // Override: --patches-dir | env: PATCHY_PATCHES_DIR

  // Default directory for cloning repos.
  "clones_dir": "./clones/", // Override: --clones-dir | env: PATCHY_CLONES_DIR

  // Path to repo you're generating patches from or applying patches to.
  // Can be relative to clones_dir: <clones_dir>/<target_repo> or absolute.
  "target_repo": "repo", // Override: --target-repo | env: PATCHY_TARGET_REPO

  // Patch set to generate into (subdirectory of patches_dir).
  // If not set, prompts interactively or errors in non-interactive mode.
  "patch_set": "001-security-fixes", // Override: --patch-set | env: PATCHY_PATCH_SET

  // Git SHA or tag to use as the base for patches.
  "base_revision": "abc123def", // Override: --base-revision | env: PATCHY_BASE_REVISION

  // Remote branch to track for updates (e.g., "main"). Used by `patchy base` to find new commits/tags.
  "upstream_branch": "main" // Override: --upstream-branch | env: PATCHY_UPSTREAM_BRANCH
}

Precedence: CLI flags > Environment variables > patchy.json

patchy.json uses jsonc, so comments are allowed.

Patch file layout

Patches are stored in the patches/ directory (customizable via patches_dir):

./
├── patches/
│   └── 001-first-patch-set/
│       ├── path/to/existingFile.txt.diff
│       └── path/to/newFile.txt
├── clones/
│   └── repo-clone-1/
│       ├── path/to/existingFile.txt (modified)
│       └── path/to/newFile.txt (added)
└── patchy.json

Patches are grouped into patch sets for organizing related changes. Patch sets have numeric prefixes (e.g., 001-auth, 002-ui) and are applied in order.

Within each patch set files follow the same folder structure as in the source_repo.

Two types of patch files:

  • .diff files — For modified existing files (generated via git diff HEAD)
  • Plain files — For newly added files (copied verbatim for easier inspection and editing)

patchy generate automatically removes stale files in patches/<patch-set> that no longer correspond to changes in target_repo.

Hooks

Patch sets can include executable scripts that run before and after patches are applied:

patches/
└── 001-add-feature/
    ├── patchy-pre-apply   # runs before patches
    ├── src/file.ts.diff
    ├── src/new-file.ts
    └── patchy-post-apply  # runs after patches

Patch sets support scripts without diffs, enabling pure automation steps.

Hook execution

  • Hooks run with cwd set to target_repo
  • Environment variables: PATCHY_TARGET_REPO, PATCHY_PATCH_SET, PATCHY_PATCHES_DIR, PATCHY_PATCH_SET_DIR, PATCHY_BASE_REVISION
  • Non-zero exit aborts patchy apply
  • Hooks must be executable (chmod +x)

Custom hook prefix

{
  "hook_prefix": "my-prefix-"  // Override: --hook-prefix | env: PATCHY_HOOK_PREFIX
}

With prefix my-prefix-, hooks are named my-prefix-pre-apply and my-prefix-post-apply.

Commands

patchy generate

Generate .diff files and new files into ./patches/<patch-set>/ based on current git diff in target_repo.

patchy generate [--patch-set] [--target-repo] [--patches-dir] [--dry-run]

If --patch-set is not provided (and not set via env/config), prompts to select an existing patch set or create a new one.

Note: patchy generate is destructive and will remove any unneeded files in the patch set directory.


patchy apply

Apply patch files from patches/ into target_repo. Patch sets are applied in alphabetical order.

patchy apply [--only <patch-set>] [--until <patch-set>] [--auto-commit=<mode>] [--on-conflict=<mode>] [--target-repo] [--patches-dir] [--dry-run]

| Flag | Description | |------|-------------| | --only <name> | Apply only the specified patch set | | --until <name> | Apply patch sets up to and including the specified one | | --auto-commit=<mode> | Control auto-commit behavior (see below) | | --on-conflict=<mode> | How to handle patches that fail to apply (see below) |

Conflict handling

When a patch doesn't apply cleanly (e.g., the upstream file changed), patchy can insert git-style conflict markers for manual resolution.

| Mode | Behavior | |------|----------| | markers (default) | Insert conflict markers and continue | | error | Fail immediately (previous behavior) |

Resolving conflicts:

When conflicts occur, patchy outputs instructions:

✗ Applied patches with conflicts to clones/my-repo

To resolve:
  1. Edit files in clones/my-repo to resolve conflicts (remove conflict markers)
  2. Run: patchy generate --patch-set 001-fix
  3. Commit the updated patches

Conflict markers look like standard git merge conflicts:

<<<<<<< current
const value = 999;
=======
const value = 42;
>>>>>>> file.ts.diff

Edit the file to keep the correct code, remove the marker lines, then regenerate the patch.

Auto-commit behavior

Each patch set creates a single commit with message Apply patch set: <name>. The --auto-commit flag controls when commits happen:

| Mode | Behavior | |------|----------| | interactive (default) | Commits all patch sets automatically, prompts for the last one | | all | Commits every patch set immediately after applying | | skip-last | Commits all except the last patch set | | off | No commits are made |

Notes:

  • In non-interactive environments (e.g., CI), interactive mode auto-commits everything
  • Commits are skipped if any patch in the set fails to apply
  • --dry-run skips all commits

patchy repo reset

Hard reset the Git working tree of target_repo to base_revision. Discards all local changes and patch commits.

patchy repo reset [--base-revision] [--target-repo]

patchy repo clone

Clone a repository into a subdirectory of clones_dir and checkout base_revision. The target directory is derived from the repo name.

patchy repo clone [--source-repo] [--clones-dir] [--base-revision] [--yes]

Use --yes to skip confirmation prompts and automatically update patchy.json with the new target directory.


patchy base [revision]

View or update the base_revision in config.

patchy base              # Interactive
patchy base abc123def    # Set base_revision to the specified SHA or tag

patchy prime

Prints a prompt you can include in your AGENTS.md / CLAUDE.md.

Tell your agent to run:

patchy prime

Or include it directly:

patchy prime >> CLAUDE.md

Outputs a brief description of Patchy, key paths, and essential commands to help AI coding agents understand your project's patch workflow.


patchy config get <key>

Output a single config value (raw, no label). Useful for shell scripts.

patchy config get target_repo_path    # /home/user/project/clones/my-repo
patchy config get patch_set           # 001-feature
patchy config get verbose             # false

Available keys:

| Key | Description | |-----|-------------| | source_repo | Git URL or local file path | | target_repo | Repository name or path | | clones_dir | Directory for clones | | patches_dir | Directory for patches | | patch_set | Current patch set name | | base_revision | Base SHA or tag | | upstream_branch | Remote branch to track | | hook_prefix | Hook script prefix | | verbose | Verbose mode ("true"/"false") | | clones_dir_path | Absolute path to clones directory | | target_repo_path | Absolute path to target repository | | patches_dir_path | Absolute path to patches directory | | patch_set_path | Absolute path to current patch set |

  • Unknown keys exit with code 1
  • Unset raw keys exit with code 1
  • Unset computed keys (e.g., patch_set_path when patch_set is not set) output an empty line

patchy config list

Output all config values as aligned key-value pairs.

patchy config list
# source_repo       https://github.com/example/repo.git
# target_repo       my-repo
# clones_dir        ./clones
# patches_dir       ./patches
# patch_set         001-feature
# verbose           false
# clones_dir_path   /home/user/project/clones
# target_repo_path  /home/user/project/clones/my-repo
# ...

Only defined values are shown. Computed path values are resolved to absolute paths.

License

MIT