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

@makibm/gites

v1.4.0

Published

Two-track git workflow for batching and timing commits

Readme

gites

Two-track git workflow for batching and timing commits.

Batch your work session on a private branch backed up to your own remote. Ship commits to the live branch with hand-picked timestamps, one chunk at a time.

Install

npm install -g gites          # or: npx gites

Then in any repo:

gites

The TUI walks you through first-time setup (detects your origin, prompts for the URL of your private "gites" remote, installs a pre-push safety hook).

Prerequisites

  • Node 20+
  • git

Usage

gites                          # Open the TUI (default)
gites start-feature <name> [base]  # Create <name> + gites-<name> from origin/<base> (default main)
gites start-feature <name> --worktree  # ...in its own worktree under <repo>.worktrees/<name>
gites attach                   # Adopt the current origin branch as a gites feature
gites switch                   # Switch between features (prints the path for worktree ones)
gites change-base              # Re-parent the active feature onto a new base (PR chains)
gites ship                     # Cherry-pick commits with custom timestamps
gites resync                   # Pull origin and rebase working branches
gites cleanup                  # Prune finished features (local + backup only)
gites config                   # Change settings (prefix, worktrees, backup remote)
gites setup                    # Re-run first-time setup
gites help                     # Show help

Flags: -v / --verbose to surface raw git output.

Worktrees

Pass --worktree to start-feature (or answer "Own worktree?" in the TUI) to create the feature in its own git worktree at <repo>.worktrees/<name> instead of checking it out in place. Each feature then has its own folder, so you can have several checked out at once. switch prints the folder to cd into rather than moving your current checkout. Run git config gites.worktree true (or the setup wizard toggle) to make worktrees the default for new features.

Work-branch prefix

Work branches default to gites-<name>. To use a different prefix in a repo (e.g. you already have branches under another convention), set it per repo:

git config gites.workprefix wip-      # work branches become wip-<name>

The setup wizard and gites config also prompt for it. The value is read at runtime, so it also drives feature discovery and the pre-push block. Changing it via gites config offers to rename existing work branches (local + backup remote, never origin) to the new prefix.

Cleanup

gites cleanup prunes features whose PR is closed and whose branch is gone from origin. For each finished feature it removes the local live branch, the local work branch, the work branch on the backup remote, and its worktree. Origin is never touched. Detection uses gh (gh pr list --state closed), so the gh CLI must be installed and authenticated.

  • You confirm before anything is deleted and can opt out of branches to keep.
  • Anything with uncommitted changes (or a checked-out branch) is not auto-deleted; cleanup prints a copy-paste command to remove it manually.

Legacy gitpace repos

Repos set up with the older gitpace naming are detected on startup and can be adopted under gites in one step (mapping gitpace.* config to gites.*, keeping the gitpace- prefix and gitpace remote). Later, rename the prefix to gites- from gites config once the old branches are cleaned up.

The workflow

  • gites-<name> - your working branch. Pushed only to your private gites remote. Never reaches origin.
  • <name> - the live branch. Created locally at start-feature and not pushed to origin until your first ship, so branching a chain off a not-yet-published base leaks nothing. Commits arrive one ship at a time via the TUI, each with a custom timestamp.

You batch many small commits on gites-<name> during one session; later you run gites ship and pick the commit cutoff. The session starts at the last commit already on <name> (or the oldest staged commit on a first ship) and runs to now; both ends are editable with the arrow keys. Commits are then distributed within working hours 08:00-18:00. Those hours are defaults, not limits: every commit time can be hand-moved anywhere between 08:00 and 18:00 on any session day - the only hard rule is that nothing lands in the future. If the span covers several days you can mark days off (weekends are pre-disabled), and the chunk lands on <name> with timestamps.

PR chains (stacked branches)

You can branch a feature off another feature instead of main - pick the base in the "New feature" wizard (fuzzy type-to-filter over local + origin/* branches), or gites start-feature <name> <base>. The base is stored per feature and becomes the branch your PR should target.

Example:

  • 214 - epic, base main
  • 237 - base 214; PR targets 214
  • 238 - base 237 (keep working while 237 is in review); PR targets 237

When 237 is merged into 214, re-parent 238 with Change base (or gites change-base) and pick 214. Its PR now targets 214.

Avoiding conflicts

  • A child's PR target = its base. Set the base to the branch that will contain the parent's work after merge.
  • Prefer merge/rebase-merge over squash for a parent that has children. A merge or rebase-merge preserves the parent's commits as the same SHAs, so the child's rebase treats them as already applied - a true no-op, trivially clean. Squash rewrites history, which is what forces the --onto dance below. Reserve squash for leaf/standalone PRs.
  • After a squash-merge, use change-base - not a plain rebase. A plain git rebase origin/<grandparent> (or git merge) re-applies every one of the parent's individual commits (still present in the child) on top of a base that already contains them squashed - every commit conflicts. change-base runs git rebase --onto origin/<newBase> origin/<oldBase> <child>, replaying only the child's own commits, so the parent's commits are never re-applied. This eliminates the duplicate-commit avalanche. It does not eliminate genuine conflicts: if your own commits touch the same lines the squash changed (or the squash author applied review edits), you still resolve those - but they're the normal, minimal kind.
  • Rebase only your own un-reviewed work. Re-parenting a live branch that is already under review force-pushes it (--force-with-lease); tell reviewers to re-pull.
  • Keep chains short. Land parents before stacking deeper.

Demo mode

To play with the TUI on fake data without touching any real repo:

npm run demo            # pick a scenario, then drop into the TUI
npm run demo -- active  # jump straight to a seeded scenario
npm run demo:reset      # wipe the demo sandbox

Scenarios: fresh (run setup wizard), ready, active (commits ready to ship), multi (multiple features for switch), teammate (origin moved ahead for resync), attachable (existing origin branch for attach).

The sandbox lives at $TMPDIR/gites-demo/ - entirely outside your repo.

What gites writes to your clone (local only)

  • Adds a gites remote (your private repo for the gites-* work branches)
  • Installs a pre-push hook in .git/hooks/pre-push (or your core.hooksPath if set) - blocks gites-* branches from ever reaching origin. An existing pre-push hook is backed up to pre-push.pre-gites.
  • Sets a few configs in gites.* namespace (origin, remote, branch)

That's it. core.hooksPath, remote.pushDefault, and aliases are never touched - you can use the repo normally outside gites. Branches created by gites have proper per-branch upstreams (<feature> → origin, gites-<feature> → gites), so git push from any branch goes where you'd expect.

None of this touches origin or anyone else who pulls from it.

Gotchas

  • The hook is per-clone. Re-run setup after cloning on a new machine (the TUI detects this automatically).
  • Don't rebase the origin branch after it has been reviewed. Use git merge main instead.
  • The pre-push hook is your safety net - blocks gites-* branches from reaching origin.
  • Cherry-pick conflicts are caught and the script stops with recovery instructions instead of silently failing.

License

MIT