基于Git命令的PR冲突检查门禁与自动合并操作

 

在团队开发的代码分支实践中,团队成员经常需要提出 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.

git-rev-list-branch

也可以展示从某个 commit-id 之前的 commit.

git-rev-list-id

还可以进一步排除可从某个分支拥有的 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

rev-list-not

接着我们可以添加选项参数 –count ,限制列出符合条件的所有 commit 的个数,是一个数字,这样我们可以使用该数字来更方便地进行布尔运算,以便更方便地使用在 gitlab CI/CD 、 脚本 或者 Github Action 等需要进行 PR 版本门禁的地方.

rev-list-count

于公司中的实践

在我的公司中代码仓库是使用 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"

参考文档

Pro Git 关于 rev-list 命令的文档 – Scott Chacon And Ben Straub