5. Git, Github, Gitlab
1. 实验环境
CentOS 7
----------------------------------
Gitlab - 10.0.0.237 2G
Jenkins - 10.0.0.227 2G
SonarQube - 10.0.0.217
Nginx-LB - 10.0.0.207
CentOS 8
WebSrv-1 / developer-1 - 10.0.0.81 512MB
WebSrv-2 / developer-2 - 10.0.0.82 512MB
----------------------------------
2. Git基本操作
2.1 git安装
CentOS 8
开发机-1 - 10.0.0.81
[root@developer-1 ~]#yum -y install git
2.2 配置git的用户名和邮箱
[root@developer-1 ~]#git config --global user.name "developer-1"
[root@developer-1 ~]#git config --global user.email "953260716@qq.com"
[root@developer-1 ~]#git config --global color.ui true
2.3 验证git配置
- 配置用户名和密码后, 会在对应的用户的家目录下生成.gitconfig文件, 保存配置信息
- 用哪个Linux用户执行的git config --global 命令, 就会在对应的用户家目录下生成.gitconfig文件
[root@developer-1 ~]#cat .gitconfig
[user]
name = developer-1
email = 953260716@qq.com
[color]
ui = true
2.4 创建本地git仓库
[root@developer-1 ~]#mkdir demo # 创建一个项目目录, 用作本地git仓库
[root@developer-1 ~]#cd demo
[root@developer-1 ~/demo]#git init # 进入到项目目录, 初始化该目录为git仓库
Initialized empty Git repository in /root/demo/.git/
[root@developer-1 ~/demo]#ls .git/ #初始化后会生成.git目录, ,包含多个仓库目录和文件
branches config description HEAD hooks info objects refs
2.5 代码的提交, 修改和比对
实战1: 将本地文件, 提交到本地git仓库
- 创建项目文件
[01:21:16 root@developer-1 ~/demo]#ls
[01:21:41 root@developer-1 ~/demo]#touch file{1..3}
[01:21:47 root@developer-1 ~/demo]#ls
file1 file2 file3
[01:21:49 root@developer-1 ~/demo]#git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
file1
file2
file3
nothing added to commit but untracked files present (use "git add" to track)
# 这里显示有三个没有被追踪的文件, 需要通过git add命令去把文件提交到暂存区, 之后才能提交到本地仓库
- 将项目文件提交到暂存区
[01:21:52 root@developer-1 ~/demo]#git add .
[01:22:38 root@developer-1 ~/demo]#git status # 执行git add提交到暂存区后, 会提示哪些文件还没有被commit
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: file1
new file: file2
new file: file3
- 将暂存区中的文件, 提交到本地仓库, 只有在git commit之后, git才会对文件进行版本的管理
- 一旦执行了git commit, 那么git就会时刻追踪本地工作目录下的文件, 无论增删改都会被git追踪
[01:22:40 root@developer-1 ~/demo]#git commit -m "新增file1,file2,file3"
[master (root-commit) bfd4622] 新增file1,file2,file3
3 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file1
create mode 100644 file2
create mode 100644 file3
# 第一次提交, 文件内容是空的, 没有增加, 也没有删除
[01:24:25 root@developer-1 ~/demo]#git status
On branch master
nothing to commit, working tree clean
# git commit后, 没有文件需要提交
实战2: 将修改后的文件提交到本地仓库
[01:24:29 root@developer-1 ~/demo]#echo "file1-v111" > file1
[01:25:09 root@developer-1 ~/demo]#git add .
[01:25:13 root@developer-1 ~/demo]#git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: file1
[01:25:16 root@developer-1 ~/demo]#git commit -m "修改file1, 添加file1-v111"
[master 033ca27] 修改file1, 添加file1-v111
1 file changed, 1 insertion(+)
# 再次提交到本地仓库, 此时本地仓库包含了两个版本的file1, 分别是第一次提交的空文件和第二次提交的新文件
[01:26:54 root@developer-1 ~/demo]#git status
On branch master
nothing to commit, working tree clean
实战3: 将文件改名, 并重新提交到本地仓库
方法1: 手动mv, git rm, git add
[00:28:51 root@developer-1 ~/demo]#mv file1 file
[01:27:51 root@developer-1 ~/demo]#git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: file1 # 改名后, git会先把file1删除, 再创建file文件, 本身的内容是保留的
Untracked files:
(use "git add <file>..." to include in what will be committed)
file
no changes added to commit (use "git add" and/or "git commit -a")
- 先git rm删除源文件
[01:27:55 root@developer-1 ~/demo]#git rm file1
rm 'file1'
- 再git add把新的文件名添加到暂存区
[01:29:13 root@developer-1 ~/demo]#git add .
[01:29:31 root@developer-1 ~/demo]#git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
renamed: file1 -> file
- git commit提交
[01:29:34 root@developer-1 ~/demo]#git commit -m "将file1重命名为file"
[master b14f472] 将file1重命名为file
1 file changed, 0 insertions(+), 0 deletions(-)
rename file1 => file (100%)
方法2: 使用git mv命令
[01:30:11 root@developer-1 ~/demo]#ls
file file2 file3
[01:30:30 root@developer-1 ~/demo]#cat file
file1-v111
[01:30:36 root@developer-1 ~/demo]#git mv file file1
[01:30:41 root@developer-1 ~/demo]#git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
renamed: file -> file1
[01:30:43 root@developer-1 ~/demo]#ls
file1 file2 file3
[01:31:02 root@developer-1 ~/demo]#git add file1 # 通过git mv修改文件名, 无需执行git add, 可以省略
[01:31:19 root@developer-1 ~/demo]#git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
renamed: file -> file1
[00:31:27 root@developer-1 ~/demo]#git commit -m "将file改回file1"
[master 1385211] 将file改回file1
1 file changed, 0 insertions(+), 0 deletions(-)
rename file => file1 (100%)
[00:31:44 root@developer-1 ~/demo]#git status
On branch master
nothing to commit, working tree clean
实战4: 如何对比本地工作目录文件内容, 暂存区文件内容, 本地仓库文件内容之间的差异?
本地工作目录和暂存区的file1文件比对
[01:31:33 root@developer-1 ~/demo]#git diff file1
# 直接执行git diff file1, 没有任何输出, 因为此时, 本地目录, 暂存区和本地仓库的file1的文件内容是一致的
- 修改本地目录file1内容
[01:32:34 root@developer-1 ~/demo]#echo "file-change" >> file1
[01:33:26 root@developer-1 ~/demo]#cat file1
file1-v111
file-change
[01:33:53 root@developer-1 ~/demo]#git diff file1
diff --git a/file1 b/file1
index 0fbd08c..20b5001 100644
--- a/file1 # 表示变更前的版本
+++ b/file1 # 表示变更后的版本
@@ -1 +1,2 @@
file1-v111
+file-change # 表示变更的内容, 新增加了file1.chanage
- 将本地内容提交到暂存区
[01:33:54 root@developer-1 ~/demo]#git add .
[01:35:02 root@developer-1 ~/demo]#git diff file1
# 本地目录和暂存区的file1内容一致
暂存区的file1和本地仓库的file1文件进行比对
[01:35:48 root@developer-1 ~/demo]#git diff --cached file1
diff --git a/file1 b/file1
index 0fbd08c..20b5001 100644
--- a/file1
+++ b/file1
@@ -1 +1,2 @@
file1-v111
+file-change
# 将暂存区文件提交到本地仓库
[01:35:55 root@developer-1 ~/demo]#git commit -m "在file1添加file1-change"
[master a729559] 在file1添加file1-change
1 file changed, 1 insertion(+)
[01:36:30 root@developer-1 ~/demo]#git diff file1
[01:36:47 root@developer-1 ~/demo]#git diff --cached file1
- git diff 文件名: 比对的是本地目录下的文件和暂存区中的文件, 通过git add .使得两者一致
- git diff --cached 文件名: 比对的是暂存区的文件和本地仓库中的文件, 通过git commit -m "描述信息", 使得两者一致
实战5: 如何理解git commit操作
我们可以将git commit操作与虚拟机的快照对比. 简单来说, 每次commit相当于对文件做了次快照.
FQ: 我们知道git commit相当于对文件的快照, 那么我们如何得知该文件快照了多少次, 都修改了哪些内容呢?
- 查看历史的git commit快照操作, 在仓库目录下, 使用git log命令
[01:40:21 root@developer-1 ~/demo]#git log
commit a72955974f5020bbd886a9ca532be48409e94457 (HEAD -> master)
Author: developer-1 <953260716@qq.com>
Date: Sat Jan 2 01:36:30 2021 +0800
在file1添加file1-change
commit 6b88f157b3e074cc26552b31211bd5b4ce28cd19
Author: developer-1 <953260716@qq.com>
Date: Sat Jan 2 01:31:33 2021 +0800
修改file为file1
commit b14f472e8d2aa6f72de279bfb21ab4539f11269c
Author: developer-1 <953260716@qq.com>
Date: Sat Jan 2 01:30:11 2021 +0800
将file1重命名为file
commit 033ca27c53abddf2ea4d31e71d2d59eea0664c3f
Author: developer-1 <953260716@qq.com>
Date: Sat Jan 2 01:26:54 2021 +0800
修改file1, 添加file1-v111
commit bfd46224a762b467f31714c84d395184e8a1f0f6
Author: developer-1 <953260716@qq.com>
Date: Sat Jan 2 01:23:50 2021 +0800
新增file1,file2,file3
# 由下至上显示git commit历史, 新的commit会排在上面
[01:40:22 root@developer-1 ~/demo]#git log --oneline
a729559 (HEAD -> master) 在file1添加file1-change
6b88f15 修改file为file1
b14f472 将file1重命名为file
033ca27 修改file1, 添加file1-v111
bfd4622 新增file1,file2,file3
[01:41:02 root@developer-1 ~/demo]#git log -1 # 查看最近一次commit
commit a72955974f5020bbd886a9ca532be48409e94457 (HEAD -> master)
Author: developer-1 <953260716@qq.com>
Date: Sat Jan 2 01:36:30 2021 +0800
在file1添加file1-change
2.6 代码的回滚
实战6: 代码回滚的几种情况
如果本地工作目录修改文件错误, 想回退怎么办?
注意: 此时只是本地目录下的文件修改错误, 还没有提交到暂存区呢, 因此可以用暂存区的最近一次提交文件覆盖本地目录下错误的文件实现回滚
# 模拟清空了本地工作目录的file1文件
[01:41:30 root@developer-1 ~/demo]#> file1
[01:42:55 root@developer-1 ~/demo]#cat file1
[01:42:58 root@developer-1 ~/demo]#
[01:42:58 root@developer-1 ~/demo]#git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: file1
no changes added to commit (use "git add" and/or "git commit -a")
# 由于修改了file1, git会追踪到文件的修改
此时, 工作目录和暂存区的file1就不一样了. 可以通过暂存区的文件覆盖掉工作目录中的文件, 来实现回滚
[01:43:15 root@developer-1 ~/demo]#git diff file1
diff --git a/file1 b/file1
index 20b5001..e69de29 100644
--- a/file1
+++ b/file1
@@ -1,2 +0,0 @@
-file1-v111
-file-change
use "git checkout -- <file>..." to discard changes in working directory)
[01:44:48 root@developer-1 ~/demo]#git checkout -- file1
[01:45:16 root@developer-1 ~/demo]#git status
On branch master
nothing to commit, working tree clean
[01:45:20 root@developer-1 ~/demo]#cat file1
file1-v111
file-change
如果本地目录修改文件后, 提交到了暂存区, 发现错误, 如何回滚?
注意: 此时本地目录和暂存区是一致的, 而暂存区和本地仓库是不一致的. 因此可以通过让本地仓库中的文件覆盖暂存区的文件, 再让暂存区的文件去覆盖本地目录的文件, 以此实现回退
# 模拟清空了file1文件
[01:45:23 root@developer-1 ~/demo]#> file1
[01:46:37 root@developer-1 ~/demo]#cat file1
[01:46:38 root@developer-1 ~/demo]#
# 将空的file1, 提交到了暂存区
[01:46:38 root@developer-1 ~/demo]#git add .
[01:46:53 root@developer-1 ~/demo]#git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: file1
[01:46:56 root@developer-1 ~/demo]#git diff file1
[01:47:21 root@developer-1 ~/demo]#
(use "git reset HEAD <file>..." to unstage)
- 先使用git reset, 将本地仓库中的文件覆盖掉暂存区中的文件
# git status命令用于显示工作目录和暂存区的状态。使用此命令能看到那些修改被暂存到了, 哪些没有, 哪些文件没有被Git tracked到. git status不显示已经commit到项目历史中的信息
[01:48:57 root@developer-1 ~/demo]#git reset HEAD file1
Unstaged changes after reset:
M file1
[01:49:38 root@developer-1 ~/demo]#git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: file1
no changes added to commit (use "git add" and/or "git commit -a")
[01:50:12 root@developer-1 ~/demo]#git diff file1
diff --git a/file1 b/file1
index 20b5001..e69de29 100644
--- a/file1
+++ b/file1
@@ -1,2 +0,0 @@
-file1-v111
-file-change
- 再用git checkout -- 文件名. 将暂存区中的文件覆盖掉本地目录的文件
[01:50:28 root@developer-1 ~/demo]#git checkout -- file1
[01:50:36 root@developer-1 ~/demo]#git status
On branch master
nothing to commit, working tree clean
[01:50:40 root@developer-1 ~/demo]#cat file1
file1-v111
file-change
如果提交了多次内容到本地仓库, 想回退至某个版本怎么办?
- 先模拟多次提交
# 第一次提交
[01:50:47 root@developer-1 ~/demo]#cat file1
file1-v111
file-change
[01:55:07 root@developer-1 ~/demo]#echo "T-1111" >> file1
[01:55:23 root@developer-1 ~/demo]#git add .
[01:55:24 root@developer-1 ~/demo]#git commit -m "增加T-1111到file1"
[master 5ffbf51] 增加T-1111到file1
1 file changed, 1 insertion(+)
# 这里master后的ID就是每次提交的快照记录. commit ID, 之后如果想要退回到这个版本, 就需要找到这个commit ID做回退即可
# 第二次提交
[01:55:45 root@developer-1 ~/demo]#echo "T-2222" >> file1
[01:56:52 root@developer-1 ~/demo]#git add .
[01:56:57 root@developer-1 ~/demo]#git commit -m "增加T-2222到file1"
[master 2d4a708] 增加T-2222到file1
1 file changed, 1 insertion(+)
[01:57:25 root@developer-1 ~/demo]#cat file1
file1-v111
file-change
T-1111
T-2222
- 如何回退到只有如下内容的版本?
file1-v111
file-change
[01:57:46 root@developer-1 ~/demo]#git log --oneline
2d4a708 (HEAD -> master) 增加T-2222到file1
5ffbf51 增加T-1111到file1
a729559 在file1添加file1-change
# 这里就是我们需要回退到的状态点, commit id是a729559
6b88f15 修改file为file1
b14f472 将file1重命名为file
033ca27 修改file1, 添加file1-v111
bfd4622 新增file1,file2,file3
[01:59:07 root@developer-1 ~/demo]#git reset --hard a729559
HEAD is now at a729559 在file1添加file1-change
注意: 一旦在本地仓库发生回滚, 那么本地目录和暂存区中的相应的文件, 都会自动回滚到本地仓库的版本
[02:00:08 root@developer-1 ~/demo]#cat file1
file1-v111
file-change
[02:00:25 root@developer-1 ~/demo]#git diff file1 ; git diff --cached file1
[02:00:50 root@developer-1 ~/demo]#
此时如果想再回到T-2222的版本, 该怎么做?
注意, 此时执行git log --oneline会发现, T-1111和T-2222版本都被不显示了. 这是因为我们从版本"T-2222"回到"在file1添加file1-change"会把中间的T-1111和最后的T-2222从git log记录删除
[02:00:50 root@developer-1 ~/demo]#git log --oneline
a729559 (HEAD -> master) 在file1添加file1-change
6b88f15 修改file为file1
b14f472 将file1重命名为file
033ca27 修改file1, 添加file1-v111
bfd4622 新增file1,file2,file3
- 此时可以使用git reflog对所有的历史记录进行查询
[02:02:34 root@developer-1 ~/demo]#git reflog
a729559 (HEAD -> master) HEAD@{0}: reset: moving to a729559
2d4a708 HEAD@{1}: commit: 增加T-2222到file1
5ffbf51 HEAD@{2}: commit: 增加T-1111到file1
a729559 (HEAD -> master) HEAD@{3}: commit: 在file1添加file1-change
6b88f15 HEAD@{4}: commit: 修改file为file1
b14f472 HEAD@{5}: commit: 将file1重命名为file
033ca27 HEAD@{6}: commit: 修改file1, 添加file1-v111
bfd4622 HEAD@{7}: commit (initial): 新增file1,file2,file3
- 用git reset --hard 回退到有T-2222的版本
[02:03:20 root@developer-1 ~/demo]#git reset --hard 2d4a708
HEAD is now at 2d4a708 增加T-2222到file1
[02:03:53 root@developer-1 ~/demo]#cat file1
file1-v111
file-change
T-1111
T-2222
补充: 只要是在git reflog中显示的提交记录, 都是可以随时回退的, 并且, 在本地仓库回退后, 本地工作目录和暂存区中的内容也会自动回退到相应的版本
如何回滚部署到了生产环境服务器的代码
-
需要到生产环境服务器的项目代码目录执行
git reset --hard 版本id
进行回滚. 这样就会回滚生产环境服务器的代码到指定的版本. 不过, 开发本地的代码和gitlab上的代码是不会回滚的 -
一般代码的部署和回滚都会在Jenkins上通过shell脚本执行, 配合tag标签, 实现基于版本标签的部署和回滚
2.7 git分支原理
2.7.1 查看分支
[02:03:58 root@developer-1 ~/demo]#git branch
* master
2.7.2 创建分支
[02:05:40 root@developer-1 ~/demo]#git branch devops
[02:05:57 root@developer-1 ~/demo]#git branch
devops
* master
# 带星号的表示当前所处的分支
2.7.3 切换分支
注意: 每次切换分支, 当前Xshell打开的所有终端的分支都会一并切换
[02:05:59 root@developer-1 ~/demo]#git checkout devops
Switched to branch 'devops'
[02:06:51 root@developer-1 ~/demo]#git branch
* devops
master
由于devops分支, 是基于master创建的, 因此, 会继承master分支的文件
[02:06:56 root@developer-1 ~/demo]#ls
file1 file2 file3
2.7.4 在devops分支创建三个文件, 模拟开发完毕
[02:07:15 root@developer-1 ~/demo]#touch file{4..6}
[02:07:40 root@developer-1 ~/demo]#ls
file1 file2 file3 file4 file5 file6
[02:07:42 root@developer-1 ~/demo]#git add .
[02:07:48 root@developer-1 ~/demo]#git commit -m "添加file4 file5 file6"
[devops e310a90] 添加file4 file5 file6
3 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file4
create mode 100644 file5
create mode 100644 file6
2.7.5 合并分支
- 把master的内容合并到devops上, 因为master是一直在更新的, 因此, 要把master的东西合并到devops上
[02:08:09 root@developer-1 ~/demo]#git merge master
Already up to date. # 这时会显示up to update, 因为我们还没有对master进行更新
- 更新master分支, 添加三个文件
[02:09:03 root@developer-1 ~/demo]#git checkout master
Switched to branch 'master'
[02:09:31 root@developer-1 ~/demo]#touch file{7..9}
[02:09:38 root@developer-1 ~/demo]#git add .
[02:09:39 root@developer-1 ~/demo]#git commit -m "新建文件file7 file8 file9"
[master 5fa42e1] 新建文件file7 file8 file9
3 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file7
create mode 100644 file8
create mode 100644 file9
- 此时master分支包含文件
[02:09:52 root@developer-1 ~/demo]#git branch
devops
* master
[02:10:12 root@developer-1 ~/demo]#ls
file1 file2 file3 file7 file8 file9
- 此时devops包含文件
[02:10:13 root@developer-1 ~/demo]#git checkout devops
Switched to branch 'devops'
[02:10:44 root@developer-1 ~/demo]#ls
file1 file2 file3 file4 file5 file6
- 将master合并到devops. 注意, 一定是把master合并到devops, 因为, master上必须是可以部署的功能测试完善的代码, 如果把devops合并到master上, 那么部署代码时一定会报错
[02:12:11 root@developer-1 ~/demo]#git merge master -m "devops合并master内容"
Merge made by the 'recursive' strategy.
file7 | 0
file8 | 0
file9 | 0
3 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file7
create mode 100644 file8
create mode 100644 file9
- 此时, devop是包含了所有的文件
[02:12:30 root@developer-1 ~/demo]#git branch
* devops
master
[02:12:54 root@developer-1 ~/demo]#ls
file1 file2 file3 file4 file5 file6 file7 file8 file9
- 将master合并到devops后, 就可以进行新代码的测试. 测试完成后, 再把devops上所有的代码, 部署到master上, 这样master上就是最新的测试完的可部署的代码
[02:12:54 root@developer-1 ~/demo]#git checkout master
Switched to branch 'master'
[02:14:17 root@developer-1 ~/demo]#ls
file1 file2 file3 file7 file8 file9
[02:14:18 root@developer-1 ~/demo]#git merge devops
Updating 5fa42e1..cb70a0f
Fast-forward
file4 | 0
file5 | 0
file6 | 0
3 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file4
create mode 100644 file5
create mode 100644 file6
[02:14:32 root@developer-1 ~/demo]#ls
file1 file2 file3 file4 file5 file6 file7 file8 file9
- 此时, 如果devops分支已经完成了开发项目, 那么就可以把该分支删除
[02:14:33 root@developer-1 ~/demo]#git branch -d devops
Deleted branch devops (was cb70a0f).
[02:14:54 root@developer-1 ~/demo]#git branch
* master
2.7.6 合并时发生冲突如何解决?
- 同一个文件, 同一行的内容在master和其他分支不一致, 合并时会导致冲突
冲突演示, 和解决
- 基于当前的master, 开辟新的分支, dev
[02:14:56 root@developer-1 ~/demo]#git branch
* master
[02:17:43 root@developer-1 ~/demo]#git branch dev
[02:17:54 root@developer-1 ~/demo]#git checkout dev
Switched to branch 'dev'
[02:19:01 root@developer-1 ~/demo]#ls
file1 file2 file3 file4 file5 file6 file7 file8 file9
- 此时, 新的dev分支会保存,所有创建分支时, master中的文件
- 先在master分支中, 修改file1文件
[02:19:04 root@developer-1 ~/demo]#git checkout master
Switched to branch 'master'
[02:19:47 root@developer-1 ~/demo]#vim file1
file1-v111
file-change
T-11111111 # 修改此行, 从T-1111 >>> T-11111111
T-2222
[02:22:08 root@developer-1 ~/demo]#git add .
[02:22:24 root@developer-1 ~/demo]#git commit -m "file1 - T11111111"
[master e458c26] file1 - T11111111
1 file changed, 1 insertion(+), 1 deletion(-)
- 切换到dev分支, 检查dev中的file1文件
[02:22:27 root@developer-1 ~/demo]#git checkout dev
Switched to branch 'dev'
[02:23:07 root@developer-1 ~/demo]#cat file1
file1-v111
file-change
T-1111 # 此时, branch的file1文件没有修改, 因为是基于master未修改前的状态拉取的, 不会保留后续的更新
T-2222
- 在dev分支的file1文件, 修改过T1111 >>> T111111111111, 这样就会和master的file1的T11111111产生冲突
[02:23:10 root@developer-1 ~/demo]#vim file1
file1-v111
file-change
T-111111111111
T-2222
~
[02:24:43 root@developer-1 ~/demo]#git add .
[02:24:48 root@developer-1 ~/demo]#git commit -m "file1 - T111111111111"
[dev 76bc639] file1 - T111111111111
1 file changed, 1 insertion(+), 1 deletion(-)
- 此时, 假如开发完毕, 需要合并master上的代码, 但是由于master和dev的file1的同一行内容不同, 就会产生冲突
[02:25:04 root@developer-1 ~/demo]#git merge master
Auto-merging file1
CONFLICT (content): Merge conflict in file1
Automatic merge failed; fix conflicts and then commit the result.
- 此时查看dev分支的file1文件, 会提示冲突信息
[02:25:29 root@developer-1 ~/demo]#vim file1
file1-v111
file-change
<<<<<<< HEAD
T-111111111111
=======
T-11111111
>>>>>>> master
T-2222
- 可以把提示的HEAD和master行删除, 这样原本冲突的一行就会变成了两行, 因此就不冲突
[02:25:29 root@developer-1 ~/demo]#vim file1
file1-v111
file-change
T-111111111111
T-11111111
T-2222
- dev分支再次提交, 提交后, 就可以进行代码测试
[02:27:49 root@developer-1 ~/demo]#git add .
[02:28:21 root@developer-1 ~/demo]#git commit -m "修改file1冲突"
[dev 97c0981] 修改file1冲突
[02:28:30 root@developer-1 ~/demo]#git status
On branch dev
nothing to commit, working tree clean
- 代码测试后, 就可以把dev合并到master, 因为dev的file1文件已经是处理过冲突的, 因此合并不会有问题
[02:28:51 root@developer-1 ~/demo]#git checkout master
Switched to branch 'master'
[02:29:43 root@developer-1 ~/demo]#git merge dev
Updating e458c26..97c0981
Fast-forward
file1 | 1 +
1 file changed, 1 insertion(+)
[02:29:48 root@developer-1 ~/demo]#cat file1
file1-v111
file-change
T-111111111111
T-11111111
T-2222
注意: 在分支项目开发完毕, 准备合并master时, 一定要确保本地的master是最新的内容, 这样可以避免冲突
2.8 git标签管理
- 标签和每次commit的commitID进行绑定, 通过tag定位commitID, 定位到某个版本
- tag并不会随着commitID的变化而变化, 每次commit都需要贴单独的tag, 一般上线和回退就是基于tag
- 标签是基于分支的, 每个分支都有自己的标签
2.8.1 创建标签
- 标签一般是针对master分支
[02:30:09 root@developer-1 ~/demo]#git checkout master
Already on 'master'
[02:31:46 root@developer-1 ~/demo]#
[02:31:48 root@developer-1 ~/demo]#
[02:31:48 root@developer-1 ~/demo]#ls
file1 file2 file3 file4 file5 file6 file7 file8 file9
[02:31:50 root@developer-1 ~/demo]#git status
On branch master
nothing to commit, working tree clean
- 基于当前master的内容, 打标签
[02:31:53 root@developer-1 ~/demo]#git tag -a "v1.0" -m "项目刚刚发布, 内容:拍照"
2.8.2 查看标签
[02:32:32 root@developer-1 ~/demo]#git tag
v1.0
2.8.3 查看标签内容
[02:33:57 root@developer-1 ~/demo]#git show v1.0
tag v1.0
Tagger: developer-1 <953260716@qq.com>
Date: Sat Jan 2 02:32:32 2021 +0800
项目刚刚发布, 内容:拍照
commit 97c098177401797b907f72f7b7cc50e064554685 (HEAD -> master, tag: v1.0, dev) # 此时tag v1.0会跟该comimt号关联. 通过tag v1.0既可找到这次提交
Merge: 76bc639 e458c26
Author: developer-1 <953260716@qq.com>
Date: Sat Jan 2 02:28:30 2021 +0800
修改file1冲突
diff --cc file1
index b6a5576,ab156eb..a3a7a17
--- a/file1
+++ b/file1
@@@ -1,4 -1,4 +1,5 @@@
file1-v111
file-change
+T-111111111111
+ T-11111111
T-2222
2.8.4 如何基于某一个commit ID打标签
# 先通过git reflog查看commit记录, 确定需要打标签的commit ID
[02:34:02 root@developer-1 ~/demo]#git reflog
...
2d4a708 HEAD@{19}: commit: 增加T-2222到file1 # 假如对此次commit打标签
...
[02:37:07 root@developer-1 ~/demo]#git tag -a "b1.0" 2d4a708 -m "增加T-2222到file1"
[02:37:40 root@developer-1 ~/demo]#git tag
b1.0
v1.0
[02:38:06 root@developer-1 ~/demo]#git show b1.0
tag b1.0
Tagger: developer-1 <953260716@qq.com>
Date: Sat Jan 2 02:37:40 2021 +0800
增加T-2222到file1
commit 2d4a708fca4a762268eb7525946642608159cced (tag: b1.0)
Author: developer-1 <953260716@qq.com>
Date: Sat Jan 2 01:57:25 2021 +0800
增加T-2222到file1
diff --git a/file1 b/file1
index 56acf55..6d6c941 100644
--- a/file1
+++ b/file1
@@ -1,3 +1,4 @@
file1-v111
file-change
T-1111
+T-2222
注意: tag会和打标签时的commit ID进行永久的捆绑, 不会随着每次commit而发生变化
2.8.5 删除标签
[02:38:08 root@developer-1 ~/demo]#git tag -d 'b1.0'
Deleted tag 'b1.0' (was 09fa56d)
[02:38:37 root@developer-1 ~/demo]#git tag
v1.0
2.9 git远程仓库github
2.9.1 创建github远程仓库


