This Git error occurs when using git replace to substitute one object with another of a different type. Use the -f flag to force the replacement, or ensure both objects share the same type (commit, tree, blob, or tag).
The error "fatal: Objects must be of the same type to be replaced" occurs when you attempt to use `git replace` to substitute one Git object with another, but the two objects have different types. Git's internal database stores four types of objects: commits (snapshots with metadata), trees (directory structures), blobs (file contents), and tags (named references). When you run `git replace <original> <replacement>`, Git expects both objects to be of the same type. For example, you can replace a commit with another commit, or a tree with another tree, but by default you cannot replace a commit with a blob. This type enforcement exists because Git internally looks up objects by their hash ID, and the replacement must work correctly in the same context as the original. A function expecting a commit object would fail if it received a tree object instead. However, Git does allow you to bypass this restriction using the `-f` (force) flag when you have a specific use case that requires cross-type replacement.
First, determine the type of each object you're trying to use:
# Check the type of the original object
git cat-file -t <original-hash>
# Check the type of the replacement object
git cat-file -t <replacement-hash>This will output one of: commit, tree, blob, or tag. Both must match for the replacement to work without forcing.
If you specifically need to replace objects of different types, use the -f or --force flag:
git replace -f <original-hash> <replacement-hash>Warning: Forcing a type mismatch can cause unexpected behavior. Git commands that expect a specific object type may fail or produce incorrect results when they encounter the replacement. Only use this when you fully understand the implications.
If you accidentally used the wrong hash, find the correct one:
For commits:
# Find commit hashes in the log
git log --oneline
# Get the full commit hash
git rev-parse <commit-ref>For trees (directory snapshots):
# Get the tree object from a commit
git rev-parse <commit>^{tree}
# Or view tree contents
git ls-tree <commit>For blobs (file contents):
# Get blob hash for a specific file at a commit
git rev-parse <commit>:<path/to/file>
# List blobs in current tree
git ls-tree -r HEADThe most common use case is replacing one commit with another:
# Replace an old commit with a corrected version
git replace <old-commit-hash> <new-commit-hash>
# Verify the replacement was created
git replace -l
# Check that the replacement is in effect
git log --onelineThis is useful for correcting commit messages, author information, or parent references without rewriting history.
To replace a tree object (for example, to modify a directory structure in history):
# Get the tree hash from the commit you want to modify
git rev-parse <commit>^{tree}
# Create a new tree with modifications (example using git mktree)
# Then replace the original tree
git replace <original-tree-hash> <new-tree-hash>This approach modifies how a directory appears at a specific point in history without changing the commit hashes.
The --edit option creates a replacement of the same type after allowing you to edit:
# Edit a commit (opens editor with commit data)
git replace --edit <commit-hash>
# Edit a blob
git replace --edit <blob-hash>This is the safest approach as Git automatically ensures the replacement is the same type as the original.
View and manage your replacement references:
# List all replacement refs
git replace -l
# Show details about a specific replacement
git replace -l <original-hash>
# Delete a replacement
git replace -d <original-hash>Replacements are stored in refs/replace/ and can be pushed/fetched like other refs:
# Push replacement refs to remote
git push origin 'refs/replace/*'
# Fetch replacement refs from remote
git fetch origin 'refs/replace/*:refs/replace/*'### Understanding Git Object Types
Git has exactly four object types:
- Commit: Contains metadata (author, date, message), a pointer to a tree, and pointers to parent commits
- Tree: Represents a directory listing with names and pointers to blobs or other trees
- Blob: Stores file content (just the data, no filename or permissions)
- Tag: An annotated tag with metadata pointing to another object (usually a commit)
The type restriction exists because each object type has a specific structure that Git commands expect. Replacing a commit with a blob would break commands like git log that need to traverse parent pointers.
### When Force Replacement Makes Sense
There are rare legitimate cases for forcing type mismatches:
- Replacing a lightweight tag ref with an annotated tag object
- Advanced repository surgery where you understand the consequences
- Experimental workflows with custom tooling that handles mixed types
### Disable Replacements Temporarily
If replacements are causing issues, you can disable them:
# Disable replacements for a single command
git --no-replace-objects log
# Disable replacements via environment variable
export GIT_NO_REPLACE_OBJECTS=1### Replacement Refs Storage
Replacements are stored as refs in .git/refs/replace/<original-sha>. Each ref file contains the SHA of the replacement object. You can manually inspect these:
# View replacement refs directly
ls .git/refs/replace/
# See what a replacement points to
cat .git/refs/replace/<original-sha>### Alternative: Use git filter-repo
For complex history modifications, consider git filter-repo instead of git replace:
# Install git-filter-repo
pip install git-filter-repo
# Rewrite history (creates new commits)
git filter-repo --commit-callback 'commit.message = commit.message.replace(b"old", b"new")'Unlike replacements, filter-repo actually rewrites history creating new objects, which may be more appropriate for permanent changes.
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