gerrit "missing Change-Id"

本文详细介绍了在Gerrit代码审核平台上提交代码时遇到缺失Change-Id的问题及解决方案,包括如何自动插入Change-Id,使用amend选项,reset方法,以及交互式rebase技巧。

场景:

你用 git push 向 gerrit 提交了待审核代码,一切都很顺利,你脑袋里冒出了"代码头上加了'佛祖保佑'果然有效"的想法.
此时 git 打印出如下提示,你的内心OS同步打印 "心情 -5" :

remote: Resolving deltas: 100% (14/14)
remote: Processing changes: refs: 1,done   
remote: ERROR: missing Change-Idincommit message footer
remote:
remote: Hint: To automatically insert Change-Id,installthe hook:
remote:   gitdir=$(git rev-parse --git-dir);scp-p -P 29418 liux@gerrit.xxxxx.com:hooks/commit-msg${gitdir}/hooks/
remote: And then amend the commit:
remote:   git commit --amend
remote:
To ssh://liux@121.xx.xx.xx:29418/kaiba_admin_yunying.git
 ! [remote rejected] HEAD -> refs/for/master(missing Change-Idincommit message footer)
error: failed to push some refs to'ssh://liux@121.xx.xx.xx:29418/sample_project.git'

套路:

大前提: commit-msg 文件必须已经在该项目中存在.

使用ls命令检查该文件是否存在:

$ cd project_dir
$ ls.git/hooks/commit-msg

如果该文件不存在,则按照 git push 时产生的提示信息,获取该文件:

$ gitdir=$(git rev-parse --git-dir);scp-p -P 29418 liux@gerrit.xxxxx.com:hooks/commit-msg${gitdir}/hooks/

上面的命令可以直接从 git push 产生的错误信息中复制出来.
如果要手敲该命令,别忘了把用户名换成自己的.

方法一: 使用 amend 选项生成 Change-Id:

如果缺失 Change-Id 的是最后一个 (head) commit, 使用以下命令即可解决问题:

$ git commit --amend

该命令会打开默认的 commit message 编辑器,一般是 vi.
这时什么都不用修改,直接保存退出即可 (:wq).
再次查看 git log,就会发现缺失的 Change-Id 已经被补上了. 再次 git push 即可.

方法二: 如果缺失 Change-Id 的不是最后一个 commit, 可用 reset 方法:

比如,如果缺失 Change-Id 的 commit 是 git log 中的第二个 commit, 则可以用 git reset 命令将本地分支回退到该 commit.
(但其实用 git reset 找回 Change-Id 是普通青年才干的事情,文艺青年有更优雅的办法.见方法三)
首先执行 git log, 找出缺失了 Change-Id 的 commit,并复制其 commit-id:

$ git log
commit 8e1cad33bcd98e175cba710b1eacfd631a5dda41
Author: liux <liux@xxxx.cn>
Date:   Mon Dec 19 17:43:00 2016 +0800
 
    testcommit"with amended commit message"
     
    Change-Id: I9d2af0cc31423cf808cd235de0ad02abf451937d
 
commit 1a9096a34322885ac101175ddcac7dab4c52665d
Author: liux <liux@xxxx.cn>
Date:   Mon Dec 19 15:23:36 2016 +0800
 
    testcommit-msg hook
 
......

发现是第二个 commit 缺失 Change-Id. 将代码 reset 到这个 commit, 并执行 amend:

$ git reset 1a9096a34322885ac101175ddcac7dab4c52665d
$ git commit --amend

注: 上面的 git reset 用法不会毁灭你写的代码,放心执行即可.
这时 git log 可以发现该 commit 已经补全了 change-Id.
下一步是把 git reset 撤消掉的代码重新 commit, 然后 push 即可:

$ git add ......
$ git commit -m "你的提交日志"
$ git push review HEAD:refs/for/master

方法三: 使用交互式 rebase 找回任意提交位置的 Change-Id:

前面方法二中给出的例子是第二个提交缺失 Change-Id,这时用 git reset 还可以解决问题.
但如果你在一个方案上已经工作了一个月,生成了100个本地 commit,提交时才发现 git log 中第99个 commit 缺失 Change-Id. 如果这时还用 git reset 来找回 Change-Id ......
不要香菇,不要蓝瘦.文艺青年表示有办法优雅的解决问题: 交互式 rebase.