2.9.2 将此前本地创建好的仓库推送到github远程仓库
- 使用https, 利用github账户和密码做认证
[root@developer-1 ~/demo]#git remote -v
[root@developer-1 ~/demo]#git remote add origin https://github.com/ChickenWinner2019/git-practice.git
[root@developer-1 ~/demo]#git push -u origin master
Username for 'https://github.com': chickenwinner2019
Password for 'https://chickenwinner2019@github.com':
Counting objects: 37, done.
Compressing objects: 100% (30/30), done.
Writing objects: 100% (37/37), 3.29 KiB | 0 bytes/s, done.
Total 37 (delta 11), reused 0 (delta 0)
remote: Resolving deltas: 100% (11/11), done.
To https://github.com/ChickenWinner2019/git-practice.git
* [new branch] master -> master
Branch master set up to track remote branch master from origin.
- 使用ssh, 基于key做认证, 需要把本机的公钥, 传到github仓库里
[root@developer-1 ~/demo]#ssh-keygen
[root@developer-1 ~/demo]#cat /root/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCtiG5NqTqVxCtEuZ9hmtkML9i30hp2V2A6OUU/TbkrxyAU+Kyd5M/spNPMdbF+VCmoZcWqt9J+t+kCFOAPzRLPa/QY3FlkhzemnjJYg5VmuV72PHtl23/Bpofbbp/9WsjaqlW3Z6gSNgEbxkrok9HIoOhfTudUJuljl0q1Sg15yYOnfgKDWgCrKIMl4v4nwY/eY4ibfbx5ObtlZKffH6KW4pBtUJLkDjNw1Bz9lyAcFLBFI/CzuubvULNN3+Ng1VXNhAApkcHyP1aIDtycsT8EuZdZsFwioK5KHwXkfIyjjrmKbifZKJi7DMt9kCqRWL6Xi6bHs0cu2+iCnudVOYvV root@git

