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

189 lines
5.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 修复重复的 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
```bash
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
```bash
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
```bash
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
```
## 推荐操作步骤
执行以下命令:
```bash
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 唯一性
```bash
# 检查是否有重复的 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 都是唯一的
```