The 'replace ref already exists' error occurs when you try to create a git replace reference for an object that already has one. Use the --force flag to overwrite, or delete the existing replacement first.
This error occurs when you attempt to create a replacement reference for a Git object, but a replacement for that object already exists. Git's replace mechanism allows you to substitute one object (typically a commit) with another without rewriting history, making it useful for correcting mistakes or hiding sensitive data. When you run `git replace <object> <replacement>`, Git creates a reference under `refs/replace/<object-hash>`. If this reference already exists because you (or someone else) previously created a replacement for that same object, Git refuses to overwrite it by default. This safety measure prevents accidental loss of existing replacements. The replace mechanism is a powerful but somewhat advanced feature. Unlike rebasing or amending, replacements don't actually modify the object store - they just tell Git to transparently swap one object for another whenever the original is accessed. This makes replacements reversible and non-destructive.
Before making changes, check what replacement references currently exist:
# List all replacement references
git replace -l
# Or use more detailed format
git replace --list
# Show the refs directly
git for-each-ref refs/replace/This shows all objects that have replacements defined. The output displays the hash of each replaced object.
To see what a specific replacement maps to:
# Show details of a specific replacement
git replace -l <object-hash>
# View the replacement ref directly
git show-ref refs/replace/<object-hash>If you want to update an existing replacement to point to a different object, use the -f or --force flag:
# Overwrite existing replacement
git replace -f <object> <new-replacement>
# Example: Replace commit abc1234 with commit def5678
git replace -f abc1234 def5678This will overwrite the existing replacement reference without needing to delete it first.
With git replace --graft:
# Force a graft replacement
git replace --graft -f <commit> <new-parent1> [<new-parent2>...]
# Example: Graft commit to have no parents (make it a root commit)
git replace --graft -f abc1234The force flag is useful when you've refined your replacement and want to update it without the extra step of deletion.
If you prefer to remove the old replacement before creating a new one, use the -d flag:
# Delete a specific replacement
git replace -d <object>
# Example
git replace -d abc1234
# Then create the new replacement
git replace abc1234 def5678To delete multiple or all replacements:
# Delete all replacements (be careful!)
git replace -d $(git replace -l)
# Or delete refs directly
git for-each-ref --format='delete %(refname)' refs/replace/ | git update-ref --stdinDeleting the replacement restores Git's view of the original object - nothing is lost, the replacement mapping is simply removed.
If replacement refs were created by git filter-repo or git filter-branch, you may want to clean them up:
After git filter-repo:
# filter-repo has an option to handle replacements
git filter-repo --replace-refs delete-no-add
# Or delete the replacement refs manually
git for-each-ref --format='delete %(refname)' refs/replace/ | git update-ref --stdinAfter git filter-branch:
# filter-branch creates backup refs in refs/original/
# but may also create replacement refs
# Check for replacement refs
git for-each-ref refs/replace/
# Delete them if no longer needed
git for-each-ref --format='delete %(refname)' refs/replace/ | git update-ref --stdinNote: Only delete replacement refs if you're sure you no longer need the mapping between old and new objects.
Replacement refs are local by default and require explicit pushing/fetching:
To push replacements to a remote:
# Push all replacement refs
git push origin 'refs/replace/*:refs/replace/*'
# Force push (overwrite remote replacements)
git push origin '+refs/replace/*:refs/replace/*'The + prefix forces the push, which is needed if the remote already has conflicting replacement refs.
To fetch replacements from a remote:
# Fetch all replacement refs
git fetch origin 'refs/replace/*:refs/replace/*'
# Force fetch (overwrite local replacements)
git fetch origin '+refs/replace/*:refs/replace/*'Configure automatic fetching:
# Add to fetch refspec in .git/config
git config --add remote.origin.fetch '+refs/replace/*:refs/replace/*'When fetching causes conflicts (same object has different replacements locally and remotely), you'll get the "already exists" error unless you use the + prefix to force.
### Understanding Git Replace
The git replace command creates a reference in refs/replace/<sha1> that points to the replacement object. Whenever Git encounters the original object, it transparently substitutes the replacement:
# How Git stores replacements
.git/refs/replace/abc1234... -> contains hash of replacement objectThis mechanism is used internally by tools like git filter-repo to map old commits to new ones.
### Disabling Replacements Temporarily
You can disable replacement lookups with an environment variable:
# Run a command ignoring all replacements
GIT_NO_REPLACE_OBJECTS=1 git log
# Or use --no-replace-objects flag
git --no-replace-objects logThis is useful for debugging or seeing the original unmodified history.
### Making Replacements Permanent
If you want to bake replacements into the actual commit graph (so replacements are no longer needed), use git filter-repo:
# Make all replacements permanent by rewriting history
git filter-repo --replace-refs delete-and-add
# The replacement refs will be removed after history is rewrittenWarning: This rewrites history and will change commit hashes.
### Types of Replacements
Git replace can work with different object types:
# Replace a commit with another commit
git replace <commit-sha> <replacement-commit>
# Replace a tree (directory structure)
git replace <tree-sha> <replacement-tree>
# Graft: change a commit's parents
git replace --graft <commit> [<new-parent>...]
# Edit a commit (opens editor)
git replace --edit <commit>### Replacement Refs in Bare Repositories
In bare repositories (like those on servers), replacement refs work the same way but are more commonly inherited from clones or pushes:
# On the server, you may need to explicitly enable replace ref fetching
git config receive.advertisePushOptions true### Troubleshooting Replace Conflicts
If you're seeing "already exists" errors after collaborating with others:
1. Check who created which replacements: git log -g refs/replace/
2. Decide whether to keep local or remote replacements
3. Use + prefix when fetching/pushing to force your version
Be careful when forcing - you might lose someone else's intentional replacement.
warning: BOM detected in file, this may cause issues
UTF-8 Byte Order Mark (BOM) detected in file
fatal: Server does not support --shallow-exclude
Server does not support --shallow-exclude
warning: filtering out blobs larger than limit
Git partial clone filtering large blobs warning
fatal: Server does not support --shallow-since
Server does not support --shallow-since in Git
kex_exchange_identification: Connection closed by remote host
Connection closed by remote host when connecting to Git server