在团队开发的代码分支实践中,团队成员经常需要提出 PR 来合并代码到主分支或开发分支,而对于开发分支来说并不需要代码合并权限人员来手动 Code Rreview ,只需要检查代码是否落后于目标分支,若无就直接批准合并。
该过程是一个重复的过程,那么我们是否可以自动检查需要合并的代码是否落后,然后自动进行批准、拒绝合并操作呢。查阅了资料发现 git rev-list 命令可以进行源代码与目标代码版本的比对,那么我们就展开讲讲这个命令与它的使用方法。
git rev-list 命令的介绍与常规用法
rev-list 是 reverse-list 的意思,即按 commit 的时间倒序列出其每次 commit-id。官方的总览使用简介为
git rev-list [<options>] <commit-id>… [[--] <path>…]
Git 官方文档是说 rev-list 是一个非常重要的 Git 命令,因为它提供了构建和遍历提交祖先图的能力。这也是为何能使用它来比对合并代码的版本是否落后的原因。
纸上得来终觉浅,我觉得还是从实际例子出发,展示 git rev-list 命令的使用与效果。
构造实验 Git 仓库
我们新建一个名为 gitSample 的空文件夹,并新建一个文本为 .DS_Store 的 .gitignore 文件,然后初始化 Git 仓库,并提交第一次 commit 到本地仓库的默认分支 master,接着新建一个文本为 Hello World 的 REAMDME.md 文件并提交第二次 commit 到本地仓库的默认分支 master,最后新建并切换从 master 分支分叉出去的 feature 分支。
mkdir gitSample
cd gitSample
echo '.DS_Store' > .gitignore
git init
git add .
git commit -m 'First Commit'
echo 'Hello World' > README.md
git add .
git commit -m 'Second Commit'
git checkout -b feature
rev-list 命令的基础使用
rev-list 命令可以展示某个分支的时间倒序的每次 commit 的 id.
也可以展示从某个 commit-id 之前的 commit.
还可以进一步排除可从某个分支拥有的 commit。在分支名前面加 ^ 符号就是排除该分支拥有的 commit 。那么我们就可以使用该命令展示 所有待合并源分支的 commit 但排除目标分支拥有的 commit 。那么这个效果就是计算是否有合并冲突。
rev-list 命令实现 PR 冲突检查门禁
首先在刚才的实验仓库 feature 分支给 README.md 文件追加 I am coder 文本。并提交到本地仓库的 feature 分支。这样我们就有了一个有版本差异的仓库。
echo 'I am coder' >> README.md
git add .
git commit -m 'commit On feature'
接着我们就可以可以测试展示所有属于 feature 分支的 commit-id , 但要排除属于 master 分支的 commit-id .
git rev-list feature ^master
# 以下是 git rev-list feature ^master 的简写
git rev-list master..feature
接着我们可以添加选项参数 –count ,限制列出符合条件的所有 commit 的个数,是一个数字,这样我们可以使用该数字来更方便地进行布尔运算,以便更方便地使用在 gitlab CI/CD 、 脚本 或者 Github Action 等需要进行 PR 版本门禁的地方.
于公司中的实践
在我的公司中代码仓库是使用 gitlab 的,因此使用了 gitlab CI/CD 来进行 PR 前落后目标分支版本的门禁与自动合并。自动合并是通知服务器异步请求使用了 gitlab 合并 PR API , 下面是可供参考的部分 gitlab CI/CD 的 .gitlab-ci.yml , 当然为了不泄密,是简略版,有不懂的欢迎留言或者电子邮件沟通,感谢。
...
# 只写了 PR 版本冲突门禁检查的 job 的代码
checkCommitDiff:
stage: check_commit_diff
script:
- echo "合并请求源分支:${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}"
- echo "合并请求目标分支:${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}"
- git fetch
- git branch -a
# 判断源分支是否落后,如果落后则失败 , gitlab CI/CD 收到非0就是失败
- if (( $(git rev-list origin/${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}..origin/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME} --count)>0 )); then exit 1; else echo exit 0; fi
rules:
# 该 job 只在合并流水线执行
- if: $CI_PIPELINE_SOURCE == "merge_request_event"