Files
gerrit/修复重复Change-Id.md
2025-12-22 17:12:39 +08:00

5.5 KiB
Raw Permalink Blame History

修复重复的 Change-Id 问题

问题

推送时出现错误:

same Change-Id in multiple changes.
Squash the commits with the same Change-Id or ensure Change-Ids are unique for each commit

这是因为多个提交使用了相同的 Change-Id。Gerrit 要求每个提交都有唯一的 Change-Id。

解决方案

方法一:使用 commit-msg hook 重新生成(推荐)

commit-msg hook 会基于提交内容自动生成唯一的 Change-Id

cd /d/zhini/zhini_im

# 1. 确保 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

# 2. 使用 filter-branch 重新为所有提交生成 Change-Id
git filter-branch -f --msg-filter '
  # 读取原始提交信息
  ORIGINAL_MSG=$(cat)
  
  # 移除旧的 Change-Id如果存在
  CLEAN_MSG=$(echo "$ORIGINAL_MSG" | sed "/^Change-Id:/d" | sed "/^$/N;/^\n$/d")
  
  # 输出清理后的提交信息
  echo "$CLEAN_MSG"
  
  # 使用 commit-msg hook 生成新的 Change-Id
  # hook 会基于提交内容(树对象、父提交、作者等)生成唯一的 Change-Id
  echo ""
  # 临时保存提交信息
  echo "$CLEAN_MSG" > /tmp/commit_msg.txt
  
  # 模拟提交过程,让 hook 生成 Change-Id
  # 这里我们需要手动生成,基于提交的 SHA1 和内容
  COMMIT_SHA=$(git rev-parse HEAD)
  TREE_SHA=$(git rev-parse HEAD^{tree})
  PARENT_SHA=$(git rev-parse HEAD^ 2>/dev/null || echo "")
  
  # 生成基于提交内容的唯一 Change-Id
  CHANGE_ID_BASE=$(echo -n "$COMMIT_SHA$TREE_SHA$PARENT_SHA" | git hash-object --stdin)
  CHANGE_ID="I${CHANGE_ID_BASE:0:40}"
  
  echo "Change-Id: $CHANGE_ID"
' --tag-name-filter cat -- --branches --tags

方法二:使用 git rebase更可靠

这个方法会真正运行 commit-msg hook

cd /d/zhini/zhini_im

# 1. 确保 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

# 2. 创建备份
git branch backup-before-rebase

# 3. 从第一个提交开始 rebase
FIRST_COMMIT=$(git rev-list --max-parents=0 HEAD)
git rebase -i --root

# 在编辑器中:
# - 将所有 'pick' 改为 'reword'
# - 保存并关闭
# 
# 对每个提交:
# - 提交信息编辑器会自动打开
# - 不要修改内容,直接保存退出
# - commit-msg hook 会自动为每个提交生成唯一的 Change-Id
# - 继续下一个提交

方法三:使用脚本自动处理(最简单)

创建一个脚本来自动为每个提交生成唯一的 Change-Id

cd /d/zhini/zhini_im

# 确保 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

# 使用 filter-branch为每个提交生成基于其内容的唯一 Change-Id
git filter-branch -f --msg-filter '
  # 读取原始提交信息
  ORIGINAL_MSG=$(cat)
  
  # 移除所有旧的 Change-Id 行
  CLEAN_MSG=$(echo "$ORIGINAL_MSG" | sed "/^Change-Id:/d")
  
  # 输出清理后的提交信息(去除末尾多余空行)
  echo "$CLEAN_MSG" | sed -e :a -e "/^\$/{\$!N;ba}" -e "s/\n\$//"
  
  # 为当前提交生成唯一的 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=$(git log -1 --format="%an <%ae> %at" HEAD)
  
  # 组合所有信息生成唯一哈希
  UNIQUE_STRING="${COMMIT_SHA}${TREE_SHA}${PARENT_SHA}${AUTHOR}"
  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

推荐操作步骤

执行以下命令:

cd /d/zhini/zhini_im

# 1. 确保 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

# 2. 创建备份
git branch backup-before-fix-changeid

# 3. 为所有提交重新生成唯一的 Change-Id
git filter-branch -f --msg-filter '
  ORIGINAL_MSG=$(cat)
  # 移除旧的 Change-Id
  CLEAN_MSG=$(echo "$ORIGINAL_MSG" | sed "/^Change-Id:/d" | sed -e :a -e "/^\$/{\$!N;ba}" -e "s/\n\$//")
  echo "$CLEAN_MSG"
  
  # 生成基于提交内容的唯一 Change-Id
  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_TIME=$(git log -1 --format="%an|%ae|%at|%cn|%ce|%ct" HEAD)
  
  UNIQUE_STRING="${COMMIT_SHA}${TREE_SHA}${PARENT_SHA}${AUTHOR_TIME}"
  CHANGE_ID_BASE=$(echo -n "$UNIQUE_STRING" | shasum -a 1 | cut -c1-40)
  CHANGE_ID="I${CHANGE_ID_BASE}"
  
  echo ""
  echo "Change-Id: $CHANGE_ID"
' --tag-name-filter cat -- --branches --tags

# 4. 验证所有 Change-Id 都是唯一的
git log --format='%H %s' | while read commit subject; do
  changeid=$(git log -1 --format='%B' "$commit" | grep "^Change-Id:" | head -1)
  echo "$commit $changeid"
done | sort -k2 | uniq -d -f1

# 如果没有输出,说明所有 Change-Id 都是唯一的

# 5. 重新推送
git push gerrit HEAD:refs/for/master

验证 Change-Id 唯一性

# 检查是否有重复的 Change-Id
git log --format='%H' | while read commit; do
  changeid=$(git log -1 --format='%B' "$commit" | grep "^Change-Id:" | head -1 | cut -d' ' -f2)
  echo "$changeid $commit"
done | sort | uniq -d

# 如果没有输出,说明所有 Change-Id 都是唯一的