git脚本

在测试脚本时:


image.png
先要切换到hook文件所在的位置
然后再执行脚本测试
最后再贴到对应的hook

背景:

做一些git规范,而准备的自动化操作

介绍:

Git 也具有在特定事件发生之前或之后执行特定脚本代码功能(从概念上类比,就与监听事件、触发器之类的东西类似)。

Git Hooks 就是那些在Git执行特定事件(如commit、push、receive等)后触发运行的脚本,挂钩是可以放置在挂钩目录中的程序,可在git执行的某些点触发动作。

没有设置可执行位的钩子将被忽略。

官网介绍:https://git-scm.com/docs/githooks

Git hooks如何工作的:

每一个使用了 git 的工程下面都有一个隐藏的 .git 文件夹。

[图片上传失败...(image-9aa8f1-1739935198806)]

挂钩都被存储在 .git 目录下的 hooks 子目录中,即大部分项目中的 .git/hooks。 如下图:

[图片上传失败...(image-149897-1739935198806)]

Git 默认会放置一些脚本样本在这个目录中,除了可以作为挂钩使用,这些样本本身是可以独立使用的。

所有的样本都是shell脚本,其中一些还包含了Perl的脚本。

不过,任何正确命名的可执行脚本都可以正常使用 ,也可以用Ruby或Python,或其他脚本语言。

上图是git 初始化的时候生成的默认钩子,已包含了大部分可以使用的钩子,但是 .sample 拓展名防止它们默认被执行。

为了安装一个钩子,你只需要去掉 .sample 拓展名。

或者你要写一个新的脚本,你只需添加一个文件名和上述匹配的新文件,去掉.sample拓展名。

把一个正确命名且可执行的文件放入 Git 目录下的 hooks子目录中,可以激活该挂钩脚本,之后他一直会被 Git 调用。

使用:

commit-msg修改成以下代码,并删掉后缀.sample

#!/bin/sh
echo "Checking commit message format..."

commit_msg=$(cat "$1")

# 检查提交消息是否以指定前缀开头(例如 feat、fix、docs 等)
if ! echo "$commit_msg" | grep -qE "^(feat|fix|docs|style|refactor|test|chore): "; then
  echo "Commit message must start with one of the following: feat, fix, docs, style, refactor, test, chore."
  exit 1
fi

echo "Commit message format is correct."

当你不以指定前缀开头(例如 feat、fix、docs 等)提交格式时,会报错:

[图片上传失败...(image-5c8483-1739935198806)]

增加前缀时,就ok:

[图片上传失败...(image-c94209-1739935198806)]

常用钩子:

客户端****钩子

只影响它们所在的本地仓库。有许多客户端挂钩,以下把他们分为:提交工作流挂钩、电子邮件工作流挂钩及其他客户端挂钩。

commit操作有 4个挂钩被用来处理提交的过程,他们的触发时间顺序如下: pre-commitprepare-commit-msgcommit-msgpost-commit

  1. pre-commit 挂钩在键入提交信息前运行,最先触发运行的脚本。

  2. prepare-commit-msg 挂钩在提交信息编辑器显示之前,默认信息被创建之后运行,它和 pre-commit 一样,以非零值退出会放弃提交。

  3. commit-msg钩子和prepare-commit-msg钩子很像,但它会在用户输入提交信息之后被调用。

  4. post-commit 挂钩在整个提交过程完成后运行,他不会接收任何参数,但可以运行git log来获得最后的提交信息。总之,该挂钩是作为通知之类使用的。

服务端钩子

pre-receive 处理来自客户端的推送(push)操作时最先执行的脚本就是 pre-receive

post-receive

post-receive 挂钩在整个过程完结以后运行,可以用来更新其他系统服务或者通知用户。

例子:

  1. pre-commit 检查代码规范

