如何使用git钩做得更好
#node #npm #bash #git

以下示例将使用nodejs工具,但是您可以使用语言中的任何类似工具。另外,这篇文章假设您已经在项目中配置了刺激工具。

git挂钩是git功能之一,当发生某个操作时,它将触发自定义脚本。有多种git钩动作,但是今天我们将使用2个客户端钩子,这将帮助您或您的团队写出更好的信息和更改。

git hooks flow

预警

将触发此钩子在将更改提交给git之前,我们将使用此钩子使用以下脚本来提交/优化我们的更改。 SVGO是一个了不起的NPM软件包,它将优化您的SVG文件,在https://jakearchibald.github.io/svgomg/上相同的实现

{
  "scripts": {
    // This will allow the lint to automatically fix our staged files
    "format-eslint": "eslint --fix",
    "format-prettier-eslint": "prettier-eslint --log-level 'silent' --write --eslint-config-path .eslintrc.js",
    "format-stylelint": "stylelint --config .stylelintrc.json --fix",
    "optimize-svgo": "svgo"
  }
}
#!/bin/bash
PASS=true

# 'git diff --diff-filter=d --cached --name-only' will output the staged file names
# with 'grep -E' we can capture the output and filter out the files we wanted to lint using RegExp
STAGED_FILES=$(git diff --diff-filter=d --cached --name-only | grep -E '.*\.(js|vue|ts|svg)$')

# This will exit the script if there is no files matching the pattern
if [[ "$STAGED_FILES" = "" ]]; then
  exit 0
fi

# '\033[0;33m' is yellow bash color
# '\e[0m' means we reset the color back to normal
echo -e "\033[0;33m☐ Running pre-commmit-hooks:\e[0m"

for FILE in $STAGED_FILES
do
  # This will capture the initial has of the file, we use this to detect if there is changes applied after linting
  PRE_LINT_HASH=$(git hash-object "$FILE")

  # Only run eslint/prettier/stylelint on vue/js/ts files
  if [[ $FILE == *vue  || $FILE == *js || $FILE == *ts ]];
  then
    # Only run stylelint on vue files since other file types doesn't contain stylesheet
    if [[ $FILE == *vue ]];
    then
      npm run --silent format-stylelint "$FILE" || PASS=false
      npm run --silent format-prettier-eslint "$FILE" || PASS=false
      npm run --silent format-eslint "$FILE" || PASS=false
    else
      npm run --silent format-prettier-eslint "$FILE" || PASS=false
      npm run --silent format-eslint "$FILE" || PASS=false
    fi
  # SVGO optimize svg files
  elif [[ $FILE == *svg ]]
  then
    npm run optimize-svgo "$FILE"
  fi

  POST_LINT_HASH=$(git hash-object "$FILE")
  # If there is changes detected, we will set the PASS flag to false to stop the commit from continuing
  if [[ "$PRE_LINT_HASH" != "$POST_LINT_HASH" ]]; then
    PASS=false
  fi
done

# Stop the commit if there is file changes during above process
if ! $PASS; then
  # '\033[0;31m' is red bash color
  echo -e "\033[0;31m☒ pre-commmit-hooks failed, please check all the errors or stage all changes\e[0m"
  # 'exit 1' will stop the process by throwing error
  exit 1
fi

exit $?

输出看起来像这样

-> % git commit -m "foo"
☐ Running pre-commmit-hooks:

~/project/foo.js
  82:11  error  Identifier 'foo_fighter' is not in camel case  camelcase

✖ 1 problem (1 error, 0 warnings)

☒ pre-commmit-hooks failed, please check all the errors or stage all changes

准备委托-MSG

在输入提交消息CLI之前将触发此钩子。有时,我们会发出愚蠢或不描述性的提交信息,使用此钩子,我们会将分支名称附加到提交消息的开头中,以便我们可以在git责备期间看到分支名称。如果您使用的是JIRA或任何其他问题跟踪板,通常我们会创建一个带有其代码的分支名称,例如:git checkout -b PROD-34

#!/bin/bash

# This way you can customize which branches should be skipped when
# prepending commit message. 
if [ -z "$BRANCHES_TO_SKIP" ]; then
    BRANCHES_TO_SKIP=(master)
fi

# Get current commit branch name
BRANCH_NAME=$(git symbolic-ref --short HEAD)
BRANCH_NAME="${BRANCH_NAME##*/}"

BRANCH_EXCLUDED=$(printf "%s\n" "${BRANCHES_TO_SKIP[@]}" | grep -c "^$BRANCH_NAME$")
BRANCH_IN_COMMIT=$(grep -c "\[$BRANCH_NAME\]" $1)

# '-n' is a test pattern, we check if the branch name matches with the one we wanted to skip
if [ -n "$BRANCH_NAME" ] && ! [[ $BRANCH_EXCLUDED -eq 1 ]] && ! [[ $BRANCH_IN_COMMIT -ge 1 ]]; then 
  # This will append the commit message with '[branch-name]:'
    sed -i.bak -e "1s/^/[$BRANCH_NAME]: /" $1
fi

使用上述脚本,如果我们做

-> % git commit -m "foo"
[PROD-34 abc123456] [PROD-34]: foo
 1 files changed, 2 insertions(+), 3 deletions(-)
 create mode 100644 foo.js

,但我们不能在远程项目上安装git钩,只有本地

是的,这就是为什么我们要使用postinstall脚本。这将在运行npm install后将触发,我们将创建一个简单的nodejs脚本,以在用户完成安装Project node_modules之后,将我们准备的脚本文件复制到.git/hooks文件夹中。在这里,我将钩子保存到git-hooks文件夹中。

{
  "scripts": {
    "postinstall": "node build/post-install.js",
  }
}
// post-install.js
const fs = require('fs')

// destination will be created or overwritten by default.
fs.copyFile('./git-hooks/prepare-commit-msg', './.git/hooks/prepare-commit-msg', err => {
  if (err) throw err
  console.log('File was copied to destination')
})

// destination will be created or overwritten by default.
fs.copyFile('./git-hooks/pre-commit', './.git/hooks/pre-commit', err => {
  if (err) throw err
  console.log('File was copied to destination')
})

这就是您可以使用git挂钩为团队代码质量创建一些自动化的方法。如果您想查看我在开发过程中使用的其他有用的脚本,则可以检查我的dotfiles

LinkedIn

Github