Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

git-tools

Git subcommands for curating the index by hand, so your commits stay focused enough to review, bisect, and blame.

Script Purpose
bin/git-addgrep Stage every change matching a regex, per-hunk when grepdiff is available.
bin/git-restage Refresh the staged copy of files you have already staged and then edited.
bin/git-post-fmt Stage only the files whose changes are formatting-only, so chore(fmt) lands separately.

The reasoning behind each one is in Commit like a librarian.. That article's code blocks are generated from this repository, so these files are the version to trust.

Install

Anything on your $PATH named git-foo is callable as git foo. Clone and symlink:

git clone https://github.com/photostructure/git-tools.git
ln -s "$PWD/git-tools/bin/git-addgrep" ~/.local/bin/git-addgrep
ln -s "$PWD/git-tools/bin/git-restage" ~/.local/bin/git-restage
ln -s "$PWD/git-tools/bin/git-post-fmt" ~/.local/bin/git-post-fmt

Copying the scripts works just as well. Each carries a # Source: header pointing back here, so a stray copy can always find the maintained one.

Usage

git addgrep

git addgrep oldFunctionName

Stages every hunk whose diff mentions the pattern. git diff -U0 emits zero-context hunks, grepdiff keeps the matching ones, and git apply --cached applies that filtered patch to the index.

Per-hunk staging needs grepdiff, from patchutils. The package is named patchutils for brew, apt, dnf, pacman, and apk alike. Without it, the script says so and falls back to staging whole files that match, via git diff -S/-G.

git restage

git restage

Re-stages the files that are already staged, and only those. Useful after a formatter, a deleted debug line, or one more test lands in files you had already staged.

It stages the whole file, so a partially-staged file loses its hunk selection.

git post-fmt

git post-fmt

Stages the files whose changes are formatting-only, so you can commit chore(fmt): apply prettier first and keep the next commit semantic.

For a file type with a mapped formatter, the test is exact: reformat both the HEAD version and the working copy, then compare. Matching canonical forms mean every difference between the two is something the formatter rewrites. Files with no mapped formatter fall back to a normalization heuristic that strips whitespace and shuffled punctuation, which can mask a precedence edit like (a+b)*c versus a+b*c — skim git diff --cached before committing those.

Add your own languages to the formatter_for table. Any formatter that reads stdin and writes stdout works; point it at the same binary your pre-commit hook and CI use, or "canonical" means something different in each place. The defaults cover Prettier, gofmt, rustfmt, black, shfmt, and clang-format.

The exact test costs two formatter runs per file, so checks fan out across cores with xargs -P and the survivors are staged in one batched git add. For a large Prettier repo, point the table at a resident daemon like prettierd to skip Node's startup cost on every file.

Development

make install-tools  # shellcheck and shfmt, via brew, apt, dnf, pacman, or apk
make precommit      # shellcheck + shfmt --diff, same as CI
make fmt            # shfmt -w -i 2

Related

photostructure/coding-skills is the plugin marketplace with the gitplan and stage skills, which teach a coding agent the same discipline.

License

MIT

About

git subcommands to keep commits clean: addgrep, restage, and post-fmt.

Topics

Resources

Stars

Watchers

Forks

Contributors

Languages