SSF0SSF0
首页
前端
  • Node
  • Go
  • C#
  • MySql
  • Bash
  • Git
  • Docker
  • VuePress
  • CI/CD
  • 服务器
  • 网站
  • 学习资料
  • 软件
Timeline
Github
标签
分类
首页
前端
  • Node
  • Go
  • C#
  • MySql
  • Bash
  • Git
  • Docker
  • VuePress
  • CI/CD
  • 服务器
  • 网站
  • 学习资料
  • 软件
Timeline
Github
标签
分类
  • Bash

    • Bash 获取路径在不同类型电脑的区别
  • Git

    • Git 使用 ssh 与 https 的区别
    • Git 回滚、重置与变基
    • 文件名大小写发生变化的坑
    • Git 提交信息规范解读与实践指南
    • Git 历史邮箱统一 + 推送 GitHub 后的远程分支处理指南
  • Docker

    • Docker 命令大全
    • nginx 镜像部署静态文件
    • Docker 运行命令说明
    • 使用 node 镜像运行本地项目
    • 挂载和卷的区别
    • Docker 打包多平台镜像
    • Docker 使用 mysql
    • Docker 容器网络访问问题总结
  • VuePress

    • 使用 VuePress 搭建个人博客概括
  • CI/CD

    • blog 使用 Github-Actions 部署 docker 服务器
  • 服务器

    • 腾讯云使用 ssh 连接服务器(Linux 实例)
    • ssl 证书安装到 docker 服务器
    • 操作系统与架构
    • ssh 连接时长问题
  • 掌握 hosts 文件:本地开发、域名重定向与回调处理完全指南
  • Cloudflare DNS与代理:完全指南

Git 历史邮箱统一 + 推送 GitHub 后的远程分支处理指南

详情:GitHub 的 contribution(贡献记录)是通过提交时的邮箱地址识别的。如果你在提交历史中使用了旧邮箱,而这个邮箱没有绑定到你现在的 GitHub 账户,GitHub 就不会将其算作你的贡献。

场景:使用 git filter-repo 统一 Git 历史邮箱,重写历史后强推 GitHub,修复 (旧地址删除后) contributions 丢失的问题,并恢复远程分支跟踪。

❓ 为什么使用 git filter-repo

为了统一历史记录中的邮箱地址,我们需要重写 Git 提交历史。
而 git filter-repo 是目前 Git 官方推荐的历史重写工具,优点:

  • 🚀 速度快(比 filter-branch 快几十倍)

  • ✅ 支持 .mailmap 映射(批量替换作者/邮箱)

  • 💡 更安全、更易用


🔧 如何安装 git filter-repo

📦 macOS(推荐 Homebrew 安装):

brew install git-filter-repo

🐧 Ubuntu / Debian:

sudo apt install git-filter-repo

🪟 Windows(Git Bash 或 Python 环境):

pip install git-filter-repo

或前往 GitHub Release 页面下载:
👉 https://github.com/newren/git-filter-repo


📄 什么是 .mailmap?

.mailmap 是 Git 提供的一个“身份映射”文件,它可以让你统一不同邮箱或用户名的提交记录,例如:

Git用户名 <邮箱A@163.com> <邮箱B@qq.com>
Git用户名 <邮箱A@163.com> <94172257+GitHub-Name@users.noreply.github.com>

当配合 git filter-repo --use-mailmap 使用时,它可以批量将旧提交中的作者名/邮箱替换为你指定的目标值,适合用于:

  • 修复 GitHub contributions 不显示的问题

  • 统一多设备提交产生的不同用户名


🎯 目标说明

  • 将 Git 提交历史中的多个旧邮箱统一为:邮箱A@163.com

  • 姓名统一为:Git用户名

  • 修改完成后强制推送至 GitHub

  • 解决重写历史后远程分支丢失跟踪的问题

🧩 旧邮箱列表

旧邮箱来源说明
邮箱B@qq.com最初本地提交邮箱
94172257+GitHub-Name@users.noreply.github.comGitHub 网页提交生成
DESKTOP-F0C5U3P\hfsWindows 本地自动生成用户名

🛠 步骤 1:创建 .mailmap 文件并重写提交历史

cat > .mailmap <<EOF
Git用户名 <邮箱A@163.com> <邮箱B@qq.com>
Git用户名 <邮箱A@163.com> <94172257+GitHub-Name@users.noreply.github.com>
Git用户名 <邮箱A@163.com> DESKTOP-F0C5U3P\hfs <邮箱A@163.com>
EOF

git filter-repo --use-mailmap --force

🔍 步骤 2:验证修改是否生效

git log --format='%an <%ae>' | sort | uniq -c

应输出:

次数 Git 用户名 <邮箱A@163.com>

🌐 步骤 3:重新添加远程仓库地址

由于 git filter-repo 会移除 origin,需要重新添加:

git remote add origin git@github.com:GitHub-Name/repositorie-name.git

🚀 步骤 4:强制推送到 GitHub

⚠️ 警告:这将覆盖远程仓库的历史,请确认无其他协作者或已备份。

git push --force --all

🔁 步骤 5:恢复本地分支与远程分支的跟踪关系

✅ 方法 1:使用 VS Code

  • 打开左侧 Source Control 面板

  • 点击 "发布分支" 按钮(Publish branch)

✅ 方法 2:使用 SourceTree

  • 打开 SourceTree ➝ 选择本地分支

  • 右键 ➝ 设置跟踪远程分支 ➝ 选择 origin/main 或 origin/master

⚠️ 注意事项(必须处理)