此时, 需要删除上面创建的origin用户, 然后重新使用ssh创建远程仓库, 再把本地仓库推到远程仓库
- 删除origin用户
[root@developer-1 ~/demo]#git remote -v
origin https://github.com/ChickenWinner2019/git-practice.git (fetch)
origin https://github.com/ChickenWinner2019/git-practice.git (push)
[root@developer-1 ~/demo]#git remote remove origin
- 再重新创建远程仓库, 把本地仓库推送到远程仓库即可, 此时要使用ssh的连接
[23:13:56 root@git ~/demo]#git remote add origin git@github.com:ChickenWinner2019/git-practice.git
[23:14:27 root@git ~/demo]#git push -u origin master
2.9.10 删除远程仓库
[root@developer-1 ~/demo]#git remote -v
[root@developer-1 ~/demo]#git remote remove origin # 这里的origin是添加远程仓库时的用户名称, 通过删除origin, 就可以删除本地仓库和远程仓库的关联关系
总结:
- 如何关联远程仓库
git remote add origin URL
- 如何将本地仓库内容推送到远程仓库
注意: 推送到远程仓库之前, 一定要在本地先commit, 把文件都提交到本地仓库
git add .
git commit -m "描述"
git push -u origin master
补充1: 如果有新的开发人员加入进来怎么办?
- 先在新人的电脑上, 生成ssh公钥, 然后添加到github账户的ssh公钥里. 或者, 直接在github仓库的设置里给新人添加权限, 也就是给新员工的github账号添加权限
这里在另一台开发机上演示, 还是使用key验证的的方式, 把sshkey添加到github账户中
[23:31:52 root@centos-7-2 ~]#ssh-keygen
[23:33:25 root@centos-7-2 ~]#cat .ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDf7a7uKVZz7kWtbQB2p9eCdPtelCZyqYP75BkOJ2GzVfgu2Ihsr/iII0nXosiB3a9mClPeQJI4uwu51aGMszy+40MrP2QQTig5w6EU2EgCtlnIJr+udMP5QfX9QEroy3nCBKE6pquBmMCOxWBI2LArSyFKa6sAAxbL73lZ2vHX47sr5mE5NUyEim+yx9ywqhTI45EjzL9D8tIVqgKcr67TZYp5BSm1tvQVUnoCkCn/98FAWJW0e54FwZgdUrsEfIst7AF5E+lRG3uBpBBhppbaNCilbCOaxfl9KctAIkzby5YxTKvmcWm3itzUNzsL4VbfO5eLFcuWvwoUTdIQj48J root@centos-7-2.prac
- 新人在自己电脑上的数据目录里, git clone最新的master分支代码
- 这里clone到/data下
yum -y install git
git config --global user.name "developer-2"
git config --global user.email "anshan0810@icloud.com"
git config --global color.ui true
[23:34:37 root@centos-7-2 /data]#git clone git@github.com:ChickenWinner2019/git-practice.git
# 如果没有添加sshkey, 那么就使用https连接,https://github.com/ChickenWinner2019/git-practice.git
[23:36:48 root@centos-7-2 /data]#ls
git-practice
[23:36:51 root@centos-7-2 /data]#cd git-practice/
[23:37:04 root@centos-7-2 /data/git-practice]#ls
file1 file2 file3 file4 file5 file6 file7 file8 file9
- 新人创建了新的文件后, 如何提交?
- 先提交到本地仓库
[23:37:04 root@centos-7-2 /data/git-practice]#touch file_newuser
[23:37:32 root@centos-7-2 /data/git-practice]#git add .
[23:39:16 root@centos-7-2 /data/git-practice]#git commit -m "新用户提交了file_newuser"
- 由于新用户这次是直接从github远程仓库克隆的, 因此本地仓库和远程仓库已经做好了关联, 无需用git remote add去添加远程仓库, 直接git push把本地仓库推到远程仓库即可
[23:39:53 root@centos-7-2 /data/git-practice]#git push -u origin master

