Рукописный скрипт git hooks (pre-commit, commit-msg)

внешний интерфейс Git JavaScript

Введение

Git может запускать пользовательские сценарии, когда происходят определенные важные действия, наиболее часто используемые из них:pre-commit,commit-msg,pre-pushДождитесь крючков. мы можемpre-commitПроверка формата кода при запуске,commit-msgЧтобы проверить триггер для фиксации и отправки пользователю сообщения вpre-pushВыполняйте модульное тестирование, e2e-тестирование и т. д. при срабатывании.

Git выполняетgit initПри инициализации будет.git/hooksКаталог генерирует серию скриптов хуков:

image.png

Как видно из рисунка выше, суффикс каждой письменности равен.sampleВ конце, в это время, скрипт не будет выполняться автоматически. Нам нужно удалить суффикс, прежде чем он вступит в силу.pre-commit.sampleсталиpre-commitбуду работать.

В этой статье в основном рассказывается о том, как писать скрипты git hooks, и мы напишем дваpre-commit,commit-msgСценарий используется в качестве примера, чтобы помочь вам лучше понять сценарий git hooks. Конечно, в работе рекомендуется использовать готовые решения с открытым исходным кодом.husky.

текст

Нет ограничений на язык сценариев, используемый для написания git-хуков, вы можете использоватьnodejs,shell,python,rubyИ другие скриптовые языки, очень гибкие и удобные.

Ниже я буду использовать язык оболочки, чтобы продемонстрировать, как написатьpre-commitа такжеcommit-msgсценарий. Также обратите внимание, что при выполнении этих сценариев, если вы выйдете из программы с ненулевым значением, процесс отправки / отправки Git будет прерван. Поэтому при проверке сообщений/кода в скрипте хуков можно использовать ненулевое значение для выхода, прерывания процесса GIT.

exit 1

pre-commit

существуетpre-commitЧто делать в хуке очень просто, проверяется только формат отправляемого кода, поэтому код скрипта относительно небольшой:

#!/bin/sh
npm run lint

# 获取上面脚本的退出码
exitCode="$?"
exit $exitCode

Поскольку я уже настроил соответствующую конфигурацию eslint и скрипты npm в проекте, вpre-commitДостаточно выполнить соответствующую команду lint в , и оценить, нормально ли она завершается.

// 在 package.json 文件中已配置好 lint 命令
"scripts": {
    "lint": "eslint --ext .js src/"
 },

Давайте посмотрим на движущуюся картинку, при неправильном формате кода будет сообщено об ошибке при фиксации:

demo.gif

Отправьте после изменения формата кода, тогда об ошибке не будет сообщено:

demo2.gif

Загнанный рисунок мы можем видеть, что это был правильно представленный коммит.

commit-msg

существуетcommit-msgВ хуках нам нужно проверить сообщение коммита и пользователя.

#!/bin/sh

# 用 `` 可以将命令的输出结果赋值给变量
# 获取当前提交的 commit msg
commit_msg=`cat $1`

# 获取用户 email
email=`git config user.email`
msg_re="^(feat|fix|docs|style|refactor|perf|test|workflow|build|ci|chore|release|workflow)(\(.+\))?: .{1,100}"

if [[ ! $commit_msg =~ $msg_re ]]
then
	echo "\n不合法的 commit 消息提交格式,请使用正确的格式:\
	\nfeat: add comments\
	\nfix: handle events on blur (close #28)\
	\n详情请查看 git commit 提交规范:https://github.com/woai3c/Front-end-articles/blob/master/git%20commit%20style.md"

	# 异常退出
	exit 1
fi

существуетcommit-msgКогда хук сработает, соответствующий скрипт получит параметр, который является сообщением фиксации.cat $1получить и назначитьcommit_msgПеременная.

Относительно просто проверить регулярность сообщения коммита, просто взгляните на код. Если вас интересует спецификация отправки коммита, вы можете прочитать другую мою статьюстатья.

