【转载】配置git hook部署项目代码

git 的教程可以查看廖雪峰老师的官网:https://www.liaoxuefeng.com/wiki/896043488029600,讲解的非常详细也非常好,基本可以满足正常的工作需求使用。

基本流程就是:

1、新建本地开发分支(比如 yangzhenhua 分支),提交也是提交的开发分支。

2、本地测试无问题之后合并到 master 分支。

3、然后 git push origin master 分支到 git 服务器。

4、服务器钩子自动 git pull origin master 分支到项目目录。

这样我们就在 yangzhenhua 分支工作开发,然后提交也可以提交到 yangzhenhua 分支上,因为服务器钩子虽然是本地提交才会触发,但是钩子是更新的 master 分支,所以提交开发分支并不会影响生产环境项目目录,什么时候想上线了,直接本地分支合并到 master 分支然后 git push origin master 分支就可以了。

准备工作

1、服务器端安装 git

1
2
[root@localhost ~]# yum install git
[root@localhost ~]# git version

2、客户端安装 git

我是 windows 环境直接在https://git-scm.com/downloads下载客户端安装,然后使用 Git Bash 作为命令行客户端。安装完成后可以查看下 git 版本。

1
2
$ git version
git version 2.9.2.windows.1

搭建 git 服务器

1、服务器端创建 git 用户来管理 git 服务

1
2
3
4
5
6
7
8
[root@localhost ~]# id git
id: git: no such user
[root@localhost ~]# useradd git
[root@localhost ~]# passwd git
New password:
BAD PASSWORD: The password contains the user name in some form
Retype new password:
passwd: all authentication tokens updated successfully.

2、创建证书登录

1
2
3
4
5
[root@localhost ~]# cd /home/git/
[root@localhost git]# sudo -u git mkdir .ssh
[root@localhost git]# chmod 700 .ssh/
[root@localhost git]# sudo -u git touch .ssh/authorized_keys
[root@localhost git]# chmod 600 .ssh/authorized_keys

3、服务器端创建 git 服务器

1
2
3
4
5
6
7
8
9
10
11
[root@localhost ~]# mkdir -p /home/data/git/gittest.git
[root@localhost ~]# git init --bare /home/data/git/gittest.git/
Initialized empty Git repository in /home/data/git/gittest.git/
[root@localhost home]# cd /home/data/git/
[root@localhost git]# ll
总用量 4
drwxr-xr-x 7 root root 4096 5月 9 01:17 gittest.git
[root@localhost git]# chown -R git:git gittest.git/
[root@localhost git]# ll
总用量 4
drwxr-xr-x 7 git git 4096 5月 9 01:17 gittest.git

我们默认设置 /home/data/git/gittest.git 为 git 仓库,当我们执行完 git init –bare /home/data/git/gittest.git/ 命令时,git 就会创建一个裸仓库,裸仓库没有工作区,因为服务器上的 git 仓库只是为了共享,所以不让用户直接登录到服务器上去改工作区,并且服务器上的 git 仓库通常都以 .git 结尾,然后把权限改为 git

客户端 clone 远程仓库

1、客户端开发目录下打开你的 Git Bash 终端克隆远程仓库

1
2
3
4
5
6
7
8
9
$ git clone git@192.168.160.130:/home/data/git/gittest.git www.yanghaihua.com
Cloning into 'gittest'...
The authenticity of host '192.168.160.130 (192.168.160.130)' can't be established.
ECDSA key fingerprint is SHA256:r1PfMrvkpc+X/Cqef9As7RvLix8kXZ2dyAfYmkDsDds.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.160.130' (ECDSA) to the list of known hosts.
git@192.168.160.130's password:
warning: You appear to have cloned an empty repository.
Checking connectivity... done.

当链接第一次链接到 git 服务器时会有一个提示 …(yes/no) 选择 yes,此时在你的 .ssh 多出来一个 known_hosts 文件

2、客户端创建 ssh 公钥和私钥

1
$ ssh-keygen -t rsa -C 'xxxxxx'

-t:指定要创建的密钥类型,可以使用:”rsa1”(SSH-1) “rsa”(SSH-2) “dsa”(SSH-2)

-C:一个注释

然后敲击两次回车就可以了,因为我这里已经有了,所以就创建了。执行完成后会在你的用户家目录 .ssh 文件夹中出现 id_rsa (私钥) id_rsa.pub (公钥)。这样一个空的仓库就完成了,然后我们把项目迁移到这个空仓库中。(如果已经有就不要创建了,直接使用就好,如果没有就创建)

3、客户端测试 git 是否配置成功

1
2
3
4
5
$ ll
total 1
-rw-r--r-- 1 Administrator 197121 11 五月 8 18:34 readme.txt
$ cat readme.txt
version.1.0

这里为了测试,我在仓库目录中只新建了一个 readme.txt 文件,然后内容是 version.1.0

4、客户端提交项目