补充2: 如何查看别人提交的代码?
比如: 10.0.0.81-developer-1的用户如何查看10.0.0.82-developer-2的用户提交的代码呢? 此时, 新用户提交了代码到远程仓库, 远程仓库已经更新了, 但是10.0.0.81的用户的本地仓库还没有更新, 那么如何查看别人提交的代码?
[23:44:40 root@git /tmp]#cd /root/demo
[23:44:44 root@git ~/demo]#git branch
dev
* master
[23:44:48 root@git ~/demo]#ls
file1 file2 file3 file4 file5 file6 file7 file8 file9
- 拉取远程仓库代码到本地, 实现本地仓库更新
[23:44:50 root@git ~/demo]#git pull origin master
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 2 (delta 1), reused 2 (delta 1), pack-reused 0
Unpacking objects: 100% (2/2), done.
From https://github.com/ChickenWinner2019/git-practice
* branch master -> FETCH_HEAD
Updating 42fafd5..b79bcb3
Fast-forward
file_newuser | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file_newuser
[23:45:37 root@git ~/demo]#ls
file1 file2 file3 file4 file5 file6 file7 file8 file9 file_newuser
3 Gitlab版本控制系统
- 基于git, 由ruby语言开发
3.1 Gitlab安装
实验环境
CentOS7
10.0.0.237 - Gitlab服务器 - gitlab-ce-12.0.3
10.0.0.81 - developer-1 - 普通开发用户
10.0.0.82 - developer-2 - 组管理员
3.1.1 安装依赖包
sudo yum install -y curl policycoreutils-python openssh-server wget postfix
sudo systemctl enable sshd
sudo systemctl start sshd
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo systemctl reload firewalld
3.1.2 安装Gitlab-rpm包
[00:35:56 root@gitlab ~]#rpm -ivh gitlab-ce-12.0.3-ce.0.el7.x86_64.rpm
3.1.3 配置Gitlab服务, 访问域名和邮箱
[00:37:55 root@gitlab ~]#vim /etc/gitlab/gitlab.rb
external_url 'http://gitlab.abc.com'
### Email Settings
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.qq.com"
gitlab_rails['smtp_port'] = 465
gitlab_rails['smtp_user_name'] = "953260716@qq.com"
gitlab_rails['smtp_password'] = "fpqdpdnppgatbeih"
gitlab_rails['smtp_domain'] = "qq.com"
gitlab_rails['smtp_authentication'] = :login
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_tls'] = true
gitlab_rails['gitlab_email_from'] = "953260716@qq.com"
user["git_user_email"] = "953260716@qq.com"
3.1.4 Gitlab初始化
注意: 每次修改/etc/gitlab/gitlab.rb都需要执行gitlab-ctl reconfigure
[00:45:02 root@gitlab ~]#gitlab-ctl reconfigure
3.1.5 Gitlab启动, 停止, 重启, 查看状态
[00:52:54 root@gitlab ~]#gitlab-ctl start | stop | restart | status
3.1.6 Gitlab登录
Gitlab 默认用户为root
密码 - 初次登录会要求重置
注意: 每次执行gitlab-ctl reconfigure时, 执行完毕,立即登录gitlab, 可能会出现502报错, 这是因为gitlab是由nginx负责代理后端应用程序, 如果nginx服务启动完成, 但是后端服务还没有启动, 就会出现502报错

