【Git 学习笔记_15】第七章 用 git hook 钩子、别名、脚本提升日常工作效率(中)

7.3 在提交消息中应用外部信息

关闭提交注释编辑器时,会触发 commit-msg 钩子,可用于处理提交注释或完成一个自动检测工作。

本节示例需要先禁用 prepare-commit-msg 钩子,同时启用 commit-msg 钩子:

# init hooks
$ git checkout -b commit-msg-example
Switched to a new branch 'commit-msg-example'
$ mv .git/hooks/prepare-commit-msg .git/hooks/prepare-commit-msg.example
$ cp .git/hooks/commit-msg.sample .git/hooks/commit-msg

示例一:禁止提交

commit-msg 脚本修改如下:

#!/bin/bash
echo "you are not allowed to commit"
exit 1

验证:

$ echo "Frogs, scallops, and coco shell" >> fishtank.txt
$ git add fishtank.txt
# no matter what you input into the editor, you got result like this:
$ git commit
you are not allowed to commit
$ git log -1
commit 64b780b3d4918e5a56ddca5662431be4fd0e3789 (HEAD -> commit-msg-example, master)
Author: SafeWinter <zandong_19@aliyun.com>
Date:   Sun Dec 19 02:41:48 2021 +0800

    did everything

可见,commit-msg 钩子是在关闭编辑器时触发,而 prepare-commit-msg 钩子是在弹出编辑器之前。

示例二:与 Jenkins-CI 组合使用

本例将演示的场景:在提交时必须输入一个有效的 Jenkins ID,关闭提交注释编辑器后,commit-msg 钩子读取该 ID 并请求第三方网站,如果查询成功,则将查询结果补录到提交注释内,否则中止提交。

修改 commit-msg 钩子:

#!/bin/bash
JIRA_ID=$(cat $1 | grep jenkins | sed 's/jenkins //g')
ISSUE_INFO=$(curl -g "https://issues.jenkins.io/browse/JENKINS-${JIRA_ID}")
if [ -z "${ISSUE_INFO}" ]; then 
  echo "Jenkins issue ${JIRA_ID} does not exist"
  echo "Please try again"
  exit 1
else
  TITLE=$(curl -g "https://issues.jenkins.io/browse/JENKINS-${JIRA_ID}" | grep -E "<title>.*</title>")
  echo "Jenkins issue ${JIRA_ID}"
  echo "${TITLE}"
  exit 0
fi

注意:由于时间间隔过久,原请求地址已经改为 https://issues.jenkins.io/browse/JENKINS-${JIRA_ID}

这里用到了 CURL 来获取网页内容,分别用一个无效 ID(jenkins 384895)与有效 ID (jenkins 3157)进行测试:

$ echo "more water" >> fishtank.txt
$ git add fishtank.txt
$ git commit

此时,在弹出编辑器的首行,即 subject 位置,输入 Feature cascading ...,然后在第三行,即 body 位置,输入 jenkins 384895,保存,关闭编辑器,返回命令行将看到如下结果:

在这里插入图片描述

很明显,无效 ID 无法顺利提交,可以用 git status 验证:

在这里插入图片描述

再来看看有效 ID 的情况。在提交注释编辑器中输入如下内容:

Feature: Cascading...

jenkins 51444

得到结果:

在这里插入图片描述

有效 ID 顺利提交,查看提交日志:

$ git log -1
commit 2fc2c1711cb86c731f9a2e94b7dee95b873acfa9 (HEAD -> commit-msg-example)
Author: SafeWinter <zandong_19@aliyun.com>
Date:   Sun Dec 19 17:47:19 2021 +0800

    Feature: Cascading...

    jenkins 51444

这里与原书不一致,按书中的原意,title标签的内容应该加到提交注释中,因此 commit-msg 钩子漏了一个写入的操作:(第 11 行)

#!/bin/bash
JIRA_ID=$(cat $1 | grep jenkins | sed 's/jenkins //g')
ISSUE_INFO=$(curl -g "https://issues.jenkins.io/browse/JENKINS-${JIRA_ID}")
if [ -z "${ISSUE_INFO}" ]; then 
  echo "Jenkins issue ${JIRA_ID} does not exist"
  echo "Please try again"
  exit 1
else
  TITLE=$(curl -g "https://issues.jenkins.io/browse/JENKINS-${JIRA_ID}" | grep -E "<title>.*</title>")
  echo "Jenkins issue ${JIRA_ID}"
  echo "${TITLE}" >> $1
  exit 0
fi