1
2
3
4
5
6
7
8
9
10
$ git add .
$ git status
$ git commit -m 'version.1.0'
$ git push origin master
git@192.168.160.130's password:
Counting objects: 3, done.
Writing objects: 100% (3/3), 224 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@192.168.160.130:/home/data/git/gittest.git
* [new branch] master -> master

这里就是平时开发时候的正常提交流程。输入密码,然后提交成功。这时候是需要输入密码的,因为我们没有将本地的公钥导入到 /home/git/.ssh/authorized_keys 这个文件中。

5、客户端导入公钥到服务器端实现免密提交

1
2
3
4
5
6
7
8
9
10
11
$ cat readme.txt
version.1.0
version.1.1
$ git add .
$ git commit -m 'version.1.1'
$ git push origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 260 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@192.168.160.130:/home/data/git/gittest.git
8c49f3d..5501923 master -> master

将客户端中的公钥导入 /home/git/.ssh/authorized_keys 文件中,公钥就在我们家目录中的 .ssh/id_rsa.pub 文件中。然后我们再次修改 readme.txt 文件,增加一行 version1.1 字符串,然后再次提交测试。(这里就不做测试了,配置好后就可以实现免密使用 git 了)

服务器端 clone 仓库(基本流程和客户端差不多)

1、服务器端克隆仓库

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost ~]# cd /home/wwwroot/
[root@localhost wwwroot]# sudo -u www git clone git@127.0.0.1:/home/data/git/gittest.git/ www.yanghaihua.com
正克隆到 'www.yanghaihua.com'...
The authenticity of host '127.0.0.1 (127.0.0.1)' can't be established.
ECDSA key fingerprint is e4:5a:53:73:8a:03:6b:5f:f7:2f:67:38:3c:a1:b3:b3.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '127.0.0.1' (ECDSA) to the list of known hosts.
git@127.0.0.1's password:
remote: Counting objects: 10, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 10 (delta 1), reused 0 (delta 0)
接收对象中: 100% (10/10), done.
处理 delta 中: 100% (1/1), done.

假设我们的项目都放在 /home/wwwroot/ 目录下,这里我们用 www 权限来 clone 版本库,因为我们的项目运行权限都是 www 运行权限。

2、服务器端生成 ssh 公钥和私钥

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[root@localhost .git]# sudo -u www ssh-keygen -t rsa -C "server@163.com"  
Generating public/private rsa key pair.
Enter file in which to save the key (/home/www/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/www/.ssh/id_rsa.
Your public key has been saved in /home/www/.ssh/id_rsa.pub.
The key fingerprint is:
50:14:cd:b2:ff:0b:48:f3:a4:f0:b7:a8:6d:03:e4:af server@163.com
The key's randomart image is:
+--[ RSA 2048]----+
| .++ |
| .. o |
| . o |
| ... |
| o. S.. |
| o+ *. |
| o+ +. |
| .+o o. |
| E+o.. .. |
+-----------------+

3、服务器端测试 git 是否正常

1
2
3
[root@localhost www.yanghaihua.com]# sudo -u www git pull
git@127.0.0.1's password:
Already up-to-date.

正常使用,需要输入密码,导入公钥到服务器端 /home/git/.ssh/authorized_keys 文件中。

4、服务器端导入公钥到 /home/git/.ssh/authorized_keys 文件中实现免密

1
2
[root@localhost www.yanghaihua.com]# sudo -u www git pull
Already up-to-date.

到这里服务器仓库就配置好了,因为这个仓库是项目目录不需要提交和修改,只需要等下配置好钩子之后 git pull 就可以了。

服务器端配置钩子

先看看官网怎么定义:和其它版本控制系统一样,git 能在特定的重要动作发生时触发自定义脚本。有两组这样的钩子:客户端的和服务器端的。客户端钩子由诸如提交和合并这样的操作所调用,而服务器端钩子作用于诸如接收被推送的提交这样的联网操作。 你可以随心所欲地运用这些钩子。https://www.git-scm.com/book/zh/v2/自定义-Git-Git-钩子

1、配置钩子

1
2
3
4
5
6
7
8
9
[root@localhost www.yanghaihua.com]# cd /home/data/git/gittest.git/hooks
[root@localhost hooks]# sudo -u git vim post-receive
#!/bin/sh

cd /home/wwwroot/www.yanghaihua.com
unset GIT_DIR

git config --list
sudo -u www git pull origin master

钩子其实就是一个 shell 脚本,在客户端提交或者推送的时候调用它,上面的配置大概就是进入项目目录,然后使用 www 用户更新项目到项目目录,就是这么简单的一个配置,客户端修改代码,服务端只做更新不做任何修改。

2、修改钩子权限

1
[root@localhost hooks]# chmod u+x post-receive

3、测试钩子是否可以正常运行

1
2
3
4
5
6
7
8
9
10
11
[root@localhost hooks]# sudo -u git ./post-receive 
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
remote.origin.url=git@127.0.0.1:/home/data/git/gittest.git/
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
branch.master.remote=origin
branch.master.merge=refs/heads/master
[sudo] password for git:
git 不在 sudoers 文件中。此事将被报告。

因为这个钩子是 git 用户在运行,所以我们要用 git 用户身份来测试,测试过程中发生错误,因为在 sudoers 文件中 git 用户没有这个权限,我们 visudo 编辑下这个文件

4、增加 git sudo 权限,在 root 这一行下面增加

1
2
root    ALL=(ALL)       ALL
git ALL=(ALL) NOPASSWD:ALL #NOPASSWD 执行时免密

5、再次测试

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost hooks]# sudo -u git ./post-receive 
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
remote.origin.url=git@127.0.0.1:/home/data/git/gittest.git/
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
branch.master.remote=origin
branch.master.merge=refs/heads/master
来自 127.0.0.1:/home/data/git/gittest
* branch master -> FETCH_HEAD
Already up-to-date.