3.2 Gitlab汉化
- 安装汉化包
汉化包下载地址: https://gitlab.com/xhang/gitlab, 目前只更新到了12版本
[01:12:31 root@gitlab ~]#ls
gitlab-v12.0.3-zh.tar.gz
[02:44:20 root@gitlab ~]#tar xf gitlab-v12.0.3-zh.tar.gz
[02:44:48 root@gitlab ~]#cd gitlab-v12.0.3-zh
[02:44:58 root@gitlab ~/gitlab-v12.0.3-zh]#cat VERSION
12.0.3 # 确认语言包版本和gitlab版本一致
[02:46:24 root@gitlab ~/gitlab-v12.0.3-zh]#gitlab-ctl stop # 先停止gitlab
[02:48:36 root@gitlab ~/gitlab-v12.0.3-zh]#\cp -r * /opt/gitlab/embedded/service/gitlab-rails/ # \cp防止有重名文件, 取消是否覆盖提示
cp: cannot overwrite non-directory ‘/opt/gitlab/embedded/service/gitlab-rails/log’ with directory ‘log’ # 报错可以忽略
cp: cannot overwrite non-directory ‘/opt/gitlab/embedded/service/gitlab-rails/tmp’ with directory ‘tmp’ # 报错可以忽略
[02:48:49 root@gitlab ~/gitlab-v12.0.3-zh]#gitlab-ctl start
启动后, 立即访问gitlab会显示502, 因为虽然nginx启动了, 但是其代理的后端服务器还没启动, 需要等待后端服务启动才能正常访问

- 调整页面字符集
Settings-Preferences-Location-选择简体中文-Save Changes-重新登录

3.3 用户, 用户组和项目
创建组 - 基于组创建项目 - 创建用户并添加到某个组,分配权限
3.3.1 创建组


3.3.2 创建项目


3.3.3 创建用户

- 创建一个普通用户developer-1

- 创建好用户后, 用户的邮箱会收到来自Gitlab的邮件, 进行密码设置

- 再创建一个管理员用户developer-2, 邮箱不能重复, 否则会报错


- 使用developer-1用户登录, 由于还没有给其加到任何组, 因此, 登录后看不到任何组信息

- 使用root账户, 进入devops组, 将developer-1和developer-2分别添加到组里, developer-1为开发人员, developer-2为所有者



- 使用developer-1登录, 可以看到自己被分配到的组的项目, 但是只能提交和下载代码, 无法对组进行管理.


- 使用developer-2登录, 因为是管理员, 所以可以对组进行管理


3.3.4 取消注册功能
- 默认情况, 任何人都可以注册登录gitlab, 不安全