第一步,找到缺失 Change-Id 的那个 commit:

$ git log
commit 8aaaa749db4a5b105aa746659c5cd266ac82fffe
Author: liux <liux@xxxx.cn>
Date:   Mon Dec 19 17:43:24 2016 +0800
 
    I am commit message 3
     
    Change-Id: Ic89d5ce6ce4de70d1dcb315ce543c86a2b3ac003
 
commit 8e1cad33bcd98e175cba710b1eacfd631a5dda41
Author: liux <liux@xxxx.cn>
Date:   Mon Dec 19 17:43:00 2016 +0800
 
    I am commit message 2
     
    Change-Id: I9d2af0cc31423cf808cd235de0ad02abf451937d
 
commit 1a9096a34322885ac101175ddcac7dab4c52665d
Author: liux <liux@xxxx.cn>
Date:   Mon Dec 19 15:23:36 2016 +0800
 
    I am commit message 1
 
commit d714bcde0c14ba4622d28952c4b2a80882b19927
Author: shangsb <shangsb@czfw.cn>
Date:   Wed Dec 14 09:20:52 2016 +0800
 
    这是一个提交
     
    Change-Id: I629b2bedff95491875f63634ad3da199612735b6
......

发现是 "I am commit message 1" 这个提交没有 Change-Id.

第二步,编辑交互式 rebase 的命令文件:

执行 git rebase -i, 参数为 该提交的上一个提交的 commit-id (本例中为 "表单" 那个提交):

$ git rebase -i d714bcde0c14ba4622d28952c4b2a80882b19927
这个命令会打开默认的编辑器,一般为 vi. 内容如下:
pick 1a9096a I am commit message 1
pick 8e1cad3 I am commit message 2
pick 8aaaa74 I am commit message 3
# Rebase d714bcd..8aaaa74 onto d714bcd
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

可以将这个文件理解为 git rebase 的内嵌脚本.其命令写法已经在下面的注释里给出了.
这里不赘述,仅给出最终要将该文件编辑成什么样子:

reword 1a9096a I am commit message 1
pick 8e1cad3 I am commit message 2
pick 8aaaa74 I am commit message 3
# Rebase d714bcd..8aaaa74 onto d714bcd
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

即: 将缺失了 Change-Id 的 commit 前面的 pick 改为 reword 即可 (简写 r 也可以). 保存退出 (:wq)
注1: 上述文件中 commit 的顺序是和 git log 显示的顺序相反的: git log 为最新的在最前; 上述文件为 最新的在最后.
注2: 如果进入该模式后,却不确定该怎么改,这时不要担心,直接退出编辑则什么都不会发生 (:q!)
注3: 如果没有搞清楚原理,就要注意,除了按需把 pick 改为 reword 外,不要做其他改动.尤其注意不要删除任何行 (被删除的那行对应的提交将丢失).
注4: 你应该已经发现,有多个 commit 缺失 Change-Id 的情况也可以用该方法一次性处理.

第三步,逐个编辑 commit-msg:

上一步打开的文件保存退出后,git会逐个打开被你标注了 reword 的提交日志页面.
不需要修改任何东西,逐个保存退出即可 (一路 :wq).

第四步,再次提交:

用 git log 查看提交日志,会发现缺失的 Change-Id 都生成了. 愉快的提交代码吧!

$ git push review HEAD:refs/for/master

心法:

gerrit 的 Change-Id 机制:

首先要明确, Change-Id 是 gerrit (代码审核平台)的概念, 与 git (版本管理) 是没有关系的.
简单来说, Change-Id 是 gerrit 用以追踪具体提交的机制. 这里不贴网上已有的解释,举两个栗子大家体会下:

  1. 你已经用 git push 将代码提交 gerrit 审核了,这时你发现代码中有疏漏,修改了一下,执行 git commit --amend, 再次推送还可以成功. 这就是因为 gerrit 检查到两次 push 的 commit 有同一个 change-id, 就认为是同一个提交,因此可以 amend.
  2. git push 将代码提交到 gerrit 审核,到 gerrit 网站一看,大红字标着 Can Not Merge 字样. 我想常用 gerrit 的同学肯定都遇到过这问题. 之前我的做法是, git reset 后,更新代码,再重新提交. 现在的做法是,不用 git reset 了,直接 git commit --amend, 删掉 commit log 中的 change-id 那行,然后wq保存退出.这时 gerrit 的那个钩子脚本会再生成一个不同的 change-id ,这时再更新代码,重新提交即可成功. 这里只简要介绍该方法,具体步骤将在 代码冲突 场景中详解.

