Recovery

Fixing wrong author or commit message after commit

How to fix wrong author info, commit messages, or forgotten files after committing. Covers amend, interactive rebase, and batch author modification with filter-repo.

Who This Is For
  • Anyone actively handling a Git mistake
  • Readers who want a conservative rescue habit before trouble happens
Prerequisites
  • Stop mutating the repo further
  • Be ready to inspect `git reflog`, `git status`, and `git log --graph`
Common Risks
  • Running more reset or rebase commands before preserving a checkpoint
  • Changing shared history before assessing blast radius

The short version

Replacing Wrong CommitsGit commits are immutable. You cannot edit an existing commit, but you can create a new one to replace it. Amend replaces the latest commit. Interactive rebase can fix commits in the middle of history.
Original chain (with error)
ABCD
Branch points to: main
After amend (replaced latest)
ABCM
BEF
After rebase -i (new chain replaces old)
ABCE'F'
Branch points to: feature

Git commits are immutable — you can't "edit" an existing commit, but you can create a new one to replace it. The fix method depends on where the error occurred (latest commit vs middle of history).

Fixing the latest commit

Changing the commit message

# Amend the most recent commit message
git commit --amend -m "New commit message"

# Opens your default editor for editing
git commit --amend

Changing the author

# Change the author of the most recent commit
git commit --amend --author="John Doe <john@example.com>"

# Change both message and author
git commit --amend -m "Fixed login bug" --author="John Doe <john@example.com>"

Adding forgotten files

# You committed but forgot to add a file
git add forgotten-file.js

# Add the file to the last commit (no new commit created)
git commit --amend --no-edit

# --no-edit keeps the original commit message unchanged

Understanding --amend

git commit --amend actually creates a new commit with:

  • Content = current staging area
  • Parent = the original commit's parent (skipping the original)
  • A new SHA
A --- B (old commit, will be replaced)
     \
      B' (new commit, after amend)

The original commit B still exists (visible in reflog) but is no longer referenced by any branch.

Fixing commits in the middle of history

Method 1: Interactive rebase (recommended)

# To amend the 3rd commit from HEAD
git rebase -i HEAD~3

This opens an editor showing:

pick abc1234 add user authentication
pick def5678 fix login bug
pick ghi9012 update dependencies

Changing commit message (reword)

Change pick to reword (or r):

reword abc1234 add user authentication
pick def5678 fix login bug
pick ghi9012 update dependencies

After saving, Git opens the editor for each reword-marked commit to let you change the message.

Changing commit content (edit)

pick abc1234 add user authentication
edit def5678 fix login bug
pick ghi9012 update dependencies

After saving, Git pauses at the edit-marked commit:

# HEAD is now at the commit you want to modify
# Modify files
vim bug-fix.js
git add bug-fix.js

# Amend the commit (can change message, author, content)
git commit --amend

# Continue the rebase
git rebase --continue

Method 2: Changing author in history

At the edit pause point during interactive rebase:

git rebase -i HEAD~3
# Mark target commit as edit

# When paused, change the author
git commit --amend --author="New Author <new@email.com>" --no-edit

git rebase --continue

Batch-modifying authors in history

Method 1: Using git filter-repo (recommended)

# Install git-filter-repo
pip install git-filter-repo

# Create a mailmap file
cat > mailmap << EOF
John Doe <john@example.com> <old-wrong@email.com>
Jane Smith <jane@example.com> <another-old@email.com>
EOF

# Apply mailmap to all commits
git filter-repo --mailmap mailmap --force

Mailmap format: New Name <new@email> <old-email> or New Name <new@email> Old Name <old-email>

Method 2: Using .mailmap file (display only)

# Create .mailmap in project root
cat > .mailmap << EOF
John Doe <john@example.com> <old-wrong@email.com>
EOF

# This doesn't modify history, only affects git log display
git log --use-mailmap

Method 3: Environment variables (for future commits)

# Permanent global config
git config --global user.name "John Doe"
git config --global user.email "john@example.com"

# Or repo-specific
git config user.name "John Doe"
git config user.email "john@example.com"

# Temporary override (next commit only)
git commit -m "commit" --author="Temp Author <temp@email.com>"

Adding Co-authored-by

Manual addition

Add to the end of your commit message:

git commit -m "Implemented search feature

Search feature implemented together with @colleague.

Co-authored-by: Colleague <colleague@example.com>
Co-authored-by: Another Colleague <another@example.com>"

Note: Co-authored-by: must be at the end of the commit body, preceded by a blank line.

GitHub's automatic recognition

GitHub recognizes the Co-authored-by: Name <email> format and displays multiple authors. It can also be auto-added during PR merges.

Fixing already-pushed commits

The problem

Rewriting pushed history causes local and remote divergence:

Remote: A --- B --- C
Local:  A --- B' --- C'  (B and C were amended/rebased)

Solution: Force push

# Force push (overwrites remote history)
git push --force-with-lease origin main

# --force-with-lease is safer than --force:
# rejects if remote has new commits you haven't pulled

Team collaboration considerations

  • Notify the team first: Before rewriting history, inform all collaborators
  • Avoid rewriting shared branches: main/master should rarely need force push
  • Use --force-with-lease: Never use bare --force
  • Consider fixup commits: For pushed commits, fixup commits are safer than history rewrite

Fixup commit technique

# Create a fixup commit (automatically marked as fixing a specific commit)
git commit --fixup abc1234

# View commit history
git log --oneline
# def5678 (HEAD) fixup! add user authentication
# abc1234 add user authentication

# Auto-squash all fixup commits
git rebase -i --autosquash HEAD~5

# Or set up a convenient alias
git rebase -i --autosquash HEAD~5

Set up aliases for easier use:

git config --global alias.fixup 'commit --fixup'
git config --global alias.squash-fix 'rebase -i --autosquash'

# Usage
git fixup abc1234
git squash-fix HEAD~5

FAQ

Q: What do I do about SHA changes after amend?

This is normal. A commit's SHA includes content, author, timestamp, and parent info — any change produces a new SHA.

Q: Can I use reset and re-commit instead?

# Go back one commit but keep changes
git reset --soft HEAD~1

# All changes are now staged, ready to re-commit
git commit -m "New commit message"

This is similar to commit --amend but more flexible (you can adjust files).

Q: Can't push after modifying many historical commits?

# Check the difference between local and remote
git log origin/main..HEAD
git log HEAD..origin/main

# If remote has commits you need, fetch first
git fetch origin
git rebase origin/main

# Then force push
git push --force-with-lease

Key takeaways

  1. Be careful with pushed commits: Rewriting forces all collaborators to resync
  2. --force-with-lease is the minimum: Always safer than bare --force
  3. Use fixup commits for small errors: More team-friendly than history rewrite
  4. Set team conventions for history rewriting: Define which branches allow force push
  5. Verify after changing authors: Use git log --format="%h %an <%ae>" to check

Summary

ScenarioMethodRewrites history?
Latest commit message wronggit commit --amendYes
Latest commit author wronggit commit --amend --author=...Yes
Latest commit forgot filesgit add + git commit --amendYes
Middle commit message wronggit rebase -i + rewordYes
Middle commit content wronggit rebase -i + editYes
Batch author changesgit filter-repo --mailmapYes
Small error after pushFixup commit + rebaseYes
Display-only changes.mailmap fileNo

Core principle: Git commits are immutable; "modifying" means creating replacement commits.