3.4 Gitlab多用户协同操作
3.4.1 使用管理员developer-2用户, 在其本地创建仓库, 创建README.md文件, 并且关联到gitlab-devops组的crm项目
developer-2 : 10.0.0.82
配置本地域名解析: 10.0.0.237 gitlab.abc.com
[10:24:25 root@developer-2 ~]#yum -y install git
[10:25:53 root@developer-2 ~]#git config --global user.name "developer-2"
[10:26:06 root@developer-2 ~]#git config --global user.email "anshan0810@icloud.com"
[10:26:28 root@developer-2 ~]#mkdir crm_project
[10:26:39 root@developer-2 ~]#cd crm_project/
[10:26:42 root@developer-2 ~/crm_project]#git init
Initialized empty Git repository in /root/crm_project/.git/
[10:26:45 root@developer-2 ~/crm_project]#vim README.md
# crm系统
# 1. 开发功能
# 2. 开发功能
...
[10:28:12 root@developer-2 ~/crm_project]#git add .
[10:28:15 root@developer-2 ~/crm_project]#git commit -m "新增README.md文件"
[master (root-commit) 74de62c] 新增README.md文件
1 file changed, 3 insertions(+)
create mode 100644 README.md
- 关联仓库信息, 推送本地现有仓库到远程gitlab-devops-crm项目
[10:32:44 root@developer-2 ~/crm_project]#git remote add origin http://gitlab.abc.com/devops/crm.git # origin是远程仓库在本地仓库对应的一个别名
[10:32:49 root@developer-2 ~/crm_project]#git push -u origin master # -u 是用来指定仓库别名, 也就是把本地哪个仓库推送到远程仓库
Username for 'http://gitlab.abc.com': developer-2
Password for 'http://developer-2@gitlab.abc.com':
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 272 bytes | 272.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To http://gitlab.abc.com/devops/crm.git
* [new branch] master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.
- 检查gitlab-devops-crm项目

- 实现使用key验证, 利用ssh推送
[11:02:18 root@developer-2 ~/crm_project]#git remote -v # 查看当前本地仓库的信息, 以及别名
origin http://gitlab.abc.com/devops/crm.git (fetch)
origin http://gitlab.abc.com/devops/crm.git (push)
[11:03:13 root@developer-2 ~/crm_project]#git remote remove origin # 删除当前本地仓库的origin
[11:03:31 root@developer-2 ~/crm_project]#git remote add origin git@gitlab.abc.com:devops/crm.git # 添加ssh克隆方式
[11:03:32 root@developer-2 ~/crm_project]#git remote -v # 查看仓库信息
origin git@gitlab.abc.com:devops/crm.git (fetch)
origin git@gitlab.abc.com:devops/crm.git (push)
- 在developer-2的机器上, 用root用户生成key, 添加公钥到gitlab的ssh认证
- 这里在哪个用户机器上生成的key, 就要对应的用哪个用户登录Gitlab去添加秘钥信息. 因为秘钥是和主机绑定的. 添加的gitlab的秘钥信息只有本人可以看到
[11:06:45 root@developer-2 ~/crm_project]#ssh-keygen
[11:06:51 root@developer-2 ~/crm_project]#cat /root/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDJHCYWfrbk7FZaZWV4JKwfYKRyeBO7D5NEOFRY5rC/aFpV7jCyzeqWTKbwNCipN2I+6YwrB34q7PAAP4PcmoimqwNsG7/Td7ReZmySL6D5Mnyu5ApLqGtH7zeKS513FRsifKeMyjTVYz74QrZNYxrsiQwv7ERnTEyuJQis4rqO8HPPDp1zeT52YpwTLFhptmSN7NhwWKt0pLOPvXuFHY765/ojp2meuaJqI5b4uVlLmVPZGOgqnLyFxQYeAxZWWc2qrsGAPtrX2MFTsVH1RqtwtvuCADwtLzZarxJ22PTNPIpJqVMyStX/UEQMECVnnrmPD11p9KAKFjSrQ6MI4Vv22CIyje0850xfPgnqYYDiGhmvP7hAcaF/feoKescSi7cO+X+r9SsK21VaGaB7A9TVae7tqpSMdMO6MYQs6gdsPUmOyTFsdDYOAgBL8pEeMrUOEVyXLeAVi17aWCuF7+DNV7QAeYxhn11dtXHbJ1JBgosHGM7+1wg07sz69duP8J8= root@developer-2
任何gitlab用户都可以登录gitlab去添加自己的ssh秘钥, 每个用户需要用自己的账号登录到gitlab去添加ssh秘钥, 在别人的账户上是看不到其他人添加的key的

- 执行git push, 验证key验证成功
[11:07:02 root@developer-2 ~/crm_project]#git push origin master
The authenticity of host 'gitlab.abc.com (10.0.0.237)' can't be established.
ECDSA key fingerprint is SHA256:/VJJzU/5qt2JNeT1vpjDf3so5VejanRN2r8N6gb8wRY.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'gitlab.abc.com,10.0.0.237' (ECDSA) to the list of known hosts.
Everything up-to-date
- 创建一个新文件, 再测试
[11:09:03 root@developer-2 ~/crm_project]#touch file1
[11:13:47 root@developer-2 ~/crm_project]#git add .
[11:13:48 root@developer-2 ~/crm_project]#git commit -m "新建file1文档"
[master 1be4c1a] 新建file1文档
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file1
[11:13:58 root@developer-2 ~/crm_project]#git push origin master
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 290 bytes | 290.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To gitlab.abc.com:devops/crm.git
74de62c..1be4c1a master -> master
- 查看仓库更新

3.4.2 新用户developer-1加入公司, 使用crm项目
developer-1 : 10.0.0.81
配置本地域名解析: 10.0.0.237 gitlab.abc.com
- 给developer-1开通Gitlab权限, 加入到devops组, 权限是普通员工, 将developer-1的公钥上传到developer-1的Gitlab账号
[11:22:00 root@developer-1 ~]#ssh-keygen
[11:22:12 root@developer-1 ~]#cat .ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4W8XQdKfYGL/V4CUJ0Kn6KqiEh7CzcAPklIN9MAwQqACb4BMNXr8Lixl4PPABK/RZjGqh1+VCfnP3XFCGXhptx/YaOn2j8PUMEas7DyjhNc4pm+OmgXkJEHhRhf+5Qg45SAXkFU/35wfEWy+JpYU/3Fo/x+S4iCJzqkJD/PwjjW4LfYXseZqLtbU9JwPWiXAey/uNdYhw57gLdlVJf/jYYe2nF0W/ZvSjT8ANnpyppNlZdDw7sYvG/ThiNzxo6EUwq4lV8XMt5m9zVrPRWVG+5BJj/md1fBTHInPeSdLcubJStLB3sUSXHN1z1IWPBYR50FPxfItHP1WRyuK271krhtgZKvJxkbJ3wcdfKiniZKgH8sitvHF8Cn9c7cMPQEHbWHObGNRmEm85KfnmCQyklkau3waHViLFvbanrjM8VZszDCkMmFZhmNrbgco/tgToRuSJdJs6J29aFEk1+QEgc28fqc9liyBFKA0D13yoHEEmnkGgQuX7kVON6SzA/H8= root@developer-1

- 克隆crm项目到本地仓库
[11:26:14 root@developer-1 ~]#git clone git@gitlab.abc.com:devops/crm.git
Cloning into 'crm'...
The authenticity of host 'gitlab.abc.com (10.0.0.237)' can't be established.
ECDSA key fingerprint is SHA256:/VJJzU/5qt2JNeT1vpjDf3so5VejanRN2r8N6gb8wRY.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'gitlab.abc.com,10.0.0.237' (ECDSA) to the list of known hosts.
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 6 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (6/6), done.
[11:28:08 root@developer-1 ~/crm]#ls
file1 README.md
- 修改README.md文件
[11:28:08 root@developer-1 ~/crm]#vim README.md
# crm系统
# 1. 开发功能
# 2. 开发功能
# 3. developer-1修复了bug
~
- 推送更新到本地仓库和远程仓库
[11:50:14 root@developer-1 ~/crm]#git add .
[11:50:14 root@developer-1 ~/crm]#git commit -m "developer-1修复了bug'
[11:37:48 root@developer-1 ~/crm]#git push origin master
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 349 bytes | 349.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To gitlab.abc.com:devops/crm.git
1be4c1a..6e8dd43 master -> master
注意: 如果出现# ! [remote rejected] master -> master (pre-receive hook declined)
报错, 需要项目管理员或者Gitlab运维登录Gitlab把项目的保护模式取消, 否则即使开发把公钥添加到了Gitlab, 也无法完成代码推送

- 验证推送成功