项目操作建议 未提交改动 提交或 stash 后再操作 暂存中的改动 清理或提交 .git/logs 等历史缓存 filter-repo 会自动清理,不建议中途操作不完整

✅ 最终效果验证

git log --format='%an <%ae>' | sort | uniq -c

输出应为:

次数 Git 用户名 <邮箱A@163.com>

并在 GitHub 上恢复正确的 contribution 显示。

🛠 Git 批量邮箱统一工具脚本(含自动推送)

需求:如果你有多个仓库需要做一样的操作,可以使用自动化脚本批量处理,比如遍历 ~/学习项目/ 下所有仓库。

适用场景:批量统一多个 Git 仓库的历史提交邮箱和作者名,自动强推到 GitHub,解决 contributions 丢失问题。

📦 脚本功能

  • ✅ 扫描指定目录下的所有 Git 仓库

  • ✅ 检测是否包含旧邮箱/旧用户名

  • ✅ 自动生成 .mailmap 文件进行邮箱替换

  • ✅ 使用 git filter-repo 重写历史

  • ✅ 自动添加远程仓库 origin

  • ✅ 自动强推所有分支

  • ✅ 支持控制是否推送(开关配置)

📂 配置说明(脚本顶部)

BASE_DIR="$HOME/学习项目"                  # 本地项目集合目录
GITHUB_USER="GitHub-Name"                 # GitHub 用户名
GITHUB_NAMESPACE="GitHub-Name"            # GitHub 用户名或组织名
NEW_NAME="Git用户名"                         # 统一后作者名
NEW_EMAIL="邮箱A@163.com"        # 统一后邮箱
OLD_EMAILS=("邮箱B@qq.com" "94172257+GitHub-Name@users.noreply.github.com")  # 所有旧邮箱
OLD_NAMES=("DESKTOP-F0C5U3P\hfs")        # 所有旧用户名(Windows 会这样)
AUTO_PUSH=true                            # 是否自动推送到远程

🧑‍💻 使用方法

① 将以下脚本保存为 fix-git-history.sh

#!/bin/bash

# ========== 配置项 ==========
BASE_DIR="$HOME/学习项目"
GITHUB_USER="Hefengshun"
GITHUB_NAMESPACE="Hefengshun"
NEW_NAME="何风顺"
NEW_EMAIL="he15518191739@163.com"
OLD_EMAILS=("511385442@qq.com" "94172257+Hefengshun@users.noreply.github.com")
OLD_NAMES=("DESKTOP-F0C5U3P\hfs")
AUTO_PUSH=true
# ============================

log_info() {
  echo -e "\033[1;34m[INFO]\033[0m $1"
}
log_warn() {
  echo -e "\033[1;33m[WARN]\033[0m $1"
}
log_done() {
  echo -e "\033[1;32m[DONE]\033[0m $1"
}

process_repo() {
  repo_path="$1"
  repo_name=$(basename "$repo_path")
  echo -e "\n=============================="
  log_info "正在处理仓库:$repo_name"

  cd "$repo_path" || return

  if [ ! -d ".git" ]; then
    log_warn "跳过:不是 Git 仓库"
    return
  fi

  match=false
  for email in "${OLD_EMAILS[@]}"; do
    if git log --format='%ae' | grep -q "$email"; then
      match=true
    fi
  done
  for name in "${OLD_NAMES[@]}"; do
    if git log --format='%an' | grep -q "$name"; then
      match=true
    fi
  done

  if [ "$match" = false ]; then
    log_info "无旧邮箱记录,跳过"
    return
  fi

  log_info "创建 .mailmap..."
  echo "$NEW_NAME <$NEW_EMAIL> <${OLD_EMAILS[0]}>" > .mailmap
  for email in "${OLD_EMAILS[@]:1}"; do
    echo "$NEW_NAME <$NEW_EMAIL> <$email>" >> .mailmap
  done
  for name in "${OLD_NAMES[@]}"; do
    echo "$NEW_NAME <$NEW_EMAIL> $name <$NEW_EMAIL>" >> .mailmap
  done

  log_info "正在重写历史..."
  git filter-repo --use-mailmap --force

  echo "📄 当前提交记录作者邮箱:"
  git log --format='%an <%ae>' | sort | uniq -c

  if [ "$AUTO_PUSH" = true ]; then
    git_remote_url="git@github.com:$GITHUB_NAMESPACE/$repo_name.git"
    git remote remove origin 2>/dev/null
    git remote add origin "$git_remote_url"
    log_info "设置远程仓库:$git_remote_url"
    git push --force --all
    log_done "推送成功:$repo_name"
  else
    log_warn "未推送,请手动执行:git push --force --all"
  fi

  echo -e "=============================="
}

log_info "开始扫描目录:$BASE_DIR"
for repo in "$BASE_DIR"/*; do
  if [ -d "$repo" ]; then
    process_repo "$repo"
  fi
done

log_done "所有仓库处理完成!"
  # 清理 .mailmap 文件
  rm -f .mailmap

② 赋予执行权限

chmod +x ~/fix-git-history.sh

③ 运行脚本

~/fix-git-history.sh

📌 注意事项

  • 脚本会删除并重建 .git/logs 和远程绑定,请 提前备份重要仓库

  • 强推会覆盖 GitHub 上历史,请确保你是唯一协作者,或所有人同意此操作

  • 提交前请处理所有 未提交的变更与暂存区


✅ 最终验证

git log --format='%an <%ae>' | sort | uniq -c

输出应为:

N Git用户名 <邮箱A@163.com>

说明你已经成功统一所有提交记录 🥳

最后更新时间:
贡献者: 何风顺
上一页
Git 提交信息规范解读与实践指南