再次验证(与书中一致):

在这里插入图片描述

如果需要去掉查询结果中的 <title></title> 标签,可以对 commit-msg 脚本调整如下:

#!/bin/bash
JIRA_ID=$(cat $1 | grep jenkins | sed 's/jenkins //g')
ISSUE_INFO=$(curl -g "https://issues.jenkins.io/browse/JENKINS-${JIRA_ID}")
if [ -z "${ISSUE_INFO}" ]; then 
  echo "Jenkins issue ${JIRA_ID} does not exist"
  echo "Please try again"
  exit 1
else
  TITLE=$(curl https://issues.jenkins.io/browse/JENKINS-${JIRA_ID} | grep -E "<title>.*</title>")
  TITLE=$(echo ${TITLE} | sed 's/^<title>//' | sed 's/<\/title>$//')
  echo "Jenkins issue ${JIRA_ID}"
  echo "${TITLE}" >> $1
exit 0
fi

新增一次提交,验证结果如下:

在这里插入图片描述

本例中,提交注释如果填入无效的 ID,会直接丢弃已经写好的注释内容,实际工作中不应如此简单粗暴。一个更合理的方案是结合 prepare-commit-msg 钩子实现提交注释内容的“缓存”:如果提交中断,则将已经写好的注释内容临时保存到一个位置,以便下次提交时,用 prepare-commit-msg 钩子提前读取。

7.4 阻止特定版本推送到远程库

本节介绍 pre-push 钩子。顾名思义,就是在执行 git push 命令时、实际推送前触发的一段 shell 脚本。如果不满足某个自定义推送条件,就可以阻止推送。

jgit 为例,演示如何按自定义的条件控制推送。由于执行 git push 命令时,相关 hook 钩子在执行脚本前会先通过 HTTPS 协议校验身份,因此只能以本地仓库为远程库:

# prepare remote repo locally
$ git clone https://git.eclipse.org/r/jgit/jgit chapter7.1
$ git clone --branch master ./chapter7.1/ chapter7.2
$ cd chapter7.2
$ git branch
* master

示例一:若提交注释包含 nopush 字样,则禁止推送

# checkout a new branch
$ git checkout -b prepushHook  --track origin/master
# Create a commit
$ git reset --hard 2e0d178
$ sed -i '' 's/2.9.1/3.0.0/g' pom.xml
$ git add pom.xml
$ git commit -m "Please nopush"
$ git log -1
# Edit the hook
$ cp .git/hooks/pre-push.sample .git/hooks/pre-push

pre-push 钩子写入如下脚本:

#!/bin/bash
echo "You are not allowed to push"
exit 1

测试推送:

$ git push origin HEAD:refs/heads/master
$ git log --grep "nopush"

观察结果:

在这里插入图片描述

与预期一致。接下来加入判定逻辑:

#!/bin/bash
COMMITS=$(git log --grep "nopush")
if [ "$COMMITS" ]; then 
  echo "You have commit(s) with nopush message"
  echo "aborting push"
  exit 1
fi

注意:第 2 行 不能 在等号两边加空格(COMMITS = $(git log --grep "nopush")

验证效果:

$ git push origin HEAD:refs/heads/master

在这里插入图片描述

发散

让用户决定是否继续推送(提供交互式逻辑):检测提交注释中是否包含 nopush,如果有,则提示用户是否继续推送——如果输入 n,则直接中止推送;如果输入 y,则继续推送:

pre-push 调整为如下内容:

#!/bin/bash
COMMITS=$(git log --grep "nopush" --format=format:%H)
if [ "$COMMITS" ]; then
  exitmaybe=1
fi
if [ $exitmaybe -eq 1 ]; then
  while true
    do
      clear
      for commit in $COMMITS
        do
          echo "$commit has no push in the message"
        done
      echo "Are you sure you want to push the commit(s)?(yY/nN)"
      read -r REPLY <&1
      case $REPLY in
        [Yy]* ) break;;
        [Nn]* ) exit 1;;
        * ) echo "Please answer yes or no.";;
      esac
    done
fi

测试1:输入 n

$ git push origin HEAD:refs/heads/master

在这里插入图片描述

测试2:输入 y

$ git push origin HEAD:refs/heads/master

在这里插入图片描述

小结

pre-push 钩子可以有效避免由于用户误操作或不小心误触命令导致的意外推送。配合 shell 脚本的强大功能,可以更灵活地控制推送细节。

  • 22
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安冬的码畜日常

您的鼓励是我持续优质内容的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值