3.4.3 管理员developer-2拉取新的代码到本地
- 可以看到, developer-1更新的代码推送到远程仓库后, 其他用户可以拉取到本地仓库进行修改
[12:00:32 root@developer-2 ~/crm_project]#git pull origin master
[12:00:52 root@developer-2 ~/crm_project]#cat README.md
# crm系统
# 1. 开发功能
# 2. 开发功能
# 3. developer-1修改了bug
3.5 分支和tag使用
- 下面在developer-2, 组管理员账号操作
3.5.1 分支
3.5.1.1 创建分支devops
[12:00:55 root@developer-2 ~/crm_project]#git branch
* master
[12:13:13 root@developer-2 ~/crm_project]#git branch devops
[12:13:17 root@developer-2 ~/crm_project]#git checkout devops
Switched to branch 'devops'
[12:13:22 root@developer-2 ~/crm_project]#ls
file1 README.md
[12:13:23 root@developer-2 ~/crm_project]#cat README.md
# crm系统
# 1. 开发功能
# 2. 开发功能
# 3. developer-1修改了bug
3.5.1.2 devops分支创建文件, 推送到本地和远程仓库
[12:13:26 root@developer-2 ~/crm_project]#touch devops_file
[12:14:21 root@developer-2 ~/crm_project]#git add .
[12:14:23 root@developer-2 ~/crm_project]#git commit -m "创建devops_file文件"
[devops 2fb91b0] 创建devops_file文件
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 devops_file
[12:14:34 root@developer-2 ~/crm_project]#git push origin devops
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 301 bytes | 301.00 KiB/s, done.
Total 2 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: To create a merge request for devops, visit:
remote: http://gitlab.abc.com/devops/crm/merge_requests/new?merge_request%5Bsource_branch%5D=devops
remote:
To gitlab.abc.com:devops/crm.git
* [new branch] devops -> devops
- 查看crm项目, devops_file只在devops分支有

3.1.5.3 将devops和master合并
[12:14:57 root@developer-2 ~/crm_project]#git merge master
Already up to date.
[12:20:19 root@developer-2 ~/crm_project]#git push origin devops
Everything up-to-date
[12:20:27 root@developer-2 ~/crm_project]#git checkout master
Switched to branch 'master'
[12:20:31 root@developer-2 ~/crm_project]#git merge devops
Updating 6e8dd43..2fb91b0
Fast-forward
devops_file | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 devops_file
[12:20:36 root@developer-2 ~/crm_project]#git push origin master
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
To gitlab.abc.com:devops/crm.git
6e8dd43..2fb91b0 master -> master
- 查看crm更新

3.5.2 tag使用
3.5.2.1 基于当前提交状态, 创建tag并推送至远程
- 一般都是对master创建tag, 代码测试完毕, 先把master和测试代码合并, 然后把master推到gitlab, 再给master当前状态打标签, 然后把标签推到gitlab, 之后基于标签对应的版本拉取和部署代码, 而master的代码每次测试完毕,一直都是累加的
[12:20:49 root@developer-2 ~/crm_project]#git tag -a "v1.1" -m "v1.1"
[12:25:47 root@developer-2 ~/crm_project]#git tag
v1.1
[12:25:49 root@developer-2 ~/crm_project]#git push origin v1.1
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 158 bytes | 158.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
To gitlab.abc.com:devops/crm.git
* [new tag] v1.1 -> v1.1
# 这里不能写master, 因为我们要推送的是v1.1版本, 推送到仓库会独立显示v1.1
3.5.2.2 查看远程仓库

3.5.2.3 基于指定提交状态, 创建tag
[12:26:12 root@developer-2 ~/crm_project]#git reflog
2fb91b0 (HEAD -> master, tag: v1.1, origin/master, origin/devops, devops) HEAD@{0}: merge devops: Fast-forward
6e8dd43 HEAD@{1}: checkout: moving from devops to master
2fb91b0 (HEAD -> master, tag: v1.1, origin/master, origin/devops, devops) HEAD@{2}: commit: ??devops_file??
6e8dd43 HEAD@{3}: checkout: moving from master to devops
6e8dd43 HEAD@{4}: pull origin master: Fast-forward
1be4c1a HEAD@{5}: commit: 新建file1文档 # 基于本次提交打标签
74de62c HEAD@{6}: commit (initial): 新家README.md文档
[12:29:53 root@developer-2 ~/crm_project]#git tag -a "v1.2" 1be4c1a -m "test_tag"
[12:31:20 root@developer-2 ~/crm_project]#git tag
v1.1
v1.2
[12:32:34 root@developer-2 ~/crm_project]#git push origin v1.2
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 163 bytes | 163.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
To gitlab.abc.com:devops/crm.git
* [new tag] v1.2 -> v1.2
- 查看crm项目

- devops_file文件是在v1.2tag后创建的, 所以v1.2是没有这个文件的

3.6 Gitlab备份, 恢复
3.6.1 备份
3.6.1.1 备份配置
- 默认备份路径
### Backup Settings
###! Docs: https://docs.gitlab.com/omnibus/settings/backups.html
# gitlab_rails['manage_backup_path'] = true
# gitlab_rails['backup_path'] = "/var/opt/gitlab/backups"
- 修改备份路径和备份保留时间
gitlab_rails['manage_backup_path'] = true
gitlab_rails['backup_path'] = "/data/gitlab/backups"
gitlab_rails['backup_keep_time'] = 604800 # 默认数据保留一个星期
- 创建备份路径
[17:09:05 root@gitlab ~]#mkdir /data/gitlab/backups -p # 要求空间足够大
- 初始化gitlab
[17:09:08 root@gitlab ~]#gitlab-ctl reconfigure
3.6.1.2 执行备份
- 手动执行备份, 会将备份的结果保存到/data/gitlab/backups中
- gitlab备份只是备份的项目数据, 并不是整个gitlab, 因此, 如果gitlab崩溃了, 需要重新配置一个gitlab, 然后把项目文件数据导入. 同时, 备份数据的同时, 最好也备份gitlab.rb and gitlab-secrets.json, 配置文件, 和秘钥认证文件, 否则重新导入时还需要修改创建
# 停止数据写入服务, 为了安全起见
[17:27:50 root@gitlab ~]#gitlab-ctl stop unicorn
[17:33:47 root@gitlab ~]#gitlab-ctl stop sidekiq
[17:17:10 root@gitlab ~]#gitlab-rake gitlab:backup:create
...
Warning: Your gitlab.rb and gitlab-secrets.json files contain sensitive data
and are not included in this backup. You will need these files to restore a backup.
Please back them up manually. # 提示可以忽略
Backup task is done.
[17:22:28 root@gitlab ~]#ll /data/gitlab/backups/
total 160
-rw------- 1 git git 163840 Dec 26 17:17 1608974258_2020_12_26_12.0.3_gitlab_backup.tar
- 创建计划任务, 实现每天定期备份
[17:22:34 root@gitlab ~]#crontab -l
00 02 * * * gitlab-rake gitlab:backup:create &> /dev/null
3.6.2 恢复
- 删除crm项目




