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

189 lines
5.7 KiB
Markdown
Raw 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 重复问题
## 问题
即使使用了 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