Change-Id 的生成机制请继续向下看.

git 的 hook 机制:

钩子(hooks)是一些在$GIT-DIR/hooks目录的脚本, 在被特定的事件(certain points)触发后被调用。当git init命令被调用后, 一些非常有用的示例钩子脚本被拷到新仓库的hooks目录中; 但是在默认情况下它们是不生效的。 把这些钩子文件的".sample"文件名后缀去掉就可以使它们生效。
hook机制可以理解为回调.各个钩子其实就是一段 bash 脚本,各钩子脚本的名字都是固定的.可以查看git项目根目录下的 .git/hooks 这个文件夹,看看都有哪些可用的钩子.

$ cdproject_dir
$ ls .git/hooks/
applypatch-msg.sample  commit-msg.sample   pre-applypatch.sample  prepare-commit-msg.sample  pre-rebase.sample
commit-msg             post-update.sample  pre-commit.sample      pre-push.sample            update.sample

如果有自己感兴趣的 git 事件要处理,修改相应的钩子脚本罗辑即可.然后把 .sample 后缀去掉,钩子就生效了.
在 gerrit 的 Change-Id 生成机制中,其实 gerrit 就是利用了 commit-msg 的钩子,在我们提交代码后,按一定规则去修改了我们的提交日志,在其末尾添加了这么一行:

 Change-Id: .......

这个钩子脚本是什么时候被加入我们的项目中的呢? 其实就是你在 git push 出错时 gerrit 网站给你的提示中的那句命令:

$ gitdir=$(git rev-parse --git-dir);scp -p -P 29418 liux@gerrit.kaiba315.com:hooks/commit-msg${gitdir}/hooks/

执行该命令即可得到生成 Change-Id 的钩子脚本. 这条命令做了以下事情:

// git rev-parse --git-dir 这条命令将找到该项目的 git 目录,并将其赋值给 gitdir 这个变量.
// 一般就是项目根目录下的 .git/ 这个目录.
$ gitdir=$(git rev-parse --git-dir)
 
// 执行 scp 命令,从 gerrit 代码服务器将钩子脚本文件 commit-msg 下载到项目的钩子目录下 (一般是 .git/hooks/)
$ scp -p -P 29418 liux@gerrit.kaiba315.com:hooks/commit-msg ${gitdir}/hooks/

查看该脚本,会发现它是用 awk 命令处理了 .git/COMMIT_EDITMSG 这个文件.
所以如果想手动生成 Change-Id ,只要执行下面命令,就可以生成一个可用的 Change-Id:

$ cdproject_dir
$ echo "some commit" > /tmp/test_generate_change_id
$ .git/hooks/commit-msg/tmp/test_generate_change_id
$ cat /tmp/test_generate_change_id
some commit
 
Change-Id: Ic89d5ce6ce4de70d1dcb315ce543c86a2b3ac003

利用 git commit --amend 重新生成 Change-Id 的原理:

git commit --amend , 看名字就知道,是对某个 commit 做出修改的.这种修改既可以包含文件修改,也可以仅包含提交日志修改.
我们用 --amend 对 commit 做出修改后, commit-msg 的钩子会被重新触发, Change-Id 就会被生成出来.
用交互式 git rebase 来生成 Change-Id 也是同一个道理.
另:
通过总结历次缺失 Change-Id 的例子,发现基本我们自己通过 git commit 生成的提交都会很顺利的生成 Change-Id.
通过 git merge, git revert 等命令由 git 自己生成的 commit 则有较高概率会缺失 Change-Id.
嗯,我们发现了一个伟大的定律! 然并卵... 并不知道怎么解决这个问题.
因此提倡尽量用 git rebase 代替 git merge 来更新代码.
事实上, git rebase 更新代码 相较 git merge 更新代码,有诸多优势,只是略复杂些.强烈建议用 git rebase 方式更新代码.

