本文整理了关于批量 cherry-pick、冲突处理、提交拆分、签名补充以及代码历史追踪的常用操作。

批量 Cherry-pick 与提交压缩

从文件读取 Commit 列表

假设 commits.txt 内容如下:

a1b2c3d
d4e5f6g
h7i8j9k

保留原提交:git cherry-pick $(cat commits.txt)

将多个提交合并为一个提交:

git cherry-pick -n $(cat commits.txt)
git commit -m "backport selected commits"

对于大量提交,建议使用脚本:

while read commit; do 
    git cherry-pick -n "$commit" || exit 1;
done < commits.txt

Cherry-pick 冲突处理

发生冲突后查看状态:git status

解决冲突文件中的:

<<<<<<< HEAD
=======
>>>>>>> commit

解决完成后: git add <file>, 继续执行:git cherry-pick --continue

如果使用 -n 且状态丢失,可通过命令确认:git ls-files -u

查看是否仍存在未解决冲突。

Rerere 自动复用冲突解决

如果出现:

Resolved '<file>' using previous resolution.

说明 Git 自动复用了之前的冲突解决结果。

查看状态:git rerere status,查看差异:git rerere diff

忘记某个文件的历史解决方案: git rerere forget <file>

临时禁用 rerere: git -c rerere.enabled=false cherry-pick <commit>

查看与排查修改内容

查看已暂存(Staged)内容

查看暂存区修改:git diff --cached 或:git diff --staged

查看已暂存文件: git diff --cached --name-only

查看修改统计:git diff --cached --stat

排查 Cherry-pick 状态异常

查看当前状态: git status

查看是否存在 Cherry-pick 状态文件:ls .git | grep CHERRY_PICK

查看未解决冲突:git ls-files -u

查看操作历史:git reflog -20

查看代码删除历史

查找某段代码被删除的提交:git log -p -S "关键字符串" -- 文件名

使用正则匹配:git log -p -G "关键字符串" -- 文件名

查看当前行最后修改者:git blame -L 100,100 文件名

查看函数完整演变历史:git log -L '/函数名/',/^}/:文件名

拆分 Squash 后的大提交

撤销提交并保留修改

如果已经将多个模块压缩为一个提交:git reset --mixed HEAD~1 或:git reset HEAD~1

效果:

撤销提交
保留所有修改
恢复到工作区

按模块重新提交

提交模块 A:

git add moduleA/

git commit -s -m "moduleA"

提交模块 B:

git add moduleB/

git commit -s -m "moduleB"

提交模块 C:

git add moduleC/

git commit -s -m "moduleC"

恢复指定文件或目录

从上一个提交恢复

恢复目录:git restore --source=HEAD^ -- packages/private/client-mgmt/

旧版写法:git checkout HEAD^ -- packages/private/client-mgmt/

从指定提交恢复

恢复某个目录:git restore --source <commit-id> -- packages/private/client-mgmt/

恢复某个文件:git restore --source <commit-id> -- file.c

提交签名管理

Signed-off-by 与 GPG 签名区别

添加 Signed-off-by:git commit -s

生成:

Signed-off-by: User Name <user@example.com>

添加 GPG/SSH 签名:git commit -S

查看签名:git log --show-signature

批量补充 Signed-off-by

最近 5 个提交补充签名:git rebase -i --exec "git commit --amend --no-edit -s" HEAD~5

当前分支所有新增提交补签:git rebase -i --exec "git commit --amend --no-edit -s" origin/develop/master

同时补充 Signed-off-by 与 GPG 签名

执行:

git rebase -i --exec "git commit --amend --no-edit -s -S" HEAD~5

验证 Signed-off-by:

git log --format=full

验证 GPG:

git log --show-signature

简洁查看:

git log --pretty="%h %G? %s"

其中:

G = 有效签名
N = 无签名
B = 签名无效