Относительно просто судить о правах пользователя, просто проверьте почтовый ящик или имя пользователя (при условии, что только сотрудники компании abc имеют разрешение на отправку кода).

email_re="@abc\.com"
if [[ ! $email =~ $email_re ]]
then
	echo "此用户没有权限,具有权限的用户为: xxx@abc.com"

	# 异常退出
	exit 1
fi

Следующие две анимации используются для демонстрации процесса проверки сообщений фиксации и оценки разрешений пользователей:

demo3.gif

demo4.gif

Установить местоположение git по умолчанию

Это только первый шаг, чтобы скрипт мог выполняться нормально, есть еще одна проблема, которую необходимо решить, а именно, как поделиться конфигурацией git hooks с другими разработчиками того же проекта. потому что.git/hooksКаталоги не отправляются в удаленные репозитории с коммитами. Есть два решения этой проблемы: первое — имитировать хаски, чтобы сделать npm-плагин, который автоматически устанавливается в момент установки..git/hooksКаталог Добавить скрипт HOOKS; второй — написать скрипт хуков отдельно в определенном каталоге в проекте, а затем автоматически установить этот каталог в каталог git hooks при установке проекта.

Далее подробно описан процесс реализации второго способа:

  1. существуетnpm installПосле завершения выполнения автоматически выполнитьgit config core.hooksPath hooksЗаказ.
  2. git config core.hooksPath hooksКоманда устанавливает каталог git hooks в каталог hooks в корне проекта.
"scripts": {
    "lint": "eslint --ext .js src/",
    "postinstall": "git config core.hooksPath hooks"
},

Ступай на яму

Исходный код демо-версии может нормально работать в Windows, но после перехода на Mac он не будет работать, и при отправке будет сообщено об ошибке:

hint: The 'hooks/pre-commit' hook was ignored because it's not set as executable.

Причина в том, что скрипт ловушек не является исполняемым по умолчанию, поэтому его необходимо сделать исполняемым:

chmod 700 hooks/*

Чтобы не изменять проект каждый раз, когда вы клонируете проект, лучше добавить эту команду в скрипт npm:

"scripts": {
    "lint": "eslint --ext .js src/",
    "postinstall": "git config core.hooksPath hooks && chmod 700 hooks/*"
},

Конечно, если это окна, вторую половину кода добавлять не нужно.

скрипт хуков nodejs

Чтобы помочь студентам, изучающим интерфейс, лучше понять скрипт git hooks, я переписал версию с nodejs.

pre-commit

#!/usr/bin/env node
const childProcess = require('child_process');

try {
  childProcess.execSync('npm run lint');
} catch (error) {
  console.log(error.stdout.toString());
  process.exit(1);
}

commit-msg

#!/usr/bin/env node
const childProcess = require('child_process');
const fs = require('fs');

const email = childProcess.execSync('git config user.email').toString().trim();
const msg = fs.readFileSync(process.argv[2], 'utf-8').trim(); // 索引 2 对应的 commit 消息文件
const commitRE = /^(feat|fix|docs|style|refactor|perf|test|workflow|build|ci|chore|release|workflow)(\(.+\))?: .{1,100}/;

if (!commitRE.test(msg)) {
  console.log();
  console.error('不合法的 commit 消息格式,请使用正确的提交格式:');
  console.error('feat: add \'comments\' option');
  console.error('fix: handle events on blur (close #28)');
  console.error('详情请查看 git commit 提交规范:https://github.com/woai3c/Front-end-articles/blob/master/git%20commit%20style.md。');
  process.exit(1);
}

if (!/@qq\.com$/.test(email)) {
  console.error('此用户没有权限,具有权限的用户为: xxx@qq.com');
  process.exit(1);
}

Суммировать

На самом деле тема этой статьи не ограничивается интерфейсом, а распространяется на все проекты, использующие git в качестве контроля версий. Такие как Android, ios, Java и т. д. Просто в этой статье в качестве примера был выбран фронтенд-проект.

Недавно прикрепленный исходный код проекта:GitHub.com/ilove3from/git-…

использованная литература