Skip to main content

Commit Modification Options

Options for modifying commit messages, author/committer names and emails, and controlling how commit ancestry is rewritten.

Commit Message Options

—replace-message

--replace-message
string
Replace text patterns in commit and tag messages.Type: Path to expressions fileFormat: Same syntax as --replace-textApplies to: Commit messages and annotated tag messagesExample expressions file (message-replacements.txt):
# Remove sensitive references
SECRET_TICKET_ID

# Replace old issue tracker URLs
regex:https://oldtracker\.com/issue/([0-9]+)==>https://newtracker.com/issues/\1

# Update old email domain
glob:*@oldcompany.com==>*@newcompany.com
Usage:
git filter-repo --replace-message message-replacements.txt

—preserve-commit-hashes

--preserve-commit-hashes
boolean
default:"false"
Don’t update commit hash references in commit messages.Default behavior: Commit hash references are automatically updated to new hashesWith this flag: Old commit hash references remain unchangedBy default, git-filter-repo automatically finds commit hash references in messages and updates them to the new post-rewrite hashes, preserving the original abbreviation length.Example:
# Don't update hash references
git filter-repo --path src/ --preserve-commit-hashes
Use this if you want to preserve original commit references, or if automatic hash updating causes issues.

—preserve-commit-encoding

--preserve-commit-encoding
boolean
default:"false"
Don’t re-encode commit messages to UTF-8.Default behavior: Messages are re-encoded to UTF-8 if commit object specifies different encodingWith this flag: Original encoding is preservedRequires: Git >= 2.23.0Example:
git filter-repo --preserve-commit-encoding

Names and Emails

—mailmap

--mailmap
string
Apply mailmap file to rewrite author, committer, and tagger names/emails.Type: Path to mailmap fileFormat: See git-shortlog(1) for mailmap formatApplies to: Authors, committers, and taggersExample mailmap file (.mailmap):
# Consolidate different name spellings
Proper Name <[email protected]> <[email protected]>
Proper Name <[email protected]> Old Name <[email protected]>

# Update company email domain
<[email protected]> <[email protected]>

# Fix typo in name
Correct Name <[email protected]> Typoed Name <[email protected]>
Usage:
git filter-repo --mailmap .mailmap
If the mailmap file is tracked in git history, only its current contents are used (historical versions are ignored).

—use-mailmap

--use-mailmap
boolean
Use the .mailmap file from the repository.Equivalent to: --mailmap .mailmapExample:
git filter-repo --use-mailmap

Parent Rewriting

Options that control how commit ancestry is modified during filtering.

—replace-refs

--replace-refs
string
default:"update-no-add"
Control how replace refs are handled.Type: Choice of strategyOptions:
  • delete-no-add - Delete existing replace refs, don’t add new ones
  • delete-and-add - Delete existing, add new for all rewrites
  • update-no-add - Update existing, don’t add new (DEFAULT)
  • update-or-add - Update existing, add only if referenced by existing replace ref
  • update-and-add - Update existing, add new for all rewrites
  • old-default - Use pre-2.45 default behavior
Replace refs allow using old commit IDs with git commands after history rewrite.Example:
# Create replace refs for all rewrites
git filter-repo --replace-refs delete-and-add
Replace refs must be manually pushed and fetched. See git-replace(1) for details.

—prune-empty

--prune-empty
string
default:"auto"
Whether to prune commits that become empty.Type: Choice of strategyOptions:
  • always - Prune all empty commits (even originally empty ones)
  • auto - Only prune commits that become empty due to filtering (DEFAULT)
  • never - Keep all commits, even if empty
What is an empty commit? A commit with no file changes compared to its parent.Default behavior (auto):
  • Prunes commits that become empty due to filtering
  • Keeps commits that were originally empty
  • When parent is pruned, first non-pruned ancestor becomes new parent
Example:
# Remove all empty commits
git filter-repo --prune-empty always

# Keep all commits even if they become empty
git filter-repo --path src/ --prune-empty never

—prune-degenerate

--prune-degenerate
string
default:"auto"
Whether to prune merge commits that become degenerate.Type: Choice of strategyOptions:
  • always - Prune all degenerate merges (even originally degenerate)
  • auto - Only prune merges that become degenerate due to filtering (DEFAULT)
  • never - Keep all merge commits
What is a degenerate merge? A merge commit that:
  • Has fewer than two parents, OR
  • Has the same commit as both parents, OR
  • Has one parent that is an ancestor of the other
Default behavior (auto):
  • Merge commits normally exempt from pruning (for topology)
  • Prunes merges that become degenerate AND have no file changes
  • Only prunes merges that become degenerate, not those that started degenerate
Example:
# Prune all degenerate merges
git filter-repo --prune-degenerate always

—no-ff

--no-ff
boolean
default:"false"
Preserve first parent even if it becomes an ancestor of another parent.Effect: Modifies --prune-degenerate behaviorUse case: Projects that always use git merge --no-ffNormally, if first parent becomes an ancestor of another parent in a merge, that first parent might be pruned (depending on --prune-degenerate). This flag prevents that.Example:
# Preserve merge commit topology
git filter-repo --no-ff

Usage Examples

Update Commit Messages

Create replacements file (messages.txt):
# Update old ticket references
regex:JIRA-([0-9]+)==>GH-\1

# Remove sensitive notes
Sensitive: DO NOT SHARE

# Update old URLs
regex:http://oldserver\.com==https://newserver.com
Apply replacements:
git filter-repo --replace-message messages.txt

Consolidate Author Names

Create mailmap file (.mailmap): Apply mailmap:
git filter-repo --mailmap .mailmap

Aggressive Pruning

# Remove all empty commits and degenerate merges
git filter-repo \
  --path src/ \
  --prune-empty always \
  --prune-degenerate always

Preserve History Topology

# Keep all commits and merges, even if empty
git filter-repo \
  --path src/ \
  --prune-empty never \
  --prune-degenerate never

Create Replace Refs for Old Hashes

# Allow using old commit IDs after rewrite
git filter-repo --replace-refs delete-and-add

# Push replace refs to allow others to use them
git push origin 'refs/replace/*'

# Users can fetch them with:
# git config --add remote.origin.fetch '+refs/replace/*:refs/replace/*'
# git fetch origin

Mailmap Format

The mailmap file format (from git-shortlog):
# Proper Name and Email
Proper Name <[email protected]>

# Just email replacement
<[email protected]> <[email protected]>

# Both name and email replacement
Proper Name <[email protected]> Commit Name <[email protected]>

# Multiple old identities -> one new identity
Proper Name <[email protected]> <[email protected]>
Proper Name <[email protected]> <[email protected]>
Proper Name <[email protected]> Old Name <[email protected]>

# Comments
# Lines starting with # are ignored

Important Notes

Commit Hash RewritingWhen commits are rewritten, they get new hashes. References to old hashes in commit messages are automatically updated unless --preserve-commit-hashes is used.
Empty Commit HandlingThe default --prune-empty auto is usually what you want:
  • Keeps originally empty commits (intentional, like “WIP” commits)
  • Removes commits that become empty due to filtering
Testing Message ReplacementsTest with --dry-run first:
git filter-repo --replace-message msg.txt --dry-run
cat .git/filter-repo/fast-export.filtered

See Also

Build docs developers (and LLMs) love