# git-rewrite-commits: rewriting a commit history with a local or remote model

> A small TypeScript CLI that feeds each commit diff to an AI provider and rewrites the message in conventional commit style, with opt-in hooks and a dry-run mode. The hard part is not the generation, it is the force-push.

**f/git-rewrite-commits** — AI-powered git commit message rewriter using Ollama or GPT

- Repository: https://github.com/f/git-rewrite-commits
- Website: https://blog.fka.dev/git-rewrite-commits/
- Stars: 1,422 · Forks: 59
- Language: TypeScript
- License: MIT
- Published: 2026-10-06 · Updated: 2026-10-06 · Language: en
- Canonical page: https://hysenlabs.com/projects/f-git-rewrite-commits

## Running it without installing anything

The project publishes two names to npm, the full `git-rewrite-commits` and the short alias `grec`, and both work identically. Nothing needs installing for a first run:

```bash
npx git-rewrite-commits
# or shorter:
npx grec
```

Global installation is the obvious pair of npm installs, and the README is explicit that the two names are the same tool rather than a wrapper around it:

```bash
# Full command name
npm install -g git-rewrite-commits

# Or install the short alias (grec = git-rewrite-commits)
npm install -g grec
```

The package manifest describes a plain ESM TypeScript project: `"type": "module"`, a single bin entry at `dist/cli.js`, a build step of `tsc`, and Node 16 as the declared floor. The published `files` array is `dist/**/*`, `hooks/**/*`, `README.md`, `QUICK_START.md` and `LICENSE`, so the hooks ship with the package rather than being fetched at runtime. The runtime dependencies are few and legible: the `openai` client, `commander` for argument parsing, `chalk` for coloured output, `ora` for the progress spinner the feature list mentions, and `node-fetch`.

One detail in the manifest deserves to be flagged rather than buried: the test script is `echo "Error: no test specified" && exit 1`. There is no test suite in this repository. For a tool that rewrites git history, that is the single most important fact on this page.

## The disclaimer, and the four situations it names

The README puts an Important Disclaimer immediately after the title, before any feature list, and it is unusually blunt about it. This tool rewrites git history, which is generally not recommended for shared repositories.

It then separates the acceptable cases from the unacceptable ones, which is more useful than a blanket warning. Use it on personal projects before making them public, on feature branches before merging with team agreement, when cleaning local commits before pushing, and when preparing a repository for open sourcing. Do not use it on shared branches without team coordination, after pushing commits that others have pulled, on the main or master branch of a team project, or in any repository where commit hashes are referenced.

That last exclusion is the one that bites hardest, because hashes end up referenced in all sorts of places that are easy to forget: review comments that reference a specific commit, pull request descriptions, release notes, CI systems that pin a SHA, and internal documentation written by other people. None of those break loudly. They break as links that resolve to nothing, or worse, as a build that pulls a different tree than the one that was tested.

The final line of the disclaimer is the part to memorise: rewriting history changes commit hashes and requires force-pushing, which can disrupt your team's workflow. That is a fact about Git rather than about this tool, and no amount of quality in the generated messages changes it.

## Choosing between OpenAI and a local Ollama model

The README is direct about what leaves your machine. When you use remote providers such as OpenAI, the tool sends your file lists and diffs to external APIs. That is the whole privacy question, stated in one sentence, and the answer is that your code goes to a third party.

The local path uses Ollama, and the configuration is a git config key rather than a CLI flag, which means it lives in the repository or in your global git config:

```bash
# Use local Ollama instead of remote APIs
git config hooks.commitProvider ollama
git config hooks.providerModel gemma3

ollama pull gemma3
ollama serve
```

The provider can also point at a remote Ollama server on your own network, through `OLLAMA_URL` in the environment or `hooks.ollamaUrl` in git config, with the example given being `http://192.168.1.100:11434`. The model name is configurable too, and the README mentions gpt-4, gpt-3.5-turbo and llama3.2 as examples of what you might select.

Alongside the provider choice, the README lists the security features that ship with the tool: explicit consent required before sending data to a remote provider, automatic redaction of API keys, passwords and private keys, an opt-in model for hooks, secure argument handling described as protection against shell injection, and always creating backups before a rewrite. The redaction and the consent prompt are the two that matter most in practice, since they are the difference between a leak and a near miss. The full treatment is in SECURITY.md at the repository root.

## Hooks are opt-in, which is the correct default

The hook installation is a three-step sequence, and the middle step is the interesting one. Step one installs or updates the hooks:

```bash
npx git-rewrite-commits --install-hooks
```

Step two is where the design decision shows. Each hook is disabled until you enable it with git config, so installing the hooks does not by itself send anything anywhere:

```bash
# Option A: Enable message preview before commit
git config hooks.preCommitPreview true

# Option B: Enable automatic message generation
git config hooks.prepareCommitMsg true
```

Step three sets the provider, as covered above. The README also notes that installing updates existing hooks, and that hooks not belonging to this tool are backed up before replacement, which is a courtesy that prevents silently overwriting something a developer wrote.

The two hooks do different things and the distinction is a reasonable one. A preview hook shows a generated message before the commit is created, which keeps a human in the loop. A prepare-commit-msg hook generates the message automatically, which is the convenience mode and the one where a bad model produces bad history at speed. Enabling only the preview first is the cautious order, and the README presents them as options rather than insisting on both.

There is also a compact one-liner form that combines staging, generation and committing, which is the shape most people will end up using:

```bash
git add -A
git commit -m "$(npx -y grec --quiet --staged --skip-remote-consent)"
```

The `--skip-remote-consent` flag deserves attention. It suppresses the prompt that normally asks before sending data to a remote provider, which is exactly what you want in a scripted context and exactly what you do not want if you have not already decided where your code goes.

## Shaping the output with flags, templates and COMMIT_MESSAGE.md

The feature list is long, and the useful parts cluster into three groups. The first is control over scope: `--max-commits` processes only the last N commits, `--dry-run` previews without applying, and `--prompt` overrides the AI behaviour with your own prompt text. Dry-run is the one to reach for first, because the whole tool is a destructive operation and a preview is cheap.

The second group is formatting. `hooks.commitTemplate` sets a format string such as `"[JIRA-XXX] feat: message"`, `hooks.commitLanguage` sets the output language with Spanish given as the example, and `hooks.providerModel` selects a specific model. Conventional commit prefixes are the default style, and the README lists multi-language generation as a supported feature rather than an accident.

The third group is project context, and this is the most interesting mechanism in the tool. You can write project-specific guidelines in a file named `COMMIT_MESSAGE.md`, and the tool searches three locations in order: the project root as `./COMMIT_MESSAGE.md`, the git directory as `./.git/COMMIT_MESSAGE.md`, and the GitHub directory as `./.github/COMMIT_MESSAGE.md`. The repository ships `COMMIT_MESSAGE.md.example` as a starting point. A file in `.github/` is a nice choice for a team, since it is already tracked and already something contributors read.

The README also lists smart filtering that skips commits already well formed, and a quality scoring feature that identifies commits needing improvement. Both are sensible ways to limit the blast radius: rather than rewriting everything, rewrite only what a heuristic says is wrong.

## Where this tool is the wrong choice

The limitations here are not subtle, which is a credit to the README, but they are worth restating as decisions rather than warnings.

There is no test suite. The manifest's test script is the npm placeholder that exits with an error, so the code that assembles diffs, calls a model and replays a rewritten history has no automated coverage in this repository. That does not mean the tool is unreliable, and the dry-run mode plus automatic backups are sensible mitigations, but it does mean you are trusting the rewrite path on your own repository first.

There is also no undo beyond Git. The README promises automatic backup branches, which is the right mechanism, but a backup branch is only helpful if you know it exists and what it is called. Combined with a missing test suite, the honest position is that you should run this on a repository you can restore from a remote, not one you cannot.

The deeper limitation is conceptual. This improves the labels on commits; it does not improve the commits. Conventional commit format makes history readable, and readable history is genuinely valuable, but a repository restructured by an AI will still contain the same design decisions that produced the messy original. For teams, the alternative worth comparing is enforcing format at review time with commitlint plus a hook, which costs no force-push and no privacy decision. git-rewrite-commits wins when the history is already written and you want it retroactively labelled; commitlint wins when you want it labelled from the start.

## Conclusion

git-rewrite-commits is a good fit for a personal repository you are about to publish, or a feature branch you have not shared, and a bad fit for any branch other people have pulled. Its own disclaimer says so, listing shared branches, already-pushed commits and any repository where commit hashes are referenced as places not to use it. The specific first step is the dry-run mode the README lists among its features, because the dry run shows exactly which commits the tool would touch without touching them, and it also tells you whether the generated messages are worth a force-push. If you plan to use the hooks, set `hooks.commitProvider ollama` before enabling anything, so nothing leaves the machine.

## FAQ

### Does git-rewrite-commits send my code to OpenAI?

It does if you configure it to. The README states that when using remote providers such as OpenAI, the tool sends your file lists and diffs to external APIs, and it lists explicit consent before sending as one of its security features. Setting git config hooks.commitProvider ollama switches to a local model instead, where nothing leaves the machine.

### Can I use git-rewrite-commits on a branch other people have pulled?

No. The README lists after pushing commits that others have pulled under the heading of when NOT to use the tool, along with shared branches without team coordination and the main or master branch of a team project. Rewriting history changes commit hashes and requires force-pushing, which is why the README reserves it for personal projects, unpublished branches and repositories being prepared for open sourcing.

### How do I preview changes before git-rewrite-commits rewrites anything?

Use the dry-run mode listed in the features, which previews changes before applying them. The verbose mode adds a diff preview and detailed processing information, and --max-commits limits processing to the last N commits, so you can scope a trial to a handful of recent changes before anything is rewritten.

### How do I set a project-specific commit message format in git-rewrite-commits?

Write guidelines in a file named COMMIT_MESSAGE.md and the tool will find it in one of three places, searched in order: ./COMMIT_MESSAGE.md in the project root, ./.git/COMMIT_MESSAGE.md in the git directory, and ./.github/COMMIT_MESSAGE.md in the GitHub directory. The repository ships COMMIT_MESSAGE.md.example as a starting point. There is also a hooks.commitTemplate config key for a fixed format string.

## Sources

- [f/git-rewrite-commits on GitHub](https://github.com/f/git-rewrite-commits)
- [Issues](https://github.com/f/git-rewrite-commits/issues)
- [License: MIT](https://github.com/f/git-rewrite-commits/blob/master/LICENSE)
- [Project website](https://blog.fka.dev/git-rewrite-commits/)
- [README](https://github.com/f/git-rewrite-commits/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/f-git-rewrite-commits