- 停止gitlab数据写入服务, 在执行备份前, 也可以停止数据写入服务, 为了安全起见
[17:27:50 root@gitlab ~]#gitlab-ctl stop unicorn
[17:33:47 root@gitlab ~]#gitlab-ctl stop sidekiq
- 找到最新的备份数据, 执行恢复
[17:36:09 root@gitlab ~]#ll /data/gitlab/backups/
total 160
-rw------- 1 git git 163840 Dec 26 17:17 1608974258_2020_12_26_12.0.3_gitlab_backup.tar
[17:36:15 root@gitlab ~]#gitlab-rake gitlab:backup:restore BACKUP=1608974258_2020_12_26_12.0.3 # 注意, gitlab会自动到备份数据的目录寻找指定的文件, 无需文件后缀_gitlab_backup.tar
[17:36:15 root@gitlab ~]#gitlab-rake gitlab:backup:restore BACKUP=1608974258_2020_12_26_12.0.3
Unpacking backup ... done
Before restoring the database, we will remove all existing
tables to avoid future upgrade problems. Be aware that if you have
custom tables in the GitLab database these tables and all data will be
removed. # 恢复之前, 需要删除所有已有表, 如果有自定义的表, 会一并删除
Do you want to continue (yes/no)? # 一路yes即可
Do you want to continue (yes/no)? yes
Removing all tables. Press `Ctrl-C` within 5 seconds to abort
You will lose any data stored in the authorized_keys file.
Do you want to continue (yes/no)? yes # 删除认证信息, 这里其实并不会删除创建好的用户名和密码, 包括ssh秘钥认证记录
Deleting tmp directories ... done
done
done
done
done
done
done
done
Warning: Your gitlab.rb and gitlab-secrets.json files contain sensitive data
and are not included in this backup. You will need to restore these files manually.
Restore task is done.
- 重启gitlab服务
[17:39:06 root@gitlab ~]#gitlab-ctl restart
ok: run: alertmanager: (pid 37131) 1s
ok: run: gitaly: (pid 37142) 1s
ok: run: gitlab-monitor: (pid 37160) 0s
ok: run: gitlab-workhorse: (pid 37163) 1s
ok: run: grafana: (pid 37179) 0s
ok: run: logrotate: (pid 37193) 1s
ok: run: nginx: (pid 37203) 0s
ok: run: node-exporter: (pid 37209) 0s
ok: run: postgres-exporter: (pid 37215) 0s
ok: run: postgresql: (pid 37235) 0s
ok: run: prometheus: (pid 37245) 1s
ok: run: redis: (pid 37333) 0s
ok: run: redis-exporter: (pid 37337) 1s
ok: run: sidekiq: (pid 37344) 0s
ok: run: unicorn: (pid 37350) 0s
- 验证项目恢复, 用户,组信息都存在即可
3.7 生产案例代码回滚演示
环境:
Gitlab 服务器 10.0.0.237
开发机-1 10.0.0.81
开发机-2 10.0.0.82
Web服务器1-10.0.0.81-apache
3.7.1 部署apache服务器,安装git
[23:51:05 root@web-srv ~]#yum -y install httpd
[23:51:55 root@web-srv ~]#systemctl start httpd
[23:54:49 root@web-srv ~]#yum -y install git
3.7.2 将此前创建好的crm项目, 克隆到web站点目录, 此时crm目录就是我们网站的页面目录
[23:54:49 root@web-srv /var/www/html]#git clone http://gitlab.abc.com/devops/crm.git
Cloning into 'crm'...
Username for 'http://gitlab.abc.com': root
Password for 'http://root@gitlab.abc.com':
remote: Enumerating objects: 25, done.
remote: Counting objects: 100% (25/25), done.
remote: Compressing objects: 100% (18/18), done.
remote: Total 25 (delta 4), reused 21 (delta 3)
Unpacking objects: 100% (25/25), 2.38 KiB | 348.00 KiB/s, done.
[23:55:35 root@web-srv /var/www/html]#ls
crm
3.7.3 在开发机-2,10.0.0.82上, 创建index.html文件, 作为web网站的主页面
[23:42:04 root@developer-2 ~]#cd crm_project/
[23:58:55 root@developer-2 ~/crm_project]#ls
devops_file file1 README.md
[23:58:55 root@developer-2 ~/crm_project]#vim index.html
webpage-v1.0
[23:59:26 root@developer-2 ~/crm_project]#git add .
[23:59:40 root@developer-2 ~/crm_project]#git commit -m "提交网站主页面v1.0"
[master 0143b2e] 提交网站主页面v1.0
1 file changed, 1 insertion(+)
create mode 100644 index.html
[23:59:53 root@developer-2 ~/crm_project]#git push origin master
Counting objects: 4, done.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 315 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
To git@10.0.0.217:devops/crm.git
21007f4..0143b2e master -> master
3.7.4 检查gitlab服务器, 验证文件提交成功

3.7.5 在web服务器上拉取最新的代码
[23:59:06 root@web-srv /var/www/html/crm]#git pull
Username for 'http://gitlab.abc.com': root
Password for 'http://root@gitlab.abc.com':
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From http://gitlab.abc.com/devops/crm
21007f4..0143b2e master -> origin/master
Updating 21007f4..0143b2e
Fast-forward
index.html | 1 +
1 file changed, 1 insertion(+)
create mode 100644 index.html
[00:01:30 root@web-srv /var/www/html/crm]#ls
devops_file file1 index.html README.md
3.7.6 验证web页面可用

这就模拟了网站初次上线
3.7.7 在开发机2上, 修改主页面, 准备进行代码回滚
[00:01:22 root@developer-2 ~/crm_project]#echo "webpage-v2.0" >> index.html
[00:03:39 root@developer-2 ~/crm_project]#cat index.html
webpage-v1.0
webpage-v2.0
[00:03:42 root@developer-2 ~/crm_project]#git add .
[00:04:29 root@developer-2 ~/crm_project]#git commit -m "提交主页面的v2.0版本"
[master 97eaba4] 提交主页面的v2.0版本
1 file changed, 1 insertion(+)
[00:04:39 root@developer-2 ~/crm_project]#git push
Counting objects: 5, done.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 309 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
To git@10.0.0.217:devops/crm.git
0143b2e..97eaba4 master -> master
3.7.8 验证gitlab服务器

3.7.9 web服务器拉取代码, 进行代码更新
[00:01:34 root@web-srv /var/www/html/crm]#git pull
Username for 'http://gitlab.abc.com': root
Password for 'http://root@gitlab.abc.com':
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From http://gitlab.abc.com/devops/crm
0143b2e..97eaba4 master -> origin/master
Updating 0143b2e..97eaba4
Fast-forward
index.html | 1 +
1 file changed, 1 insertion(+)
[00:06:20 root@web-srv /var/www/html/crm]#cat index.html
webpage-v1.0
webpage-v2.0
3.7.10 验证网站页面更新

3.7.11 这时发现, v2.0有问题, 如何回滚到v1.0
思路:
- 首先, web服务器上, 只有本地仓库, 并不涉及开发的工作目录, 以及缓存区, 因此, 只需要考虑在web服务器上, 从本地仓库回滚代码到指定版本, 参考之前讲的, "多次提交代码到仓库, 如何进行回滚"
- 查看web服务器上的提交记录, 找到需要回滚到的版本
- 通过git reset --hard COMMIT_ID 进行回滚, 即可实现代码回滚, 网站也会回到之前的状态
[00:06:23 root@web-srv /var/www/html/crm]#git log --oneline
97eaba4 提交主页面的v2.0版本
0143b2e 提交网站主页面v1.0 # 确定要回滚的版本和commit号码
21007f4 new devops_file
4c2166d 张三修改了所有bug,更新README.md
d341234 new file1
8a741f7 new README.md
[00:07:53 root@web-srv /var/www/html/crm]#git reset --hard 0143b2e
HEAD is now at 0143b2e 提交网站主页面v1.0
[00:10:52 root@web-srv /var/www/html/crm]#cat index.html
webpage-v1.0 # 此时, 主页面已经回滚到上一个状态
验证web页面

补充:
- web服务器上拉取代码到本地后, 代码就是运行在本地git仓库, 因为web服务器是没有开发人员操作的, 也就没有工作区和暂存区, 只有本地仓库, 因此, 无论是拉取还是回滚都是在本地仓库做操作, 回滚就是使用git reset --hard命令, 后面接指定的commit id 或者 HEAD^, 来定义回滚的次数
- 另外, 从gitlab拉取代码到web服务器后, 其本地仓库会有所有该项目的历史commit记录, 也就是说, 即使这个服务器是新的服务器, 原来没有部署过这个web项目, 那它也是可以回滚到任意原来的版本, 只要gitlab上的代码有就行
- web服务器回滚后, gitlab上的代码还是最新的, 因此, 开发可能还需要修改上面的内容, 或者保留错误更新, 重新提交代码并打标签提交, 这样在提交后, gitlab上就是新的没问题的代码了, 运维在web服务器上拉取最新的代码既可完成部署, 对应静态资源都可以使用这种方法完成手动上线和回滚
额外命令:
- 回滚本地仓库到指定版本
git reset --hard HEAD^ # HEAD代表的是当前的本地仓库版本, 一个^就是上一个版本, ^^就是上上个版本, 以此类推
- 查看当前本地仓库所在的版本
[00:17:49 root@web-srv /var/www/html/crm]#git show
commit 49ca3ad7db2b2f3f14ccd0a2b01965f81da4d1e0 (HEAD -> master)
Author: developer-2 <anshan0810@icloud.com>
Date: Mon May 31 15:54:17 2021 +0800
提交网站主页面v1.0
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..5e3aee2
--- /dev/null
+++ b/index.html
@@ -0,0 +1 @@
+webpage-v1.0
- 在web或者其他生产服务器, 对比本地仓库多个版本的差异
# 先通过git log --oneline获取需要对比的版本commit_id
[00:39:00 root@web-srv /var/www/html/crm]#git diff 8a741f7 4c2166d # 从8a741f7 开始到 4c2166d 的差别
diff --git a/README.md b/README.md
index 4ba6b15..3f6f773 100644
--- a/README.md
+++ b/README.md
@@ -2,3 +2,4 @@
# 1. 开发功能
# 2. 开发功能
...
+# 3. 张三已经完成了所有的bug修复
diff --git a/file1 b/file1
new file mode 100644
index 0000000..e69de29