5.5 KiB
5.5 KiB
修复重复的 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 都是唯一的