钩子配置成功,在上面钩子文件中,我们使用了 www 用户权限执行了 git push origin master 命令,是因为我们的项目是用的 www 权限执行的,但是 git 的钩子操作是用的 git 权限来操作的,如果不用 www 权限,那么钩子更新下来的文件权限就是 git 权限,所以为了保证 nginx 下项目目录运行权限是 www 用户,我们加上了 sudo -u www xxxxxx 来操作。这里基本就完成了,我们可以测试下整体流程操作。

测试

1、客户端提交代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ cat readme.txt
version.1.0
version.1.1
version.1.2
$ git add .
$ git commit -m 'version.1.2'
$ git push
Counting objects: 3, done.
Writing objects: 100% (3/3), 263 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: core.repositoryformatversion=0
remote: core.filemode=true
remote: core.bare=false
remote: core.logallrefupdates=true
remote: remote.origin.url=git@127.0.0.1:/home/data/git/gittest.git/
remote: remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
remote: branch.master.remote=origin
remote: branch.master.merge=refs/heads/master
remote: sudo:抱歉,您必须拥有一个终端来执行 sudo
To git@192.168.160.130:/home/data/git/gittest.git
13b9970..990b6ee master -> master

再次修改 readme.txt 文件,增加一行 version.1.2 字符串,然后提交的后看 git 的反馈,说明提交已经成功,但是调用钩子的时候报错了,需要一个终端来执行 sudo,解决办法就是编辑 /etc/sudoers 文件:

2、修改 /etc/sudoers 文件

1
2
3
4
5
6
7
8
9
10
11
[root@localhost ~]# visudo
.
.
.
Defaults requiretty
改为:
#Defaults requiretty #表示不需要控制终端

Defaults requiretty
改为:
Defaults:git !requiretty #表示仅git用户不需要控制终端(我使用的这个)

3、再次提交测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ cat readme.txt
version.1.0
version.1.1
version.1.2
version.1.3
$ git add .
$ git commit -m 'version.1.3'
$ git push
Counting objects: 3, done.
Writing objects: 100% (3/3), 265 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: core.repositoryformatversion=0
remote: core.filemode=true
remote: core.bare=false
remote: core.logallrefupdates=true
remote: remote.origin.url=git@127.0.0.1:/home/data/git/gittest.git/
remote: remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
remote: branch.master.remote=origin
remote: branch.master.merge=refs/heads/master
remote: 来自 127.0.0.1:/home/data/git/gittest
remote: * branch master -> FETCH_HEAD
remote: 更新 8d17b41..ab39eb6
remote: Fast-forward
remote: readme.txt | 3 ++-
remote: 1 file changed, 2 insertions(+), 1 deletion(-)
remote: --钩子拉取项目成功--
To git@192.168.160.130:/home/data/git/gittest.git
8d17b41..ab39eb6 master -> master

再次修改 readme.txt 文件,增加一行 version.1.3 字符串,然后再次提交。钩子中的命令都已经执行。接下来看下服务器端项目目录是否正常。

3、查看服务端 readme.txt 文件

1
2
3
4
5
[root@localhost www.yanghaihua.com]# less readme.txt 
version.1.0
version.1.1
version.1.2
version.1.3

4、禁用服务端 git 用户 shell 登录

1
2
3
4
5
[root@localhost ~]# vi /etc/passwd
.
.
.
git:x:1001:1001::/home/git:/usr/bin/git-shell

这样 git 用户就可以正常通过 ssh 使用 shell,但是不可以登录 shell。到这里使用 git 提交,然后服务器端钩子更新代码到项目目录就基本上行完成了。

基本大致流程就是客户端 push 到服务器,然后服务器再用钩子 pull 到项目目录,服务器端只做更新而不做任何的修改和提交。主要就是权限的分配和分支的开发。开发一定要新建一个分支,然后没有问题之后再合并到主分支,然后再 push 到服务器上,否则如果直接提交的 master 分支就会直接到被钩子更新到项目目录了。

这只是一个简单的部署流程,中间还有很多细节问题需要我们去配置和探索。

转载于:https://www.yanghaihua.com/content/2019-04-09/1033.shtml