跳转到主要内容

Git hooks 是一种非常强大的改​​进开发工作流程的方法,无需记住运行额外的脚本或执行额外的任务。在本文中,我们将看看如何在项目存储库中定义自己的简单 git 钩子,它可以自动执行 linting + 格式化 Go 代码的任务。

这个相当简单的示例应该让您了解如何利用 git hooks 来实现您自己的狡猾计划。

现实生活中的例子


这方面的一个例子来自我当前的一个项目,其中团队必须在将机密文件推送到项目的存储库之前对其进行加密。加密文件是一件简单的事情,但由于我们正在处理的加密文件的数量,记住加密每个已更改的文件成为一项挑战,而且我们经常会运行我们的项目并挠头而我们试图弄清楚为什么它没有发现新的秘密。

解决方案


当试图解决这个问题时,我们可以使用的工具相当有限,并且不想使用会影响团队中有自己偏好的人的当前开发流程的东西。

这就是 git hooks 发挥作用的地方。使用钩子,我可以定义一个简单的预提交钩子脚本,它会自动执行加密任何未加密文件并将它们添加到提交的任务。我还可以通过在 hooks/ 目录中创建这些钩子来使其成为团队开发流程的可选插件,这样如果他们希望将这些 git 钩子添加到他们的工作流程中,他们可以使用简单的 git config core.hooksPath hooks 命令。

创建一个 Git 钩子


钩子实际上制作起来非常简单,因为它们只是在特定目录中具有特定名称的 bash 脚本。当您下次执行给定的 git 命令时,它会自动执行此 bash 脚本,前提是它是该特定命令的正确命名文件。

如果您只想在您的机器上为您的特定项目创建 git hooks,您可以通过导航到当前项目目录,然后进入该项目中的 .git/hooks/ 目录来实现。

如果您查看该目录的内容,您应该会看到如下内容:

31/07/2019  22:09               478 applypatch-msg.sample
31/07/2019  22:09               896 commit-msg.sample
31/07/2019  22:09             3,327 fsmonitor-watchman.sample
31/07/2019  22:09               189 post-update.sample
31/07/2019  22:09               424 pre-applypatch.sample
31/07/2019  22:09             1,642 pre-commit.sample
31/07/2019  22:09             1,348 pre-push.sample
31/07/2019  22:09             4,898 pre-rebase.sample
31/07/2019  22:09               544 pre-receive.sample
31/07/2019  22:09             1,492 prepare-commit-msg.sample
31/07/2019  22:09             3,610 update.sample


其中每一个都包含示例 git 挂钩,您只需重命名文件并删除 .sample 文件结尾即可打开这些挂钩。

出于本文的目的,我们关注的文件是预提交文件。

在同一个目录中,让我们创建一个名为 pre-commit 的新文件,并在其中添加以下内容:

#!/bin/bash

echo "Test Hook"

如果您在 Mac 或 Linux 上运行,则必须使用 chmod 设置此脚本的可执行位。在 Windows 上,这应该可以直接开箱即用!

chmod +x pre-commit


使用这个集合,尝试做一个空提交来测试这个:

git commit --allow-empty -m "Testing Git Hook"


当你运行它时,你现在应该看到在 git 执行提交命令之前打印出“Test Hook”。

惊人的!你已经成功创建了自己的 git hook!现在,每次您在此给定存储库中提交某些内容时,都会执行此操作。

改进我们的 Git Hook


好的,所以我们已经能够成功地创建我们的第一个 git 钩子,现在是时候开始改进它了,以便它实际上为我们执行一项有用的任务,而不仅仅是回显一些文本。

让我们首先在这个脚本中添加一些 go linting:

#!/bin/bash

echo "Test Hook"

## this will retrieve all of the .go files that have been 
## changed since the last commit
STAGED_GO_FILES=$(git diff --cached --name-only -- '*.go')

## we can check to see if this is empty
if [[ $STAGED_GO_FILES == "" ]]; then
    echo "No Go Files to Update"
## otherwise we can do stuff with these changed go files
else
    for file in $STAGED_GO_FILES; do
        echo $file
    done
fi

有了这个,尝试更改项目中的 .go 文件并尝试 git add -A 后跟 git commit -m "Some Message"。

您现在将看到,在我们的“测试挂钩”下方,我们的预提交挂钩现在正在打印出已更改文件的路径。

$ git commit -m "Test Commit"

Test Hook
test.go
[master 82ab8c6] test
 1 file changed, 2 insertions(+)


太棒了,所以它可以看到我们已经在我们的项目目录中更新了一个 .go 文件,并且我们能够在我们的 for 循环中回显该文件。让我们扩展我们的 git 钩子,以便在我们提交时自动为我们格式化这个文件:

.git/hooks/pre-commit

#!/bin/bash

echo "Test Hook"

## this will retrieve all of the .go files that have been 
## changed since the last commit
STAGED_GO_FILES=$(git diff --cached --name-only -- '*.go')

## we can check to see if this is empty
if [[ $STAGED_GO_FILES == "" ]]; then
    echo "No Go Files to Update"
## otherwise we can do stuff with these changed go files
else
    for file in $STAGED_GO_FILES; do
        ## format our file
        go fmt $file
        ## add any potential changes from our formatting to the 
        ## commit
        git add $file
    done
fi

现在,当我们保存任何文件并随后添加并提交它们时,这些文件将自动为我们格式化,并且格式化所做的任何更改都将自动添加到给定的提交中:

git add -A

C:\Projects\test>git status
On branch master

        modified:   main.go

git commit -m "Updates"

Test Hook
main.go
main.go
[master 61e6ed4] Updates


惊人的!我们现在已经能够创建一个 git 挂钩,它可以自动改进我们的 Go 开发工作流程,并确保我们提交的任何内容都是格式正确的代码!

在团队之间分配 Git Hooks


现在,不幸的是,我们在项目的 .git/ 目录下的 hooks/ 目录中所做的更改将不会被跟踪,因此将这些更改发布给您团队的各个不同成员变得有点挑战。

但是,要解决这个特殊挑战,您可以做的是在当前项目的目录中创建一个名为 .githooks/ 的目录,并将预提交 git 挂钩存储在该目录中。您将能够像处理项目中的任何其他文件一样提交和跟踪它,并且为了在其他开发机器上启用这些钩子,您只需运行以下命令:

$ git config core.hooksPath .githooks


一旦你执行了这个特定的命令,你现在应该会看到,每当你尝试提交某些东西时,该目录中提供的钩子现在都已启用!

结论


太棒了,所以在本教程中,我们已经了解了如何通过使用 git 挂钩和现有工具(例如 go fmt)来改进 Go 开发工作流程,以确保您提交到存储库的任何内容都已正确格式化!

这只是您可以使用 git hooks 实现的一个非常小的尝试,希望它可以为您提供一些关于如何更进一步的想法!如果您对如何改进此工作流程有任何想法或示例,那么我很乐意在下面的评论部分中听到它们!

 

文章链接