# 彻底修复 Change-Id 重复问题 ## 问题 即使使用了 SHA1,仍然有重复的 Change-Id。这可能是因为 filter-branch 的处理方式有问题。 ## 最可靠的解决方案:使用 git rebase + commit-msg hook 这是 Gerrit 推荐的标准方法,commit-msg hook 会基于提交内容自动生成唯一的 Change-Id。 ### 步骤 1:清理 filter-branch 的备份引用 ```bash cd /d/zhini/zhini_im # 清理所有 filter-branch 创建的备份引用 git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d 2>/dev/null || true ``` ### 步骤 2:确保 commit-msg hook 已安装 ```bash mkdir -p .git/hooks curl -o .git/hooks/commit-msg http://101.43.95.130:8080/tools/hooks/commit-msg chmod +x .git/hooks/commit-msg ``` ### 步骤 3:使用 git rebase 让 hook 自动生成 Change-Id ```bash # 创建备份 git branch backup-before-rebase-fix # 从第一个提交开始交互式 rebase git rebase -i --root ``` **在编辑器中**: 1. 将所有 `pick` 改为 `reword`(或简写 `r`) 2. 保存并关闭(`:wq`) **对每个提交**: 1. 提交信息编辑器会自动打开 2. **不要修改任何内容**,直接保存退出(`:wq`) 3. commit-msg hook 会自动为这个提交生成唯一的 Change-Id 4. 继续下一个提交 这个过程会自动完成,每个提交都会获得基于其内容的唯一 Change-Id。 ### 步骤 4:验证并推送 ```bash # 验证所有 Change-Id 都是唯一的 git log --format='%H' | while read commit; do git log -1 --format='%B' "$commit" | grep "^Change-Id:" | head -1 | cut -d' ' -f2 done | sort | uniq -d # 如果没有输出,说明所有 Change-Id 都是唯一的 # 推送 git push gerrit HEAD:refs/for/master ``` ## 自动化脚本(如果提交太多,手动 rebase 太麻烦) 如果提交太多,可以使用这个脚本自动化处理: ```bash cd /d/zhini/zhini_im # 1. 清理备份 git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d 2>/dev/null || true # 2. 确保 hook 已安装 mkdir -p .git/hooks curl -o .git/hooks/commit-msg http://101.43.95.130:8080/tools/hooks/commit-msg chmod +x .git/hooks/commit-msg # 3. 创建备份 git branch backup-before-auto-fix # 4. 使用 filter-branch,但这次真正运行 commit-msg hook # 我们需要模拟提交过程,让 hook 生成 Change-Id git filter-branch -f --msg-filter ' # 读取原始提交信息 ORIGINAL=$(cat) # 移除旧的 Change-Id CLEAN=$(echo "$ORIGINAL" | grep -v "^Change-Id:") # 将清理后的提交信息保存到临时文件 echo "$CLEAN" > /tmp/commit_msg.txt # 使用 commit-msg hook 生成 Change-Id # hook 需要环境变量 GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL 等 export GIT_AUTHOR_NAME=$(git log -1 --format="%an" HEAD) export GIT_AUTHOR_EMAIL=$(git log -1 --format="%ae" HEAD) export GIT_AUTHOR_DATE=$(git log -1 --format="%ad" HEAD) export GIT_COMMITTER_NAME=$(git log -1 --format="%cn" HEAD) export GIT_COMMITTER_EMAIL=$(git log -1 --format="%ce" HEAD) export GIT_COMMITTER_DATE=$(git log -1 --format="%cd" HEAD) # 运行 commit-msg hook if [ -f .git/hooks/commit-msg ]; then cat /tmp/commit_msg.txt | .git/hooks/commit-msg else cat /tmp/commit_msg.txt # 如果 hook 不存在,使用 SHA1 作为后备 echo "" echo "Change-Id: I$(git rev-parse HEAD)" fi rm -f /tmp/commit_msg.txt ' --tag-name-filter cat -- --branches --tags # 5. 推送 git push gerrit HEAD:refs/for/master ``` ## 最简单的解决方案(推荐) 如果上面的方法还是有问题,使用这个最简单直接的方法: ```bash cd /d/zhini/zhini_im # 1. 清理所有备份 git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d 2>/dev/null || true # 2. 确保 hook 已安装 mkdir -p .git/hooks curl -o .git/hooks/commit-msg http://101.43.95.130:8080/tools/hooks/commit-msg chmod +x .git/hooks/commit-msg # 3. 创建备份 git branch backup-final-fix # 4. 使用 filter-branch,为每个提交生成基于其完整信息的唯一 Change-Id git filter-branch -f --msg-filter ' # 读取原始提交信息 ORIGINAL=$(cat) # 移除旧的 Change-Id CLEAN=$(echo "$ORIGINAL" | grep -v "^Change-Id:" | sed -e :a -e "/^\$/{\$!N;ba}" -e "s/\n\$//") # 输出清理后的提交信息 echo "$CLEAN" # 生成基于提交完整信息的唯一 Change-Id # 使用:提交 SHA1 + 树对象 SHA1 + 父提交 SHA1 + 作者信息 + 提交者信息 + 时间戳 COMMIT_SHA=$(git rev-parse HEAD) TREE_SHA=$(git rev-parse HEAD^{tree}) PARENT_SHA=$(git rev-parse HEAD^ 2>/dev/null || echo "root") AUTHOR_NAME=$(git log -1 --format="%an" HEAD) AUTHOR_EMAIL=$(git log -1 --format="%ae" HEAD) AUTHOR_DATE=$(git log -1 --format="%at" HEAD) COMMITTER_NAME=$(git log -1 --format="%cn" HEAD) COMMITTER_EMAIL=$(git log -1 --format="%ce" HEAD) COMMITTER_DATE=$(git log -1 --format="%ct" HEAD) # 组合所有信息 UNIQUE_STRING="${COMMIT_SHA}${TREE_SHA}${PARENT_SHA}${AUTHOR_NAME}${AUTHOR_EMAIL}${AUTHOR_DATE}${COMMITTER_NAME}${COMMITTER_EMAIL}${COMMITTER_DATE}" # 生成 40 位十六进制字符串(使用 git hash-object) CHANGE_ID_BASE=$(echo -n "$UNIQUE_STRING" | git hash-object --stdin | cut -c1-40) CHANGE_ID="I${CHANGE_ID_BASE}" echo "" echo "Change-Id: $CHANGE_ID" ' --tag-name-filter cat -- --branches --tags # 5. 验证 echo "验证 Change-Id 唯一性..." DUPLICATES=$(git log --format='%H' | while read commit; do git log -1 --format='%B' "$commit" | grep "^Change-Id:" | head -1 | cut -d' ' -f2 done | sort | uniq -d) if [ -z "$DUPLICATES" ]; then echo "✅ 所有 Change-Id 都是唯一的" echo "" echo "现在可以推送:" echo " git push gerrit HEAD:refs/for/master" else echo "⚠️ 仍有重复的 Change-Id:" echo "$DUPLICATES" fi