STAGE_FILES=$(git diff --cached --name-only --diff-filter=ACM -- '*.ts' '*.js' '*.tsx')
if test ${#STAGE_FILES} -gt 0
then
    echo '开始eslint检查'

    which eslint &> /dev/null
    if [[ "$?" == 1 ]]; then
        echo '没安装eslint'
        exit 1
    fi

    PASS=true

    for FILE in $STAGE_FILES
    do
        eslint $FILE
        if [[ "$?" == 1 ]]; then
      PASS=false
    fi
  done

  if ! $PASS; then
      echo "eslint检查没通过!"
      exit 1
  else
      echo "eslint检查完毕"
  fi

else
    echo '没有js文件需要检查'
fi

exit 0

如果没安装eslint或者没通过检查就不允许推送

[图片上传失败...(image-4fa1a2-1739935198806)]

  1. prepare-commit-msg 统一提交格式

#!/bin/sh

# 获取当前分支名
branch=$(git symbolic-ref --short HEAD)

# 提交消息文件路径
commit_msg_file=$1

# 获取提交信息的类型和其他部分
type=""
scope=""
subject=""

# 从默认提交消息中获取类型、范围和主题
if [ -n "$branch" ]; then
    # 你可以根据你的团队约定,自定义从分支名提取 `type` 和 `scope`
    # 例如从 `feature/xyz` 分支中提取 `type=feat`, `scope=xyz`
    # 这里假设分支名是按照 `<type>/<scope>` 形式命名的

    type=$(echo "$branch" | cut -d'/' -f1)    # 获取 type,假设分支名格式为 type/scope
    scope=$(echo "$branch" | cut -d'/' -f2)   # 获取 scope,假设分支名格式为 type/scope
fi

# 获取提交主题(假设用户已经输入了提交消息)
subject=$(cat $commit_msg_file)

# 统一格式:type(scope): subject
echo "$type($scope): $subject" > $commit_msg_file

# 添加空行和可选的 body/footer
echo "" >> $commit_msg_file
echo "" >> $commit_msg_file
echo "Footer: Fixes #123" >> $commit_msg_file   # 可以替换为实际的 footer 信息,如 issue 号码

[图片上传失败...(image-7a0d33-1739935198806)]

会根据你的提交内容,然后加上格式,格式就是获取你的分支名(type),文件夹或者路径(scope)

  1. commit-msgprepare-commit-msg类似,前者是提交git写入历史之前触发,后者是提交git消息之前触发

#!/bin/sh
echo "Checking commit message format..."

commit_msg=$(cat "$1")

# 检查提交消息是否以指定前缀开头(例如 feat、fix、docs 等)
if ! echo "$commit_msg" | grep -qE "^(feat|fix|docs|style|refactor|test|chore): "; then
  echo "Commit message must start with one of the following: feat, fix, docs, style, refactor, test, chore."
  exit 1
fi

echo "Commit message format is correct."

检测提交内容如果不包含feat、fix、docs 等,就拒绝推送

  1. post-commit提交成功后,触发

#!/bin/bash

# 获取当前分支
current_branch=$(git rev-parse --abbrev-ref HEAD)
echo "您推送的分支是"
echo "$current_branch"

当commit提交到本地时触发,一般做提交之后的操作

  1. git merge每当有合并操作后,执行

#!/bin/bash

echo "获取当前分支"
current_branch=$(git rev-parse --abbrev-ref HEAD)

echo "已获取完毕"
echo "$current_branch"

# 获取远程仓库名称(默认 origin)
remote_name=$(git remote)

# 检查是否有未推送的 commit
if git rev-list --count "$current_branch" "@{u}" 2>/dev/null | grep -q '[1-9]'; then
    echo "检测到未推送的 commit,正在推送..."
    git push "$remote_name" "$current_branch"
    echo "推送完成 ✅"
else
    echo "没有未推送的 commit 🎉"
fi

# 判断是否是 master 分支
if [[ "$current_branch" == "dev/master" ]]; then
  echo "我在分支 dev/master"

  echo "检测到合并操作,获取被合并的分支名..."
  merged_branch=$(git reflog -1 --pretty=format:"%gs" | sed -n 's/^merge \(.*\):.*/\1/p')

  if [[ -n "$merged_branch" ]]; then
       echo "被合并的分支是: $merged_branch"
    else
        merged_branch="origin/dev/master"
        echo "无法检测到被合并的分支名,采用默认分支origin/dev/master"
    fi

  # 拉取远程仓库的最新数据(包括 master 和 develop)
  git fetch

  echo "我已拉取到最新代码"

  echo "检测到合并操作,准备将更改合并到 develop。"

    # 切换到 develop 分支
    git checkout dev/develop

    # 确保 develop 分支是最新的
    git pull origin dev/develop

    # 合并 master 分支的更改到 develop
    git merge merged_branch -m "Merge master changes (from hotfix) into dev/develop"

    # 推送 develop 分支的更新到远程
    git push

    echo "已将 $merged_branch 的更改合并并推送到 develop 分支。"

    # 切换回master 分支
    git checkout dev/master

    echo "已切换回 master 分支。"
fi

[图片上传失败...(image-3ab970-1739935198806)]

[图片上传失败...(image-9539ff-1739935198806)]

  1. 合并操作后,触发的方法,并没有push

  2. 因此先检测是否需要push,然后push到master

  3. 检测当前分支是否是master

  4. 如果是,就获取被合并分支名和拉取远程最新代码

  5. 切换到develop分支,合并被合并分支的代码(同步更改)

  6. 切换到之前手动切换的master分支

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。