|
#!/bin/bash |
|
|
|
# A script to rewrite author/committer history for a Git repository. |
|
# It uses 'git filter-branch' and has no external dependencies. |
|
# Created by @paladini - github.com/paladini |
|
|
|
# Define colors for output |
|
C_BLUE="\033[1;34m" |
|
C_GREEN="\033[1;32m" |
|
C_RED="\033[1;31m" |
|
C_YELLOW="\033[1;33m" |
|
C_RESET="\033[0m" |
|
|
|
# --- 1. Get New Author Information --- |
|
echo -e "${C_BLUE}--- Step 1: Fetching your global Git configuration ---${C_RESET}" |
|
NEW_NAME=$(git config --global user.name) |
|
NEW_EMAIL=$(git config --global user.email) |
|
|
|
if [ -z "$NEW_NAME" ] || [ -z "$NEW_EMAIL" ]; then |
|
echo -e "${C_RED}Error: Your global user.name and user.email are not set.${C_RESET}" |
|
echo "Please set them first with:" |
|
echo " git config --global user.name \"Your Name\"" |
|
echo " git config --global user.email \"[email protected]\"" |
|
exit 1 |
|
fi |
|
|
|
echo "Your configured identity is: ${C_GREEN}${NEW_NAME} <${NEW_EMAIL}>${C_RESET}" |
|
echo |
|
|
|
# --- 2. Find and Select Old Email --- |
|
echo -e "${C_BLUE}--- Step 2: Finding all unique author emails in the log ---${C_RESET}" |
|
# Get a sorted, unique list of author emails from the entire history |
|
OLD_EMAILS=($(git log --all --format='%ae' | sort -u)) |
|
|
|
if [ ${#OLD_EMAILS[@]} -eq 0 ]; then |
|
echo -e "${C_YELLOW}No commits found in this repository. Nothing to do.${C_RESET}" |
|
exit 0 |
|
fi |
|
|
|
# Let user choose which email to replace |
|
echo "Please choose the OLD email you want to replace:" |
|
select OLD_EMAIL in "${OLD_EMAILS[@]}"; do |
|
if [[ -n "$OLD_EMAIL" ]]; then |
|
break |
|
else |
|
echo -e "${C_RED}Invalid selection. Please try again.${C_RESET}" |
|
fi |
|
done |
|
|
|
if [ "$OLD_EMAIL" == "$NEW_EMAIL" ]; then |
|
echo -e "${C_YELLOW}The old email is the same as the new email. Nothing to do.${C_RESET}" |
|
exit 0 |
|
fi |
|
|
|
echo |
|
echo -e "You will replace commits from: ${C_RED}${OLD_EMAIL}${C_RESET}" |
|
echo |
|
|
|
# --- 3. Final Confirmation --- |
|
echo -e "${C_BLUE}--- Step 3: Confirmation ---${C_RESET}" |
|
echo -e "${C_YELLOW}WARNING: This will rewrite your project's history. This is a destructive operation.${C_RESET}" |
|
echo |
|
echo "The following change will be applied to all matching commits:" |
|
echo -e " - FROM: ${C_RED}${OLD_EMAIL}${C_RESET}" |
|
echo -e " - TO: ${C_GREEN}${NEW_NAME} <${NEW_EMAIL}>${C_RESET}" |
|
echo |
|
|
|
read -p "Are you absolutely sure you want to proceed? (y/N) " -n 1 -r |
|
echo |
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then |
|
echo "Operation cancelled." |
|
exit 1 |
|
fi |
|
|
|
# --- 4. Execute History Rewrite --- |
|
echo |
|
echo -e "${C_BLUE}--- Step 4: Rewriting history... (This may take a while) ---${C_RESET}" |
|
|
|
# Export variables so they are available in the subshell created by filter-branch |
|
export OLD_EMAIL |
|
export NEW_NAME |
|
export NEW_EMAIL |
|
|
|
git filter-branch --env-filter ' |
|
if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]; then |
|
export GIT_COMMITTER_NAME="$NEW_NAME" |
|
export GIT_COMMITTER_EMAIL="$NEW_EMAIL" |
|
fi |
|
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]; then |
|
export GIT_AUTHOR_NAME="$NEW_NAME" |
|
export GIT_AUTHOR_EMAIL="$NEW_EMAIL" |
|
fi |
|
' --tag-name-filter cat -- --all |
|
|
|
# --- 5. Clean Up and Final Instructions --- |
|
echo |
|
echo -e "${C_GREEN}History rewritten successfully!${C_RESET}" |
|
echo |
|
echo -e "${C_BLUE}--- Step 5: Final Instructions ---${C_RESET}" |
|
echo "Git keeps a backup of your old history in 'refs/original/'." |
|
read -p "Do you want to remove this backup now? (y/N) " -n 1 -r |
|
echo |
|
if [[ $REPLY =~ ^[Yy]$ ]]; then |
|
git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin |
|
echo "Backup refs removed." |
|
fi |
|
|
|
echo |
|
echo -e "${C_YELLOW}IMPORTANT: To make these changes permanent on your remote, you must force-push.${C_RESET}" |
|
echo "Run the following command for your main branch:" |
|
echo -e "${C_GREEN}git push --force origin main${C_RESET}" |
How to Use
Save the Script: Save the code for the script into a file named
git-rewrite-author.shin the root of your Git repository.Make it Executable: Open your terminal and grant execution permissions to the script:
Run the Script: Execute the script from within your repository. It will guide you through the process.
Rewriting history changes the unique ID (SHA-1 hash) of every altered commit. After the script finishes, your local history will be different from the remote repository's history. To update the remote, you must force-push.
This is a destructive action. If you are collaborating with others on this branch, a force-push can create significant problems for their work. Ensure you are the only one working on the branch or that your entire team is coordinated before proceeding.
# Example: Force-push your changes to the 'main' branch on 'origin' git push --force origin main