git rebase -i:

呃... 自己查文档去吧, 要讲清楚这个又得写一大坨东西出来.

<think>我们正在处理一个关于Git提交错误的问题,错误信息是“missing Change-Id in message footer”。根据引用内容,我们知道这个Change-IdGerrit代码审核系统所要求的,用于标识每次提交。用户提到他想查找提交记录中缺少Change-Id的提交信息,具体是针对提交44268f4。 根据引用[1]和引用[3],我们知道可以通过在本地仓库的.git/hooks目录下放置一个commit-msg钩子脚本来生成Change-Id。如果这个钩子不存在或者没有正确执行,就会导致提交信息中缺少Change-Id。 用户已经执行了一个命令来获取这个钩子,但可能由于网络或命令格式问题没有成功(引用[3]提到将scp -p改为scp -O)。 现在用户想要查找提交记录中缺少Change-Id的提交信息(注意:他指定了提交44268f4)。我们可以通过以下步骤来查看该提交的信息并修复问题: 步骤1:检查该提交的提交信息 使用命令:`git show 44268f4 --pretty=fuller` 这会显示该提交的详细信息,包括提交信息。我们可以查看是否确实缺少Change-Id。 步骤2:如果确认缺少Change-Id,我们需要修复这个提交。修复的方法有两种: 方法一:使用交互式变基(rebase)来修改提交信息(适用于尚未推送到远程的提交) 方法二:如果已经推送,则可能需要使用`git commit --amend`(但注意,如果已经推送,修改提交历史可能会影响他人,需要谨慎,并且可能需要管理员权限强制推送) 但是,由于这个提交已经存在于历史记录中(用户指定了提交哈希),并且可能是已经推送的,我们通常使用交互式变基来修改。 具体步骤: 1. 确定要修改的提交的前一个提交(即44268f4的前一个提交),假设为<base-commit>。 2. 执行:`git rebase -i <base-commit>` 在打开的编辑器中,找到44268f4这一行,将前面的“pick”改为“edit”(或“reword”),然后保存退出。 3. 当变基进行到该提交时,会暂停。此时,我们可以使用`git commit --amend`来修改提交信息。 在修改提交信息时,我们需要让钩子生成Change-Id。但是,由于我们可能已经安装了钩子,所以当我们修改提交信息时,钩子会自动添加Change-Id。 如果没有自动添加,我们可以手动在提交信息的最后一行添加一个空行,然后添加一行:Change-Id: I...(但通常钩子会自动生成) 4. 完成修改后,使用`git rebase --continue`继续变基。 但是,如果钩子没有安装,我们需要先安装钩子。安装钩子的命令在引用[1]和引用[3]中给出,但需要根据实际情况调整。 步骤3:安装commit-msg钩子(如果尚未安装) 执行命令(根据引用[3]修改): ``` scp -O -P 29418 liyj@gerrit.ingageapp.com:hooks/commit-msg .git/hooks/ ``` 注意:这里需要将端口和用户名、主机名替换为实际值。用户之前使用的命令可能是不同的端口和用户名。 步骤4:如果钩子已经安装,但提交时没有生成Change-Id,可能是因为钩子没有执行权限。我们可以给钩子添加执行权限: ``` chmod +x .git/hooks/commit-msg ``` 步骤5:重新提交(在变基过程中修改提交信息)时,钩子会自动运行,添加Change-Id。 但是,用户可能只是想查看这个提交的信息,而不是修复它?根据问题描述,用户说“我想查找提交记录中缺少Change-Id的提交信息”,所以首先我们需要查看这个提交的信息。 因此,我们先执行步骤1,查看提交信息。 如果用户需要修复,再按照上述步骤进行。 另外,引用[2]提到了Commitizen工具,这是一个帮助撰写规范提交信息的工具,但我们的问题主要是缺少Change-Id,所以重点还是安装钩子。 总结回答: 首先,我们可以通过以下命令查看提交44268f4的详细信息: ``` git show 44268f4 --pretty=fuller ``` 如果确认缺少Change-Id,我们可以通过以下步骤修复: 1. 确保已经正确安装了commit-msg钩子(参考引用[3]的命令,注意使用scp -O): ``` scp -O -P 29418 liyj@gerrit.ingageapp.com:hooks/commit-msg .git/hooks/ chmod +x .git/hooks/commit-msg ``` 2. 使用交互式变基来修改该提交: - 找到该提交的父提交哈希(假设为`abc123`,即44268f4的前一个提交) - 执行:`git rebase -i abc123` - 在编辑器中,将44268f4这一行前面的“pick”改为“edit”,保存退出。 - 然后Git会停在44268f4这个提交,此时执行:`git commit --amend` - 这会打开编辑器,你可以修改提交信息(或者不做任何修改,直接保存退出),这时钩子会自动在提交信息末尾添加Change-Id- 最后,执行`git rebase --continue`完成变基。 注意:如果该提交已经被推送到远程,那么修复后需要使用`git push --force`(或`git push -f`)强制推送,但这会改变历史,所以需要确保没有其他人基于这个提交工作。 如果用户只是想查找所有缺少Change-Id的提交,我们可以编写一个脚本来检查。例如,使用`git log`结合grep来查找没有Change-Id的提交。 例如: ``` git log --pretty=format:"%H" | while read commit_hash; do if ! git show $commit_hash --pretty=fuller | grep -q "^Change-Id:"; then echo "Commit $commit_hash is missing Change-Id" fi done ``` 但是,这个脚本可能会比较慢,因为要检查每一个提交。我们可以优化,比如只检查最近一定数量的提交,或者指定范围。 根据用户的需求,他指定了提交44268f4,所以我们先针对这个提交处理。 最后,生成相关问题。</think>### 解决 Git 提交缺少 Change-Id 的问题 当 Git 提交出现 `missing Change-Id in message footer` 错误时,说明提交信息中缺少 Gerrit 代码审核系统要求的 Change-Id 标识符。以下是针对提交 `44268f4` 的解决方案: #### 1. **检查提交信息** 首先确认该提交是否确实缺少 Change-Id: ```bash git show 44268f4 --pretty=fuller ``` 在输出中检查是否存在以 `Change-Id: I` 开头的行(通常在提交信息末尾)。 #### 2. **安装 commit-msg 钩子** 缺少 Change-Id 通常是因为未安装 Gerrit 的钩子脚本: ```bash # 进入项目目录 cd /path/to/your/repo # 下载钩子脚本(根据引用[1][3]调整参数) scp -O -P 29418 your_username@gerrit.server.com:hooks/commit-msg .git/hooks/ # 添加执行权限 chmod +x .git/hooks/commit-msg ``` > **注意**: > - 替换 `your_username` 和 `gerrit.server.com` 为实际值 > - 使用 `-O` 参数而非 `-p`(引用[3]) #### 3. **修复历史提交** 为已存在的提交 `44268f4` 添加 Change-Id: ```bash # 启动交互式变基(替换 abc123 为 44268f4 的前一个提交IDgit rebase -i abc123 ``` 在编辑器中: 1. 找到 `44268f4` 所在行,将行首的 `pick` 改为 `edit` 2. 保存退出后执行: ```bash git commit --amend --no-edit git rebase --continue ``` 钩子会自动注入 Change-Id。 #### 4. **验证修复** ```bash git show HEAD # 检查最新提交是否包含 Change-Id ``` #### 5. **强制推送(如需)** 如果提交已推送到远程: ```bash git push --force-with-lease origin branch-name ``` > ⚠️ 强制推送会覆盖远程历史,确保团队协作无冲突[^1]。 --- ### 关键原理说明 1. **Change-Id 作用**:Gerrit 通过该标识跟踪同一变更的多次提交(如代码修订后重新提交)。 2. **钩子工作机制**:`commit-msg` 钩子会在每次提交时自动生成 Change-Id 并插入消息末尾[^3]。 3. **常见错误原因**: - 未安装钩子脚本 - 钩子脚本权限不足(需 `chmod +x`) - 网络问题导致钩子下载失败 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值