介绍
版本控制已成为现代软件开发的核心要求,它允许项目安全地跟踪更改,并允许重置、完整性检查和协作等好处。
通过使用hooks
系统,git允许开发人员和管理员通过指定git将根据不同的事件和操作调用的脚本来扩展功能。
在本指南中,您将探索 git hooks 的想法,并展示如何实现可以帮助您在您自己的独特环境中自动化任务的代码。
前提条件
- 在你開始之前,你必須在你的伺服器上安裝「git」。如果你在Ubuntu 20.04上跟隨,你可以查看我們的指南(如何在Ubuntu 20.04上安裝 git)。
- 你應該熟悉如何在一般意義上使用 git. 如果你需要介紹,安裝是其中的一部分,稱為 Introduction to Git: Installation, Usage, and Branches,這是開始的好地方。
<$>[注]
注: 如果您已经对 git 和 git hook 概念感到舒适,并且想深入实践示例, 您可以跳过设置仓库
。
当你完成上述要求后,继续。
使用 Git Hooks 的基本想法
当开发软件在共享项目上,维护风格指南标准,或部署软件时,往往有重复性的任务,你会想做每次采取行动。
当您运行某些 git 命令时,软件将检查 git 存储库中的hooks
目录,看看是否有相关的脚本要运行。
某些脚本在发生操作之前运行,可用于确保代码符合标准,进行健全检查,或设置环境。
使用这些能力,可以执行政策,确保一致性,控制环境,甚至处理部署任务。
定义 Hooks 类别
斯科特·查康(Scott Chacon)的书(Pro Git)试图将不同类型的摇篮分为类别,他将它们分为以下类别:
- 客户-Side Hooks: 在犯人的电脑上被召唤和处决的钩子. 这些又分为几个不同的类别: -Contting-Workflow hooks: 承诺钩被用来支配在作出承诺时应当采取的行动。 它们被用来进行理智检查,预先发布消息,核实消息细节. 犯罪时,您也可使用此程序通知。
- 电子邮件工作流程钩: 此类钩子包含在使用电子邮件补丁时采取的行动. Linux内核等项目使用电子邮件方法提交并审查补丁. 这些与承诺钩类似,但可以被负责应用所提交代码的维护者使用.
- 其他:其他客户端-侧钩子包括合并时执行的钩子,检查出代码,再定位,重写,并打扫重置.
- 服务器移动 钩子: 这些钩被执行在用来接收推力的服务器上. 一般来说,这是一个项目的主要收益。 Chacon再次将这些分类分为:
- 接收前和接收后: 在接受推力的服务器上执行这些功能,以检查项目是否符合要求,并在推后部署。
- 最新情况 : 这就像一个预收,但逐个分支运作,在每个分支被接受之前执行代码. (英语)
这些分类有助于获得您可选设置链接的事件的一般想法,但要真正了解这些项目是如何工作的,最好尝试并找出您正在尝试实施的解决方案。
按参数观看 Hooks
某些也需要参数,这意味着当git为调用脚本时,它会传输一些相关数据,该脚本可以用来完成任务。
被"描述"所引用的"虎克"名称被"描述"所引用的"描述"参数(数量和描述)"被"描述"所引用的"描述"可以编辑承诺信息文件并经常被用于验证或积极将补丁信息格式化为项目标准. 非零退出状态中止承诺。 {{} (1) 包含拟议承诺消息的文件名称{}_
}}\\ 申请前 {}git am'}{} 这实际上叫做_after_ 此补丁被应用, 但 _ 在_ 更改被执行之前 。 以非零状态退出将使变化处于未承诺状态。 可用于在实际执行更改前检查树的状态 。 __(无) _ __ 申请后 __________________________ 此钩在补丁被应用并被承诺后运行. 因此,它不能中止进程,并且主要用于创建通知。 QQ( 无)_ _++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 这个钩子在获得拟议承诺信息之前被调用. 除"零"外的退出会中止承诺. 它用来检查承诺本身(而不是信件). QQ (无) _ 准备-承诺- msg QQ
git 承诺' , 在收到默认承诺信息之后, 即发射承诺信息编辑器之前发出。 非零退出中止承诺 。 用于编辑无法被压制的信息。 {{{}1至3} 与承诺信息有关的文件名称、承诺信息的来源(消息'、
更新'、相接'、
平地'或承诺'),以及SHA-1(在对现有承诺进行操作时)。 _ _ _ 承诺- msg +
git 承诺' 可用于编辑后调整消息,以确保符合标准或根据任何标准拒绝。 如果它以非零值退出, 它可以中止承诺 。 @ @ info (1) 持有拟议信件的文件。_
后承诺 {}git progress ' }}在实际做出承诺后打电话。 因此,它不能破坏承诺。 它主要用于允许通知。 QQ (无)_ _+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 主要用于在不可取的情况下停止再基. ++ (1或2) 从被加固地的上游,分支被再基(在重新加固电流时没有设置) ++ ( +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 更新工作树后或
git Clone后, 调用检票时运行 。 它主要用于验证条件,显示差异,并在必要时配置环境. QQ (3) 参考上届总部, 参考新总部, 标出旗号, 显示它是分支的检出 (1) 还是文件检出 (0) _ _ _ 后相接 * *
git 合并' 或git pull' 合并后打电话来。 因此,它不能中止合并。 可用于保存或应用权限或git不处理的其他类型数据. XQ (1) 标出合并是否为壁球的旗帜。 _ _+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 除参数外,以空格相隔的附加信息会以""地上回想""地上回想""地上回想""地上回想""地上回想""地上回想""地上回想""地上回想""地上回想""地上回想"地上回想""地上回想"地上回想"地上回想"地上回想"地上回想"地上回想"地上回想"地上回想"地上回想"地上回想"地上回想"地上回想"地上回想"地上回想"地上回想"地上回想"地上回想"地上回想"地上回想". 解析输入可以获取额外信息,用于检查. 例如,如果本地sha1为40个零长,推取就是删除;如果远程sha1为40个零长,则是一个新的分支. 这可用于对当前情况进行许多比较。 非零退出状态中止了推动 。 @ info (2) 目的地遥控器名称、目的地遥控器位置_ ___在远程回取器上预收QQ
git-receive-pack ' 这在更新被推取的回取器之前已调取。 非零状态会中止这一过程. 虽然它没有获得参数,但以"<旧值><新值>< ref-name>"的形式通过 stdin通过字符串传递给每个 ref. {(无)}}
}}}}在远程 repo上更新 }} git-receive-pack' 这在远程 Repo上运行一次,每次推出每个 repo,而不是每次推出一次. 非零状态会中止这一过程. 例如,这可以用来确保所有承诺只是快速向前。 (3) 正在更新的 ref 名称,旧对象名称,新对象名称_ ___ 在远程 repo上接收后 QQ
git-receive-pack' 当所有 ref 更新后,此在远程上运行 。 它不取参数,而是以"<旧值><新值>git-receive-pack> 这只运行一次, 在所有 refs 被推后。 在这方面,它与接收后钩类似,但不接受新旧价值观。 它主要用于执行被推回人的通知。 每一个被推回的回放都有一个参数,其中包含它的名称为:_ _+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 当 git 命令正在重写已承诺的数据时, 就会叫它 。 除参数外,它还以""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" (1) 援引该命令的指挥部名称(
修正'或`基地')
与Git Hooks相关的环境变量
在你可以开始你的脚本之前,你需要了解一些关于什么环境变量 git 设置时调用. 要让你的脚本工作,你最终需要取消一个环境变量, git 设置时调用后委托
。
这是一个非常重要的内化点,如果您希望写出可靠的 git hooks,Git 会设置不同的环境变量,取决于哪个hook 被调用。
与此相关的第一个问题是,如果您不知道什么变量被自动设置,它可以使您的脚本环境非常不可预测,第二个问题是,设置的变量几乎完全不在git自己的文档中。
幸运的是,Mark Longair在运行这些链接时开发了(http://longair.net/blog/2011/04/09/missing-git-hooks-documentation/)测试 git 设置的每个变量的方法,其中包括将以下内容放入各种 git 链接脚本中:
1[environment local]
2#!/bin/bash
3echo Running $BASH_SOURCE
4set | egrep GIT
5echo PWD is $PWD
他的网站上的信息是从2011工作Git版本 1.7.1,所以已经有一些变化,这个指南是使用Ubuntu 20.04与Git 2.25.1
在此版本的 git 上测试的结果如下(包括在运行每个链接时通过 git 看到的工作目录)。测试的本地工作目录是 /home/sammy/test_hooks
,而空的远程目录(必要时)是 /home/sammy/origin/test_hooks.git
:
*** 用户**:应用patch-msg'、
应用前patch-msg'、应用后patch- -**环境变量**: -
GIT_AUTHOR_DATE='蒙,2014年8月11日 11:25:16-0400'
-[email protected] -
GIT_AUTHOR_NAME=Sammy用户'-
GETTEXT_SH-SHINTNU'-MKBRBR1-FLOG_ACTION'-am-MKBRBR1_** 工作目录**:`/home/sanmy/test_hoks'
- ** 胡克**:
承诺前',
承诺后',承诺后' -** 环境变量**: -
GIT_AUTHOR_DATE'@1407774159-0400'---
- ** 书名**:
前还原' -** 环境变量**: -
GIT_INTERNAL_GETTEXT_SH_SH-SCHEME=gnu' -GIT_REFLOG-ACTION=再还原' -** 工作目录**:
家/家/ Sam/test_hooks' - ** 用户**: " 离职后 "
-环境变量:
-
GIT_DIR=.git' -
GIT_PREFIX=' -**工作目录**:
/home/sammy/test_hooks' - ** 胡克**: '后相接'
-** 环境变量**:
-
GITEAD_4b407c.' -
GIT_DIR=.git' -'GIT_INTERNAL_GETEXT_SH_SCHEME=gnu' -'GIT_PREFIX=`--' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - ** 胡克**:
前推' -** 环境变量**: -'GIT_PREFIX=
-** 工作目录**:`/home/sammy/test_hooks' - ** 胡克**:
接收前',
更新后',接收后',
更新后' -** 环境变量**: -GIT_DIR=.' -** 工作目录**:
/home/sammy/起源/test_hooks.git' - ** Hooks**:`预自发-gc' -(因难以可靠触发而不知)
- ** Hooks**:
后重写' -** 环境变量**: --
GIT_AUTHOR_DATE='@1407773551-0400' -[email protected]' -
GIT_AUTHOR_NAME=Sammy用户' -GIT_DIR=.git'- -
GIT_PREFIX=-----'-**工作目录**:
家/家/家/家/家/家/家/家/家/家口-家口' (英语)
这些变量对 git 如何看待其环境有影响. 您将使用上述有关变量的信息来确保您的脚本正确考虑其环境。
现在你有所有这些一般信息,你可以展示如何在几个场景中实现这些。
创建一个存储库
要开始,您将在您的主目录中创建一个新的、空的存储库,您可以称之为proj
。
1[environment local]
2mkdir ~/proj
3cd ~/proj
4git init
1[secondary_label Output]
2Initialized empty Git repository in /home/sammy/proj/.git/
对于本指南的其余部分,根据需要,用您的用户名取代 sammy。
现在,你是在一个 git 控制的目录的空白工作目录. 在你做任何其他事情之前,跳入这个目录中的隐藏文件中存储的存储库,名为 .git
:
1[environment local]
2cd .git
3ls -F
1[secondary_label Output]
2branches/ config description HEAD hooks/ info/ objects/ refs/
您将看到一些文件和目录. 您感兴趣的目录是hooks
目录:
1[environment local]
2cd hooks
3ls -l
1[secondary_label Output]
2total 40
3-rwxrwxr-x 1 sammy sammy 452 Aug 8 16:50 applypatch-msg.sample
4-rwxrwxr-x 1 sammy sammy 896 Aug 8 16:50 commit-msg.sample
5-rwxrwxr-x 1 sammy sammy 189 Aug 8 16:50 post-update.sample
6-rwxrwxr-x 1 sammy sammy 398 Aug 8 16:50 pre-applypatch.sample
7-rwxrwxr-x 1 sammy sammy 1642 Aug 8 16:50 pre-commit.sample
8-rwxrwxr-x 1 sammy sammy 1239 Aug 8 16:50 prepare-commit-msg.sample
9-rwxrwxr-x 1 sammy sammy 1352 Aug 8 16:50 pre-push.sample
10-rwxrwxr-x 1 sammy sammy 4898 Aug 8 16:50 pre-rebase.sample
11-rwxrwxr-x 1 sammy sammy 3611 Aug 8 16:50 update.sample
首先,你可以看到这些文件中的每一个都标记为可执行的,因为这些脚本只是以名称命名,它们必须是可执行的,他们的第一个行必须是 shebang 魔法号码引用来调用正确的脚本解释器。最常见的是,这些脚本语言如 bash, perl, python等。
您可能注意到的第二件事是,所有的文件都结束在.sample. 这是因为 git 只是在试图找到要执行的链接文件时查看文件名。 偏离 git 正在寻找脚本的名称基本上会禁用脚本。 为了启用本目录中的任何脚本,您将不得不删除.sample 的附加字符。
第一個例子:部署到本地 Web 伺服器,使用後委任
您的第一个例子将使用订单后
链接来向您展示如何部署到本地Web服务器,每次订单发生时,这不是您在生产环境中使用的链接,但它允许我们展示一些重要的,几乎没有文件的项目,您应该知道使用链接时。
首先,您将安装Apache Web 服务器来演示:
1[environment local]
2sudo apt-get update
3sudo apt-get install apache2
为了让你的脚本在/var/www/html
中修改网页根(这是Ubuntu 20.04上的文档根,根据需要进行修改),你需要有写权。
1[environment local]
2sudo chown -R `whoami`:`id -gn` /var/www/html
现在,在您的项目目录中,创建一个index.html
文件:
1[environment local]
2cd ~/proj
3nano index.html
在里面,你可以添加一点HTML来证明这个想法,这不一定是复杂的:
1[label index.html]
2<h1>Here is a title!</h1>
3
4<p>Please deploy me!</p>
添加新文件,告诉 git 跟踪文件:
1[environment local]
2git add .
现在, before you commit, you are going to set up your post-commit
hook for the repository. 在项目的 .git/hooks
目录中创建此文件:
1[environment local]
2nano .git/hooks/post-commit
由于git hooks是标准脚本,你需要告诉git使用bash,从 shebang 开始:
1[environment local]
2#!/bin/bash
3unset GIT_INDEX_FILE
4git --work-tree=/var/www/html --git-dir=$HOME/proj/.git checkout -f
在下一行中,您需要仔细观察设置的环境变量,每次调用后委托
链接时。
此路径与工作目录有关,在这种情况下是 /var/www/html
. 由于 git 索引在这个位置不存在,如果您将其留在状态下,脚本将失败。
之后,你只会使用Git本身,在委托后将最新版本的存储库卸载到你的Web目录中,你会想强迫这个交易,以确保每次都成功。
完成这些更改后,保存并关闭文件。
由于这是一个常规的脚本文件,您需要使其可执行:
1[environment local]
2chmod +x .git/hooks/post-commit
现在,您终于准备好对 git repo 进行更改,确保您回到正确的目录中,然后进行更改:
1[environment local]
2cd ~/proj
3git commit -m "here we go..."
现在,如果您在浏览器中访问您的服务器的域名或 IP 地址,您应该看到您创建的 index.html 文件:
1http://server_domain_or_IP
正如您所看到的,您最近的更改在 commit 时自动被推到 Web 服务器的文档根中,您可以做一些额外的更改,以显示它在每个 commit 上工作:
1[environment local]
2echo "<p>Here is a change.</p>" >> index.html
3git add .
4git commit -m "First change"
当您更新浏览器时,您应该立即看到您应用的新更改:
正如您所看到的,这种类型的设置可以使局部测试更改变得更容易,但是,您几乎从不希望在生产环境中发布订单。
使用 Git Hooks 部署到单独的生产服务器
在下一个示例中,您将展示更新生产服务器的更好的方法. 您可以使用推送部署模型来更新您的 Web 服务器,每当您推到空格 git 存储库时。
在您的生产机器上,您将设置另一个 Web 服务器,一个你将推动更改的 bare git 存储库,以及一个 git 绑架器,每次收到推送时都会执行。
完成下面的步骤作为一个正常的用户与sudo权限。
创建生产服务器接收后钩
在生产服务器上,开始安装 Web 服务器:
1[environment second]
2sudo apt-get update
3sudo apt-get install apache2
再次,您应该将文档根的所有权授予您所操作的用户:
1[environment second]
2sudo chown -R `whoami`:`id -gn` /var/www/html
您还需要在这个机器上安装 git:
1[environment second]
2sudo apt-get install git
现在,你可以创建一个目录在你的用户的家庭目录中,以保持存储库. 然后,你可以移动到该目录,并初始化一个空的存储库. 空的存储库没有一个工作目录,它是更好的服务器,你不会直接工作很多:
1[environment second]
2mkdir ~/proj
3cd ~/proj
4git init --bare
由于这是一个空白的存储库,所以没有工作目录,并且通常位于.git
中的所有文件现在都位于主目录本身。
接下来,你需要创建另一个 git 链接. 这次,你对接收后
链接感兴趣,该链接在接收一个git push
的服务器上运行。
1[environment second]
2nano hooks/post-receive
再一次,你需要通过识别你正在写的脚本类型开始。之后,你可以输入你在后委托
文件中使用的相同的支票命令,修改为在这个机器上使用路径:
1[environment second]
2#!/bin/bash
3while read oldrev newrev ref
4do
5if [[ $ref =~ .*/master$ ]];
6then
7echo "Master ref received. Deploying master branch to production..."
8git --work-tree=/var/www/html --git-dir=$HOME/proj checkout -f
9else
10echo "Ref $ref successfully received. Doing nothing: only the master branch may be deployed on this server."
11fi
12done
由于这是一个空白的存储库,所以git-dir
应该指向该Repo的顶级目录。
但是,你需要为这个脚本添加一些额外的逻辑。如果你意外地将一个测试功能
分支推到这个服务器,你不希望它被部署。
首先,你需要阅读标准输入. 对于每一个 ref 被推,三个信息(旧 rev,新 rev, ref)将被输入到脚本中,以白色空间分开,作为标准输入。
因此,现在,您将根据正在推出的内容设置三个变量。对于主分支推,ref
对象将包含一些看起来像refs/heads/master
的东西。
最后,添加一些文本,描述了哪些情况被检测到,以及采取了什么行动. 您应该添加一个else
块,以通知用户,当非主管分支成功接收时,即使该操作不会触发部署。
完成后,保存并关闭文件,但请记住,您必须使脚本可执行,以便链接工作:
1[environment second]
2chmod +x hooks/post-receive
现在,您可以在您的客户端上设置访问此远程服务器。
在您的客户端机器上配置远程服务器
回到您的客户端(开发)机器上,返回您的项目的工作目录:
1[environment local]
2cd ~/proj
在内部,将远程服务器添加为名为生产
的远程服务器。
1[environment local]
2git remote add production sammy@remote_server_domain_or_IP:proj
现在将当前的主分支推向您的生产服务器:
1[environment local]
2git push production master
如果您没有配置 SSH 密钥,您可能需要输入您的生产服务器用户的密码。
1[secondary_label Output]]
2Counting objects: 8, done.
3Delta compression using up to 2 threads.
4Compressing objects: 100% (3/3), done.
5Writing objects: 100% (4/4), 473 bytes | 0 bytes/s, done.
6Total 4 (delta 0), reused 0 (delta 0)
7remote: Master ref received. Deploying master branch...
8To [email protected]:proj
9 009183f..f1b9027 master -> master
正如您所看到的,您的接收后
链接中的文本位于命令的输出中. 如果您在 Web 浏览器中访问您的生产服务器的域名或 IP 地址,您应该看到您的项目的当前版本:
它看起来像成功地将您的代码推向生产,一旦它收到信息。
现在,是时候测试一些新的代码了,在开发机器上,你将创建一个新的分支来保存你的更改,创建一个名为test_feature
的新分支,然后通过键入来检查新的分支:
1[environment local]
2git checkout -b test_feature
你现在在测试_功能
分支工作. 尝试做一个你可能想要转移到生产的变化. 你会把它交给这个分支:
1[environment local]
2echo "<h2>New Feature Here</h2>" >> index.html
3git add .
4git commit -m "Trying out new feature"
在此时,如果您转到开发机器的 IP 地址或域名,您应该看到您的更改显示:
這是因為您的開發機器在每個委託時仍在重新部署,這個工作流程非常適合在將變更轉移到生產前進行測試。
您可以将您的test_feature
分支推到您的远程生产服务器:
1[environment local]
2git push production test_feature
你应该在输出中看到你的接收后
链接的另一个消息:
1[secondary_label Output ]
2Counting objects: 5, done.
3Delta compression using up to 2 threads.
4Compressing objects: 100% (2/2), done.
5Writing objects: 100% (3/3), 301 bytes | 0 bytes/s, done.
6Total 3 (delta 1), reused 0 (delta 0)
7remote: Ref refs/heads/test_feature successfully received. Doing nothing: only the master branch may be deployed on this server
8To [email protected]:proj
9 83e9dc4..5617b50 test_feature -> test_feature
如果你再次检查浏览器中的生产服务器,你应该看到没有什么变化,这是你所期望的,因为你推出的变化不是在主分支。
现在你已经在你的开发机器上测试了你的更改,你确定你想将这个功能纳入你的主分支机构. 你可以检查你的主
分支机构,并在你的开发机器上合并你的test_feature
分支机构:
1[environment local]
2git checkout master
3git merge test_feature
现在,您已经将新功能合并到主分支中,推向生产服务器将部署您的更改:
1[environment local]
2git push production master
如果您查看您的生产服务器的域名或IP地址,您将看到您的更改:
使用此工作流程,您可以有一个开发机器,它将立即显示任何承诺的更改。
结论
如果你已经跟踪到现在为止,你应该能够看到Git Hooks可以帮助自动化一些任务的不同方式,它们可以帮助你部署你的代码,或者通过拒绝不合规的更改或委托消息来帮助你维持质量标准。
虽然 git hooks 的实用性是难以争辩的,但实际的实施可能很难理解和令人沮丧,以便解决问题。练习实施各种配置,实验分析论点和标准输入,并跟踪 git 如何构建hooks 的环境,在教你如何写有效的hooks 方面会走很长的路。
要开始使用 git 来贡献项目,请参阅 如何贡献开源:开始使用 Git或如果您有兴趣使用 git 的更多方法,请尝试 如何使用 Git:参考指南。