第 1 章 Git 版本控制系统

作者: admin 分类: ARM64 Linux CICD 研发 发布时间: 2022-07-19 12:01

1.1、Git、Github、Gitlab 的区别

Git 是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目。是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。

Github 是在线的基于 Git 的代码托管服务。 GitHub 是 2008 年由 Ruby on Rails 编写而成。GitHub 同时提供付费账户和免费账户。这两种账户都可以创建公开的代码仓库,只有付费账户可以创建私有的代码仓库。

Gitlab 解决了这个问题,可以在上面创建免费的私人仓库。

git:是一套软件,可以做本地私有仓库。

github:本身是一个代码托管网站,公有和私有仓库(收费),不能做本地私有仓库。

gitlab:本身也是一个代码托管的网站,功能上和 github 没有区别,公有和私有仓库(免费)可以部署本地私有仓库。

1.2、Git 与 SVN 区别

Git 不仅仅是个版本控制系统,它也是个内容管理系统(CMS),工作管理系统等。

如果你是一个具有使用 SVN 背景的人,你需要做一定的思想转换,来适应 Git 提供的一些概念和特征。

Git 与 SVN 区别

  1. Git 是分布式的,SVN 不是,这是 Git 和其它非分布式的版本控制系统,例如 SVN,CVS 等,最核心的区别。
  2. Git 把内容按元数据方式存储,而 SVN 是按文件存储,所有的资源控制系统都是把文件的元信息隐藏在一个类似 .svn,.cvs 等的文件夹里。
  3. Git 分支和 SVN 的分支不同,分支在 SVN 中一点不特别,就是版本库中的另外的一个目录。
  4. Git 没有一个全局的版本号,而 SVN 有,目前为止这是跟 SVN 相比 GIT 缺少的最大的一个特征。
  5. Git 的内容完整性要优于 SVN,Git 的内容存储使用的是 SHA-1 哈希算法。这能确保代码内容的完整性,确保在遇到磁盘故障和网络问题时降低对版本库的破坏。

git:是分布式的版本控制器,没有客户端和服务器端的概念。

svn:它是 C/S 结构的版本控制器,有客户端和服务器端,服务器如果宕机而且代码没有备份的情况下,完整代码就会丢失。

1.3、部署 Git 服务

1.3.1、创建 git 仓库

git-server 上的操作:

[root@arm64v8 ~]# yum install git gitweb -y
[root@arm64v8 ~]# useradd git
[root@arm64v8 ~]# echo "Brinnatt@487X" | passwd --stdin git
[root@arm64v8 ~]# su - git
Last login: Sat Mar  5 20:06:49 CST 2022 on pts/0
[git@arm64v8 ~]$
[git@arm64v8 ~]$ mkdir git-root
[git@arm64v8 ~]$ cd git-root/
[git@arm64v8 git-root]$ 
[git@arm64v8 git-root]$ git init --bare shell.git
Initialized empty Git repository in /home/git/git-root/shell.git/
[git@arm64v8 git-root]$ 
[git@arm64v8 git-root]$ ls shell.git/
branches  config  description  HEAD  hooks  info  objects  refs
[git@arm64v8 git-root]$
  • git init 和 git init --bare 的区别:
    • 使用 --bare 选项时,不再生成 .git 目录,而是只生成 .git 目录下面的版本历史记录文件,这些版本历史记录文件也不再存放在 .git 目录下面,而是直接存放在版本库的根目录下面。
    • 用 "git init" 初始化的版本库用户也可以在该目录下执行所有 git 方面的操作。但远程的用户再将更新代码 push 上来的时候容易出现冲突。
    • 使用 "git init --bare" 方法创建一个所谓的裸仓库,之所以叫裸仓库是因为这个仓库只保存 git 历史提交的版本信息,而不允许用户在上面进行各种 git 操作,如果你硬要操作的话,只会得到下面的错误(”This operation must be run in a work tree”)这个就是最好把远端仓库初始化成 bare 仓库的原因。

1.3.2、git 仓库测试

git-client 上的操作:

[root@armcli ~]# yum install git -y
[root@armcli ~]# ssh-keygen -t rsa
[root@armcli ~]# ssh-copy-id -i git@arm64v8
[root@armcli ~]# mkdir localgit
[root@armcli ~]# cd localgit/
[root@armcli localgit]# git config --global user.email "brinnatt@gmail.com"
[root@armcli localgit]# git config --global user.name "Brinnatt"
[root@armcli localgit]# git clone git@arm64v8:/home/git/git-root/shell.git
Cloning into 'shell'...
warning: You appear to have cloned an empty repository.
[root@armcli localgit]# ls
shell
[root@armcli localgit]#
[root@armcli localgit]# cd shell/
[root@armcli shell]# vim test.sh
#!/bin/bash
echo "hello world"
[root@armcli shell]# git add test.sh 
[root@armcli shell]# git commit -m "first commit, changed test.sh"
[master (root-commit) 7b55201] first commit, changed test.sh
 1 file changed, 2 insertions(+)
 create mode 100644 test.sh
[root@armcli shell]# 
[root@armcli shell]# git push origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 247 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@arm64v8:/home/git/git-root/shell.git
 * [new branch]      master -> master
[root@armcli shell]#

再找一台 armcli2 的服务器:

[root@armcli2 ~]# yum install git -y
[root@armcli2 ~]# git clone git@arm64v8:/home/git/git-root/shell.git
[root@armcli2 ~]# cd shell/
[root@armcli2 shell]# ls
test.sh
[root@armcli2 shell]# cat test.sh 
#!/bin/bash
echo "hello world"
[root@armcli2 shell]#
  • 经验证,Git 服务部署成功。

1.4、Git 工作流程

一般工作流程如下:

  • 克隆 Git 资源作为工作目录。
  • 在克隆的资源上添加或修改文件。
  • 如果其他人修改了,你可以更新资源。
  • 在提交前查看修改。
  • 提交修改。
  • 在修改完成后,如果发现错误,可以撤回提交并再次修改并提交。

      Git 的工作流程示意图:

img

1.5、Git 基本概念

  • 工作区:.git 所在的目录就是工作区,一般是项目的根目录。
  • 暂存区:英文叫 stage,或 index。一般存放在 "git 目录" 下的 index 文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。
  • 版本库:工作区有一个隐藏目录 .git,这个不算工作区,而是 Git 的版本库。

工作区、版本库中的暂存区和版本库之间的关系的示意图:

img

  •   图中左侧为工作区,右侧为版本库。在版本库中标记为 "index" 的区域是暂存区(stage,index),标记为 "master" 的是 master 分支所代表的目录树。

  •   图中我们可以看出此时 "HEAD" 实际是指向 master 分支的一个"游标"。所以图示的命令中出现 HEAD 的地方可以用 master 来替换。

  •   图中的 objects 标识的区域为 Git 的对象库,实际位于 ".git/objects" 目录下,里面包含了创建的各种对象及内容。

  •   当对工作区修改(或新增)的文件执行 "git add" 命令时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的 ID 被记录在暂存区的文件索引中。

  •   当执行提交操作(git commit)时,暂存区的目录树写到版本库(对象库)中,master 分支会做相应的更新。即 master 指向的目录树就是提交时暂存区的目录树。

  •   当执行 "git reset HEAD" 命令时,暂存区的目录树会被重写,被 master 分支指向的目录树所替换,但是工作区不受影响。

  •   当执行 "git rm --cached (file)" 命令时,会直接从暂存区删除文件,工作区则不做出改变。

  •   当执行 "git checkout ." 或者 "git checkout -- (file)" 命令时,会用暂存区全部或指定的文件替换工作区的文件。这个操作很危险,会清除工作区中未添加到暂存区的改动。

  •   当执行 "git checkout HEAD ." 或者 "git checkout HEAD (file)" 命令时,会用 HEAD 指向的 master 分支中的全部或者部分文件替换暂存区和以及工作区中的文件。这个命令也是极具危险性的,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改动。

1.6、Git 客户端安装使用

1.6.1、Git 安装

[root@arm64v8 ~]# yum install git -y
[root@arm64v8 ~]# git version
git version 1.8.3.1

1.6.2、Git 配置

Git 提供了一个叫做 git config 的工具,专门用来配置或读取相应的工作环境变量。

这些环境变量,决定了 Git 在各个环节的具体工作方式和行为。这些变量可以存放在以下三个不同的地方:

  • /etc/gitconfig 文件:系统中对所有用户都普遍适用的配置。若使用 git config 时用 --system 选项,读写的就是这个文件。
  • ~/.gitconfig 文件:用户目录下的配置文件只适用于该用户。若使用 git config 时用 --global 选项,读写的就是这个文件。
  • 当前项目的 Git 目录中的配置文件(也就是工作目录中的 .git/config 文件):这里的配置仅仅针对当前项目有效。每一个级别的配置都会覆盖上层的相同配置,所以 .git/config 里的配置会覆盖 /etc/gitconfig 中的同名变量。

1.6.2.1、Git 用户信息

配置个人的用户名称和电子邮件地址:

[root@armcli2 ~]# git config --global user.name 'Brinnatt'
[root@armcli2 ~]# git config --global user.email 'brinnatt@gmail.com'
  • 如果用了 --global 选项,那么更改的配置文件就是位于你用户主目录下的那个,以后你所有的项目都会默认使用这里配置的用户信息。

  • 如果要在某个特定的项目中使用其他名字或者电邮,只要去掉 --global 选项重新配置即可,新的设定保存在当前项目的 .git/config 文件里。

1.6.2.2、文本编辑器

设置 Git 默认使用的文本编辑器,一般可能会是 Vi 或者 Vim。如果你有其他偏好,比如 Emacs 的话,可以重新设置

[root@armcli2 ~]# git config --global core.editor vim

1.6.2.3、差异分析工具

还有一个比较常用的是,在解决合并冲突时使用哪种差异分析工具。比如要改用 vimdiff 的话:

[root@armcli2 ~]# git config --global merge.tool vimdiff
  • Git 可以理解 kdiff3,tkdiff,meld,xxdiff,emerge,vimdiff,gvimdiff,ecmerge 和 opendiff 等合并工具的输出信息。当然,你也可以指定使用自己开发的工具。

1.6.2.4、查看配置信息

要检查已有的配置信息,可以使用 git config --list 命令:

[root@armcli2 ~]# git config --list
user.name=Brinnatt
user.email=brinnatt@gmail.com
core.editor=vim
merge.tool=vimdiff
[root@armcli2 ~]#

有时候会看到重复的变量名,那就说明它们来自不同的配置文件(比如 /etc/gitconfig 和 ~/.gitconfig),不过最终 Git 实际采用的是最后一个。

这些配置我们也可以在 ~/.gitconfig/etc/gitconfig 看到,如下所示:

[root@armcli2 ~]# cat ~/.gitconfig 
[user]
    name = Brinnatt
    email = brinnatt@gmail.com
[core]
    editor = vim
[merge]
    tool = vimdiff
[root@armcli2 ~]#

也可以直接查阅某个环境变量的设定,只要把特定的名字跟在后面即可,像这样:

[root@armcli2 ~]# git config user.name
Brinnatt

1.6.3、Git 使用

1.6.3.1、SSH 连接

  1. 本地生成 SSH 密钥对。
[root@armcli2 ~]# rm -rf .ssh/
[root@armcli2 ~]# ssh-keygen -t rsa -b 4096 -N '' -f /root/.ssh/id_rsa -q
[root@armcli2 ~]# ls .ssh/
id_rsa  id_rsa.pub
[root@armcli2 ~]# cat .ssh/id_rsa.pub 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDYbtRw0Sq2LOxPRJsVbL5xgaY8aVjsK0M22GWc2vZGv3yek0pYCyTAudPiC43Q29yquRkRMZoyZI/hasq6PKZH0LUrkRJM1eH1umpMr7YobHwU2nxsowzLdOGZWe1y80LmTiUQBbLt7NIG0rvDn0xWm/f1sdfsedgwesdg23dtytssdglTwOzyAuPYI8A3+mxZoKPbTL5ZNTVhxuLbPBkZQXFf0gD0NJjf4BnvvHnvbuTzKIa8P/ALOBQPD63HZAJ9uuqO0mCDhb1OADUJQ0DuQFUPaIYi0Bzvevm22QTv+BYHXTUnZON6AWeZDMqNuHUqLsgdrEOhBSnURo1HV7eTSUmS1wf+4L7YaxQGLn2pyezzV+LihHu+3LbHSrR+iwDhJW3o9R2BrVAbyYlzboZqT5FAmjNrmd+gM1v7jP/y2xIEecvSxhh8gFscsSTOGQdyxDvh6bPBnCCsWPHhsmDB41VZrvbrsBNOsAC9TvJC+EvldrWfdb6PsNvKT6UBojhknY3nfsTDVW7/f/UCia2xi9JVbwVlu4H+6oZL/9GTxv+hnF/2x4zD5CsKOxvle0/ltLrYLzYxr7q80hOug3MjbHw/r8Nc6324E3G3CLWWaDx4WEHhzC1MNkoTym+0EYve7TQE+MRurrx3vOKU+bCFrMnMPgPsHZpB14VJtZ/Vw== root@armcli2
[root@armcli2 ~]#
  1. 将 SSH 公钥复制到 github 账号对应的剪贴板上。

git ssh1

git ssh2

git ssh3

  1. 测试 SSH 密钥认证是否成功。
[root@armcli2 ~]# ssh -T git@github.com
The authenticity of host 'github.com (20.205.243.166)' can't be established.
ECDSA key fingerprint is SHA256:p2QAMXNIC1TJYWeIOttrVc98/R1BUFWu3/LiyKgUfQM.
ECDSA key fingerprint is MD5:7b:99:81:1e:4c:91:a5:0d:5a:2e:2e:80:13:3f:24:ca.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'github.com,20.205.243.166' (ECDSA) to the list of known hosts.
Hi liangtiansheng! You've successfully authenticated, but GitHub does not provide shell access.
[root@armcli2 ~]#
  1. 用我的 github 账号做一个测试,注意使用 ssh clone 的方式。当然,如果使用 https clone 也没有关系,在本地修改一下 url 的连接方式即可。
[root@armcli2 ~]# git clone git@github.com:liangtiansheng/pipework.git
[root@armcli2 ~]# ls
pipework
[root@armcli2 ~]# cd pipework/
[root@armcli2 pipework]# cat .git/config 
[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
[remote "origin"]
    url = git@github.com:liangtiansheng/pipework.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
    remote = origin
    merge = refs/heads/master
[root@armcli2 pipework]# echo "for i in {1..10};do echo $i;done" > mytest.sh   # 增加一个文件,写点代码
[root@armcli2 pipework]# git add mytest.sh                                      # 加到缓存
[root@armcli2 pipework]# git commit -m "try to change source code"                # 提交到本地版本库

*** Please tell me who you are.                                                 # 要说明一下是谁修改的代码

Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: unable to auto-detect email address (got 'root@armcli2.(none)')
[root@armcli2 pipework]#
[root@armcli2 pipework]# git config user.name "Jack"                          # 随便取一个名字
[root@armcli2 pipework]# git config user.email "Jackie@gmail.com"             # 给一个邮箱地址
[root@armcli2 pipework]# git commit -m "try to change source code"                # 可以提交到本地版本库了
[master 6d8cb58] try to change source code
 1 file changed, 1 insertion(+)
 create mode 100644 mytest.sh
[root@armcli2 pipework]# git push -u origin master                              # 基于 ssh key 直接提交到 github 账号仓库  
Counting objects: 4, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 300 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To git@github.com:liangtiansheng/pipework.git
   ae42f1b..6d8cb58  master -> master
Branch master set up to track remote branch master from origin.                 # 去 github 账号下检查代码提交情况
[root@armcli2 pipework]#

1.6.3.2、token 连接

本人用得少,后面再补充。

1.6.3.3、Git 身份验证

[root@armcli2 ~]# git config --global user.name 'Brinnatt'
[root@armcli2 ~]# git config --global user.email 'brinnatt@gmail.com'
  • 注意:设定本机用户名,绑定邮箱,让远程服务器知道来者的身份,无论是提交到自己的仓库还是提交到别人的仓库,需要自报代码修改者的家门。

1.6.3.4、Git 本地与远程项目交互

1.6.3.4.1、克隆 github 项目
[root@armcli ~]# git clone https://github.com/liangtiansheng/pipework.git   # 这里是项目的地址,将远程服务器的内容完全复制过来
[root@armcli ~]# cd pipework/                                               # clone 之后进入该项目的文件夹
[root@armcli pipework]# echo "for i in {1..10};do echo $i;done" > mytest.sh    # 创建 mytest.sh 写点东西进去
[root@armcli pipework]# git add mytest.sh                                   # 将新的文件添加到 git 的暂存区
[root@armcli pipework]# git commit -m "try to change source code"         # 将暂存区的文件提交到某一个版本保存下来,并加上注释
[root@armcli pipework]# git push -u origin master                           # 将本地的更改提交到远程服务器
Username for 'https://github.com': liangtiansheng
Password for 'https://liangtiansheng@github.com': 
remote: Support for password authentication was removed on August 13, 2021. Please use a personal access token instead.
remote: Please see https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/ for more information.
fatal: Authentication failed for 'https://github.com/liangtiansheng/pipework.git/'
[root@armcli pipework]#
  • 最后一步将本地版本库中的代码提交到远程服务器失败,这是 github 从 2021.8.13 日起禁止使用用户名和密码认证。
  • 参见上面的 ssh 密钥认证,然后再 push 即可。
# 把 https url 改成 ssh url
[root@armcli2 pipework]# grep "url" .git/config 
    url = https://github.com/liangtiansheng/pipework.git
[root@armcli2 pipework]#
[root@armcli2 pipework]# git remote set-url origin git@github.com:liangtiansheng/pipework.git
[root@armcli2 pipework]# 
[root@armcli2 pipework]# grep "url" .git/config 
    url = git@github.com:liangtiansheng/pipework.git
[root@armcli2 pipework]#
[root@armcli2 pipework]# git push -u origin master
1.6.3.4.2、本地关联 github 项目
  1. 用 github 账号创建一个名叫 gitlearning 的测试仓库。
git@github.com:liangtiansheng/gitlearning.git
  1. 本地创建一个项目根目录,取名 localsource,并在该项目中写一些测试代码。
[root@armcli2 ~]# mkdir localsource
[root@armcli2 ~]# 
[root@armcli2 ~]# cd localsource/
[root@armcli2 localsource]# 
[root@armcli2 localsource]# vim echo.sh
#!/bin/bash
for i in {1..9}; do
    echo $i
done
  1. 关联 github 账号,提交本地代码到远程 github 账号对应项目下。
[root@armcli2 localsource]# git init                                                            # 初始化,准备 git 管理
[root@armcli2 localsource]# git remote add origin git@github.com:liangtiansheng/gitlearning.git # 关联 github 账号项目
[root@armcli2 localsource]# git config user.name 'Brinnatt'
[root@armcli2 localsource]# git config user.email "brinnatt@gmail.com"
[root@armcli2 localsource]# 

# 先要把原仓库的代码拉下来合并,不然直接被github服务器拒绝,因为非clone情况下会对比本地和远程服务器代码差异
[root@armcli2 localsource]# git pull origin master                                              # 下载github远程代码同时合并本地代码
[root@armcli2 localsource]# git add .
[root@armcli2 localsource]# git commit -m "my source to master"
[master a6b2265] my source to master
 1 file changed, 4 insertions(+)
 create mode 100644 echo.sh
[root@armcli2 localsource]# 
[root@armcli2 localsource]# git push -u origin master                                           # 提交代码到 github 账号项目下
Counting objects: 4, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 323 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:liangtiansheng/gitlearning.git
   af2b709..a6b2265  master -> master
Branch master set up to track remote branch master from origin.
[root@armcli2 localsource]#
1.6.3.4.3、多人关联 github 项目

接着 1.6.3.4.2 小节实验,再找一台主机 armcli,同样先配置好 ssh 密钥认证(见上文),准备好要提交的本地代码。

  1. 本地创建一个项目根目录,取名 nativesource,并在该项目中写一些测试代码。
[root@armcli ~]# mkdir nativesource
[root@armcli ~]# 
[root@armcli ~]# cd nativesource/
[root@armcli nativesource]# 
[root@armcli nativesource]# vim echo.sh         # 这个文件 1.6.3.4.2 小节已经 push 到远程 github 上了,修改了一点
#!/bin/bash
for i in {1..9}; do
    echo $i
done

echo "succeed!"
[root@armcli nativesource]# vim count.sh        # 新增一个文件
#!/bin/bash
ls /etc | wc -l
  1. 关联 github 账号,提交本地代码到远程 github 账号对应项目下。
[root@armcli nativesource]# git init
[root@armcli nativesource]# git remote add origin git@github.com:liangtiansheng/gitlearning.git     # 关联 github 账号项目
[root@armcli nativesource]# git config user.name 'Susan'                                          # 自报家门
[root@armcli nativesource]# git config user.email 'susan@gmail.com'
[root@armcli nativesource]#
[root@armcli nativesource]# git add .                                   # 添加该文件夹中所有的文件到 git 的暂存区
[root@armcli nativesource]# git commit -m "revise code by Susan"      # 提交所有代码到本机的版本库 
[root@armcli nativesource]# git push -u origin master                   # 直接提交本地版本库代码到github远程服务器
To git@github.com:liangtiansheng/gitlearning.git
 ! [rejected]        master -> master (fetch first)                      # 拒绝
error: failed to push some refs to 'git@github.com:liangtiansheng/gitlearning.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first merge the remote changes (e.g.,
hint: 'git pull') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
  • 很明显,当多人直接提交自己代码的时候会被拒绝,按照错误提示,需要合并操作。
  • git clone 过来的时候,git 不会对比本地和服务器的文件,也就不会有冲突。
  • 建议确定完全覆盖本地的时候用 clone,不确定会不会有冲突的时候用 git pull,将远程服务器的代码 download 下来。
    • git pull = git fetch + git merge
  1. 为了解决多人提交代码可能被拒绝的问题,可以使用以下步骤进行处理。

本地机器在提交自己代码之前做 fetch 操作:

[root@armcli nativesource]# git fetch origin master:test
warning: no common commits
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From github.com:liangtiansheng/gitlearning
 * [new branch]      master     -> test
[root@armcli nativesource]#
  • fetch 是把远程代码作为本地的一个其他分支下载到本地,并不更新本地分支,这里的命令是把远程的 "master" 分支下载到本地作为一个新的分支 "test" 存在。

查看本地文件并没有发生变化

[root@armcli nativesource]# ls
count.sh  echo.sh
[root@armcli nativesource]# cat echo.sh 
#!/bin/bash
for i in {1..9}; do
    echo $i
done

echo "succeed!"
[root@armcli nativesource]# cat count.sh 
#!/bin/bash
ls /etc | wc -l
[root@armcli nativesource]#

用 diff 查看本地 master 分支和 fetch 下来的 test 分支有什么区别:

[root@armcli nativesource]# git diff master test
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c464c7b
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+# gitlearning
\ No newline at end of file
diff --git a/count.sh b/count.sh
deleted file mode 100644
index f1f7f2d..0000000
--- a/count.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-ls /etc | wc -l
diff --git a/echo.sh b/echo.sh
index e7e933c..7969251 100644
--- a/echo.sh
+++ b/echo.sh
@@ -2,5 +2,3 @@
 for i in {1..9}; do
     echo $i
 done
-
-echo "succeed!"
[root@armcli nativesource]#

如果发现 fetch 下来的代码没什么问题,可以选择和本地分支进行合并

[root@armcli nativesource]# git merge test 
Auto-merging echo.sh
CONFLICT (add/add): Merge conflict in echo.sh
Automatic merge failed; fix conflicts and then commit the result.
[root@armcli nativesource]#
  • 发现 echo.sh 这个文件有冲突,这是我们预设的冲突点,上一小节有人提交过 echo.sh,这一小节另外一个主机新建了一个 echo.sh,代码还不完全一样,所以出现了冲突。

查看一下当前的状态和 git 表达 echo.sh 冲突的文件格式,然后手动修改代码,再

# 当前状态
[root@armcli nativesource]# git status
# On branch master
# You have unmerged paths.
#   (fix conflicts and run "git commit")
#
# Changes to be committed:
#
#   new file:   README.md
#
# Unmerged paths:
#   (use "git add <file>..." to mark resolution)
#
#   both added:         echo.sh
#
[root@armcli nativesource]#

# git 表达冲突的格式
[root@armcli nativesource]# cat echo.sh 
#!/bin/bash
for i in {1..9}; do
    echo $i
done
<<<<<<< HEAD

echo "succeed!"
=======
>>>>>>> test

# 修改 echo.sh
[root@armcli nativesource]# vim echo.sh
#!/bin/bash
for i in {1..9}; do
    echo $i
done

echo "succeed!"

# 修改好冲突后,再次提交
[root@armcli nativesource]# git add echo.sh
[root@armcli nativesource]# git commit -m "fix echo.sh confliction"
[master 72cc489] fix echo.sh confliction
[root@armcli nativesource]#
[root@armcli nativesource]# git status 
# On branch master
nothing to commit, working directory clean
[root@armcli nativesource]#
[root@armcli nativesource]# git push -u origin master
Counting objects: 8, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (6/6), 636 bytes | 0 bytes/s, done.
Total 6 (delta 0), reused 0 (delta 0)
To git@github.com:liangtiansheng/gitlearning.git
   a6b2265..72cc489  master -> master
Branch master set up to track remote branch master from origin.
[root@armcli nativesource]#

1.6.4、常用的 git 命令

git 命令可以实现很复杂的软件版本管理系统,但是一般中小型公司很难维护这么复杂的系统,成本太高,所以学习一些基本的用法就足够了。
参见官方手册:https://git-scm.com/book/zh/v2

待补充...

1.6.4.1、基本用法

git basic

上面的四条命令在工作目录、暂存目录(也叫做索引)和仓库之间复制文件。

  • git add files 把当前文件放入暂存区域。
  • git commit 给暂存区域生成快照并提交。
  • git reset 命令用于回退版本,可以指定退回某一次提交的版本。
  • git checkout 命令用于在不同的分支之间切换、恢复文件、创建新分支等操作。
    • git checkout 命令在 Git 2.23 版本后引入了 git switch 和 git restore 命令,分别用于分支切换和文件恢复,以提供更清晰的语义和错误检查。

你可以用 git reset -pgit checkout -p,or git add -p 进入交互模式。

也可以跳过暂存区域直接从仓库取出文件或者直接提交代码。

  • git commit -a 相当于运行 git add 把所有当前目录下的文件加入暂存区域再运行 git commit
  • git commit files 进行一次包含最后一次提交加上工作目录中文件快照的提交。并且文件被添加到暂存区域。
  • git checkout HEAD -- files 回滚到复制最后一次提交。

git basic

1.6.4.2、命令图解

后文中以下面的形式使用图片。

git conventions

绿色的 5 位字符表示提交的 ID,分别指向父节点。分支用橘色显示,分别指向特定的提交。当前分支由附在其上的 HEAD 标识。 这张图片里显示最后 5 次提交,ed489 是最新提交。 main 分支指向此次提交,另一个 stable 分支指向祖父提交节点。

1.6.4.2.1、Diff

有许多种方法查看两次提交之间的变动。下面是一些示例。

git diff

1.6.4.2.2、Commit

提交时,git 用暂存区域的文件创建一个新的提交,并把此时的节点设为父节点。然后把当前分支指向新的提交节点。下图中,当前分支是 main。 在运行命令之前,main 指向 ed489,提交后,main 指向新的节点 f0cec 并以 ed489 作为父节点。

git commit

即便当前分支是某次提交的祖父节点,git 会同样操作。下图中,在 main 分支的祖父节点 stable 分支进行一次提交,生成了 1800b。 这样,stable 分支就不再是 main 分支的祖父节点。此时,合并(或者衍合)是必须的。

git commit

如果想更改一次提交,使用 git commit --amend。git 会使用与当前提交相同的父节点进行一次新提交,旧的提交会被取消。

git commit

另一个例子是分离 HEAD 提交,后文讲。

1.6.4.2.3、Checkout

checkout 命令用于从历史提交(或者暂存区域)中拷贝文件到工作目录,也可用于切换分支。

当给定某个文件名(或者打开 -p 选项,或者文件名和 -p 选项同时打开)时,git 会从指定的提交中拷贝文件到暂存区域和工作目录。比如,git checkout HEAD~ foo.c 会将提交节点 HEAD~(即当前提交节点的父节点)中的 foo.c 复制到工作目录并且加到暂存区域中。(如果命令中没有指定提交节点,则会从暂存区域中拷贝内容。)注意当前分支不会发生变化。

git checkout

当不指定文件名,而是给出一个(本地)分支时,那么 HEAD 标识会移动到那个分支(也就是说,我们“切换”到那个分支了),然后暂存区域和工作目录中的内容会和 HEAD 对应的提交节点一致。新提交节点(下图中的a47c3)中的所有文件都会被复制(到暂存区域和工作目录中);只存在于老的提交节点(ed489)中的文件会被删除;不属于上述两者的文件会被忽略,不受影响。

git checkout

如果既没有指定文件名,也没有指定分支名,而是一个标签、远程分支、SHA-1 值或者是像 main~3 类似的东西,就得到一个匿名分支,称作 detached HEAD(被分离的 HEAD 标识)。这样可以很方便地在历史版本之间互相切换。比如说你想要编译 1.6.6.1 版本的 git,你可以运行 git checkout v1.6.6.1(这是一个标签,而非分支名),编译,安装,然后切换回另一个分支,比如说 git checkout main。然而,当提交操作涉及到 “分离的 HEAD” 时,其行为会略有不同,详情见下面。

git checkout

HEAD 标识处于分离状态时的提交操作

HEAD 处于分离状态(不依附于任一分支)时,提交操作可以正常进行,但是不会更新任何已命名的分支。(你可以认为这是在更新一个匿名分支。)

git commit detached

一旦此后你切换到别的分支,比如说 main,那么这个提交节点(可能)再也不会被引用到,然后就会被丢弃掉了。注意这个命令之后就不会有东西引用 2eecb

git checkou after detached

但是,如果你想保存这个状态,可以用命令 git checkout -b name 来创建一个新的分支。

git checkout b detached

1.6.4.2.4、Reset

reset 命令把当前分支指向另一个位置,并且有选择的变动工作目录和索引。也用来在从历史仓库中复制文件到索引,而不动工作目录。

如果不给选项,那么当前分支指向到那个提交。如果用 --hard 选项,那么工作目录也更新,如果用 --soft 选项,那么都不变。

git reset commit

如果没有给出提交点的版本号,那么默认用 HEAD。这样,分支指向不变,但是索引会回滚到最后一次提交,如果用 --hard 选项,工作目录也同样。

git reset

如果给了文件名(或者 -p 选项),那么工作效果和带文件名的 checkout 差不多,除了索引被更新。

git reset files

1.6.4.2.5、Merge

merge 命令把不同分支合并起来。合并前,索引必须和当前提交相同。如果另一个分支是当前提交的祖父节点,那么合并命令将什么也不做。 另一种情况是如果当前提交是另一个分支的祖父节点,就导致 fast-forward 合并。指向只是简单的移动,并生成一个新的提交。

git merge ff

否则就是一次真正的合并。默认把当前提交( ed489 如下所示)和另一个提交(33104)以及他们的共同祖父节点(b325c)进行一次三方合并。结果是先保存当前目录和索引,然后和父节点 33104 一起做一次新提交。

git merge

1.6.4.2.6、Cherry Pick

cherry-pick 命令"复制"一个提交节点并在当前分支做一次完全一样的新提交。

git cherry pick

1.6.4.2.7、Rebase

衍合是合并命令的另一种选择。合并把两个父分支合并进行一次提交,提交历史不是线性的。衍合在当前分支上重演另一个分支的历史,提交历史是线性的。 本质上,这是线性化的自动的 cherry-pick。

git rebase

上面的命令都在 topic 分支中进行,而不是 main 分支,在 main 分支上重演,并且把分支指向新的节点。注意旧提交没有被引用,将被回收。

要限制回滚范围,使用 --onto 选项。下面的命令在 main 分支上重演当前分支从 169a6 以来的最近几个提交,即 2c33a

git rebase onto

同样有 git rebase --interactive 让你更方便的完成一些复杂操作,比如丢弃、重排、修改、合并提交。没有图片体现这些,细节看这里:git-rebase(1)

说明:

文件内容并没有真正存储在索引(.git/index)或者提交对象中,而是以 blob 的形式分别存储在数据库中(.git/objects),并用 SHA-1 值来校验。 索引文件用识别码列出相关的 blob 文件以及别的数据。

对于提交来说,以树(tree)的形式存储,同样用对于的哈希值识别。树对应着工作目录中的文件夹,树中包含的树或者 blob 对象对应着相应的子目录和文件。每次提交都存储下它的上一级树的识别码。

如果用 detached HEAD 提交,那么最后一次提交会被 the reflog for HEAD 引用。但是过一段时间就失效,最终被回收,与 git commit --amend 或者 git rebase 很像。

1.7、Gitlab Server 部署

aarch64 版本的 Gitlab 在 Centos8 以后都支持,可以直接通过 rpm 包安装,如果是 Centos8 以前,需要手动编译 aarch64 版本,当然也可以使用 x86 版本。下面介绍 Gitlab 一般使用方法,详细教程请参考官方文档 https://docs.gitlab.com/

下载地址:https://packages.gitlab.com/gitlab/gitlab-ce

1.7.1、环境配置

关闭防火墙、SELinux

[root@cide ~]# setenforce 0
[root@cide ~]# yum remove firewalld NetworkManager -y

开启邮件服务

[root@cide ~]# systemctl start postfix
[root@cide ~]# systemctl enable postfix

1.7.2、部署 Gitlab

1.7.2.1、安装 gitlab 依赖包

centos7:
[root@cide ~]# yum install -y curl openssh-server openssh-clients postfix cronie policycoreutils-python

centos8:
[root@cide ~]# yum install -y curl openssh-server openssh-clients postfix cronie policycoreutils-python-utils
  • gitlab-ce 10.x.x 以后的版本需要依赖 policycoreutils-python。

1.7.2.2、添加官方源

[root@cide ~]# curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | sudo bash

因为官方源太慢,可以使用国内 yum 源,配置如下:

[root@cide ~]# vim /etc/yum.repos.d/gitlab-ce.repo
[gitlab-ce]
name=Gitlab CE Repository
baseurl=https://mirrors.cloud.tencent.com/gitlab-ce/yum/el$releasever/
gpgcheck=0
enabled=1

1.7.2.3、安装 Gitlab

[root@cide ~]# yum -y install gitlab-ce             # 自动安装最新版
或:
[root@cide ~]# yum -y install gitlab-ce-x.x.x       # 安装指定版本Gitlab

1.7.2.4、配置 Gitlab

  1. 查看 Gitlab 版本
[root@cide ~]# head -1 /opt/gitlab/version-manifest.txt 
gitlab-ce 14.8.2
  1. Gitlab 配置登录链接
[root@cide ~]# vim /etc/gitlab/gitlab.rb
......
# 没有域名,可以设置为本机 IP 地址
external_url 'http://172.17.0.61'
......

# 绑定监听的域名或 IP
[root@cide ~]# grep "^external_url" /etc/gitlab/gitlab.rb
external_url 'http://192.168.114.129'
  1. 初始化 Gitlab

gitlab 要求语言环境为英文环境,必须切换,切换方法如下:

可以先尝试以下方案

[root@cide ~]# echo "export LC_ALL=en_US.UTF-8"  >>  /etc/profile
  • 语言环境问题:如果碰到之后的解决方案如上操作,需要重新登录。

如果上面的方案不可以,再使用下面的方案

[root@cide ~]# yum install langpacks-zh_CN langpacks-en langpacks-en_GB -y
[root@cide ~]# cat > /etc/profile.d/locale.sh<<-EOF
 export LANG=en_US.UTF-8
 export LANGUAGE=en_US.UTF-8
 export LC_COLLATE=C
 export LC_CTYPE=en_US.UTF-8
 EOF
[root@cide ~]# source /etc/profile.d/locale.sh
  • 退出终端重新登陆

第一次使用配置时间较长

[root@cide ~]# gitlab-ctl reconfigure
.....

1.7.2.5、启动 Gitlab 服务

[root@cide ~]# gitlab-ctl start 
ok: run: alertmanager: (pid 3187) 40s
ok: run: gitaly: (pid 3206) 39s
ok: run: gitlab-exporter: (pid 3160) 43s
ok: run: gitlab-kas: (pid 3130) 44s
ok: run: gitlab-workhorse: (pid 3141) 44s
ok: run: grafana: (pid 3215) 39s
ok: run: logrotate: (pid 2223) 261s
ok: run: nginx: (pid 2699) 152s
ok: run: node-exporter: (pid 3150) 43s
ok: run: postgres-exporter: (pid 3201) 40s
ok: run: postgresql: (pid 2417) 238s
ok: run: prometheus: (pid 3170) 42s
ok: run: puma: (pid 2618) 170s
ok: run: redis: (pid 2254) 255s
ok: run: redis-exporter: (pid 3162) 42s
ok: run: sidekiq: (pid 2635) 164s
[root@cide ~]#
[root@cide ~]# lsof -i:80
COMMAND  PID       USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx   2699       root    7u  IPv4  25593      0t0  TCP *:http (LISTEN)
nginx   2700 gitlab-www    7u  IPv4  25593      0t0  TCP *:http (LISTEN)
nginx   2701 gitlab-www    7u  IPv4  25593      0t0  TCP *:http (LISTEN)
nginx   2702 gitlab-www    7u  IPv4  25593      0t0  TCP *:http (LISTEN)
[root@cide ~]#

1.7.2.6、Gitlab 设置 HTTPS 方式

如果想要 https 方式正常生效使用,则需要把 letsencrypt 自动生成证书的配置打开,这样在执行重新让配置生效命令 (gitlab-ctl reconfigure) 的时候会自动给域名生成免费的证书并自动在 gitlab 自带的 nginx 中加上相关的跳转配置,都是全自动的,非常方便。

[root@cide ~]# vim /etc/gitlab/gitlab.rb
[root@cide ~]# vim /etc/gitlab/gitlab.rb
letsencrypt['enable'] = false
letsencrypt['contact_emails'] = ['1062817308@qq.com']

1.7.2.7、Gitlab 添加 smtp 邮件功能

[root@cide ~]# vim /etc/gitlab/gitlab.rb
......
### Email Settings
gitlab_rails['gitlab_email_enabled'] = true
gitlab_rails['gitlab_email_from'] = '1062817308@qq.com'
gitlab_rails['gitlab_email_display_name'] = 'gitlab'
gitlab_rails['gitlab_email_reply_to'] = '1062817308@qq.com'
gitlab_rails['gitlab_email_subject_suffix'] = '[gitlab]'
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.qq.com"
gitlab_rails['smtp_port'] = 465
gitlab_rails['smtp_user_name'] = "1062817308@qq.com"
gitlab_rails['smtp_password'] = "kktohrvdryglbjjh" # 这是我的 qq 邮箱授权码
gitlab_rails['smtp_domain'] = "smtp.qq.com"
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_tls'] = true
......

# 修改配置后需要初始化配置,先关掉服务再重新初始化
[root@cide ~]# gitlab-ctl stop
[root@cide ~]# gitlab-ctl reconfigure
[root@cide ~]# gitlab-ctl start
  • 前面虽然安装了 postfix,但是这里不打算使用;实际上官方建议使用外部 SMTP Server 方式进行配置,上面就是借用 qq smtp 配置邮件服务器来实现通知;参见 https://docs.gitlab.com/omnibus/settings/smtp.html
  • qq 邮箱授权码要到自己的 qq 邮箱 -> 设置 -> 账户 -> 开启 smtp 服务,进行设置。

1.7.2.8、Gitlab 发送邮件测试

[root@cide ~]# gitlab-rails console
--------------------------------------------------------------------------------
 Ruby:         ruby 2.7.5p203 (2021-11-24 revision f69aeb8314) [x86_64-linux]
 GitLab:       14.8.2 (c7be43f6dd3) FOSS
 GitLab Shell: 13.23.2
 PostgreSQL:   12.7
------------------------------------------------------------[ booted in 28.17s ]
Loading production environment (Rails 6.1.4.6)
// 输入测试命令,回车
irb(main):001:0> Notify.test_email('1062817308@qq.com', 'Message Subject', 'Message Body').deliver_now 
Delivered mail 62275913aa0c4_49e55a64307a9@cide.mail (2163.2ms)
=> #<Mail::Message:270420, Multipart: false, Headers: <Date: Tue, 08 Mar 2022 21:24:35 +0800>, <From: gitlab <1062817308@qq.com>>, <Reply-To: gitlab <1062817308@qq.com>>, <To: 1062817308@qq.com>, <Message-ID: <62275913aa0c4_49e55a64307a9@cide.mail>>, <Subject: Message Subject>, <Mime-Version: 1.0>, <Content-Type: text/html; charset=UTF-8>, <Content-Transfer-Encoding: 7bit>, <Auto-Submitted: auto-generated>, <X-Auto-Response-Suppress: All>>
irb(main):002:0>
  • 去 qq 邮箱 web 界面查看是否收到邮件,经查看已收到邮件,测试成功。

1.7.3、Gitlab 的使用

在浏览器中输入 https://192.168.114.129/,然后 change password,并使用 root 用户登录即可(后续动作根据提示操作)。

1.7.3.1、Gitlab 命令行修改密码

[root@cide ~]# gitlab-rails console -e production
--------------------------------------------------------------------------------
 Ruby:         ruby 2.7.5p203 (2021-11-24 revision f69aeb8314) [x86_64-linux]
 GitLab:       14.8.2 (c7be43f6dd3) FOSS
 GitLab Shell: 13.23.2
 PostgreSQL:   12.7
------------------------------------------------------------[ booted in 35.98s ]
Loading production environment (Rails 6.1.4.6)
irb(main):001:0>
irb(main):021:0> user = User.where(id: 1).first                  # id 为 1 的是超级管理员
=> #<User id:1 @root>
irb(main):022:0> user.password = 'Greatwall487X'               # 密码必须至少8个字符
=> "Greatwall487X"
irb(main):023:0> user.password_confirmation = 'Greatwall487X'
=> "Greatwall487X"
irb(main):024:0> user.save!                                      # 保存如没有问题 返回 true
=> true
irb(main):025:0>

1.7.3.2、Gitlab 服务管理

# gitlab-ctl start                      # 启动所有 gitlab 组件;
# gitlab-ctl stop                       # 停止所有 gitlab 组件;
# gitlab-ctl restart                    # 重启所有 gitlab 组件;
# gitlab-ctl status                     # 查看服务状态;
# gitlab-ctl reconfigure                # 初始化服务;
# vim /etc/gitlab/gitlab.rb             # 修改默认的配置文件;
# gitlab-ctl tail                       # 查看日志;

1.7.3.3、登陆 Gitlab

如果需要手工修改 nginx 的 port ,可以在 gitlab.rb 中设置 nginx['listen_port'] = 8000 ,然后再次 gitlab-ctl reconfigure 即可。

登录 gitlab 如下所示(首次登陆设置 root 密码):
gitlab login

1.7.3.4、创建项目组 group

创建一个名叫 Adapted 项目组:

gitlab group

1.7.3.5、打开用户注册

Menu -> Admin -> Settings -> Sign-up restrictions 如下图勾选,然后拉到最下面保存,重新登录。

gitlab sign up

1.8、Gitlab 开发代码提交流程

1.8.1、公司代码提交合并流程

  1. PM(项目主管/项目经理)在 gitlab 创建任务,分配给开发人员。

  2. 开发人员领取任务后,在本地使用 git clone 拉取代码库。

  3. 开发人员创建开发分支(git checkout -b dev),并进行开发。

  4. 开发人员完成之后,提交到本地仓库(git commit )。

  5. 开发人员在 gitlab 界面上申请分支合并请求(Merge request)。

  6. PM 在 gitlab 上查看提交和代码修改情况,确认无误后,确认将开发人员的分支合并到主分支(master)。

  7. 开发人员在 gitlab 上 Mark done 确认开发完成,并关闭 issue。这一步在提交合并请求时可以通过描述中填写 "close #1" 等字样,可以直接关闭 issue。

1.8.2、创建项目管理用户 Brinnatt

Menu -> Admin -> Overview -> Users -> New user 创建用户 Brinnatt,如下图所示:

gitlab create user

同样的方法,再创建 Eric 、Hellen 用户。用户添加完毕后,gitlab 会给用户发一封修改密码的邮件,各用户需要登录自己的邮箱,并点击相关的链接,设置新密码。

1.8.3、Brinnatt 设为组管理员

Menu -> Admin -> Groups -> Adapted,选择 Brinnatt 用户,角色设为 Owner,点击 Add users to group。

gitlab adduser

1.8.4、Eric、Hellen 设为组 Developer

Menu -> Admin -> Groups -> Adapted,选择 Eric、Hellen 用户,角色设为 Developer,点击 Add users to group。

gitlab_addusers

1.8.5、Brinnatt 登陆创建 Project

gitlab create project

1.8.6、指定项目的存储路径和项目名称

gitlab project detail

1.8.7、为项目创建 Dev 分支

左上角 GitLab -> 选择 Projects -> 左菜单 Repository -> Branched -> New branch,创建 dev 分支,如下图:

gitlab project branch

1.8.8、客户端创建 Brinnatt 用户

[root@cide ~]# useradd Brinnatt
[root@cide ~]# passwd Brinnatt 
Changing password for user Brinnatt.
New password: 
Retype new password: 
passwd: all authentication tokens updated successfully.
[root@cide ~]# su - Brinnatt 
[Brinnatt@cide ~]$
[Brinnatt@cide ~]$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/Brinnatt/.ssh/id_rsa): 
Created directory '/home/Brinnatt/.ssh'.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/Brinnatt/.ssh/id_rsa.
Your public key has been saved in /home/Brinnatt/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:hslPBZSGrqb8/d67o4RRajl65XhKAe81MsiSKKOQISY Brinnatt@cide
The key's randomart image is:
+---[RSA 2048]----+
|       oo.       |
|      . o.       |
|E.  .. .. .      |
|++ o =.* .       |
|* o o.# S        |
|+. .o+ / .       |
|.. o. * =        |
|  o  + + ..      |
|   .. oo+.++     |
+----[SHA256]-----+
[Brinnatt@cide ~]$
[Brinnatt@cide ~]$ cat .ssh/id_rsa.pub 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDaJfDilzrSzjbcmhOwH83FOKFkSRf0WpG34IXjLjkbDrDQEZDApTbbmNKLTgN29WZTT2cpT2dfcpS6m+l2NTWIKVACYpSlTjIYmQBawULqIQzZx3lxnFdGRNbPK2aJvs8uw89oTZaD9F0IsiSkyGljMww0KuUAvJ61eiD9mvkkBfahduJWxRhqSeCAIXr6//ESVIrkbxPa9VcfcuDQW5GFw3/5MgSQW6J/zmnQOQOv62M13+WV4esNUAZXMDw0Bca+YOu2Dkzy6tBR+DkAUH7WVSnunI4twZ3Hmmw6rEb5awrgp6PWEAAnkU+x3Nnm5Qax9k/END6kALeUkLY8PkBT Brinnatt@cide

1.8.9、公钥复制到 gitlab 中

右上角用户菜单 Brinnatt -> Edit profile -> SSH Keys,按提示粘贴公钥,如下图:

gitlab sshkey

1.8.10、Brinnatt 用户配置 git

[Brinnatt@cide ~]$ git config --global user.email 'brinnatt@gmail.com'
[Brinnatt@cide ~]$ git config --global user.name 'brinnatt'
[Brinnatt@cide ~]$ 
[Brinnatt@cide ~]$ git clone git@192.168.114.129:adapted/arm64v8.git
Cloning into 'arm64v8'...
remote: Enumerating objects: 7, done.
remote: Counting objects: 100% (7/7), done.
remote: Compressing objects: 100% (5/5), done.
remote: Total 7 (delta 1), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (7/7), done.
Resolving deltas: 100% (1/1), done.
[Brinnatt@cide ~]$ cd arm64v8/
[Brinnatt@cide arm64v8]$ 
[Brinnatt@cide arm64v8]$ ls
README.md
[Brinnatt@cide arm64v8]$

1.8.11、修改代码并提交到 main 分支

[Brinnatt@cide arm64v8]$ vim echo.sh
#!/bin/bash
echo "brinnatt code to greatwall project whose owner is Brinnatt"

# 注意:可以先查看一下当前分支,如果想提交代码的分支不同会报错,需要手动 checkout 分支
[Brinnatt@cide arm64v8]$ git branch 
* main
[Brinnatt@cide arm64v8]$ git add .
[Brinnatt@cide arm64v8]$ git commit -m "first commit"
[main 1142737] first commit
 1 file changed, 2 insertions(+)
 create mode 100644 echo.sh
[Brinnatt@cide arm64v8]$ 
[Brinnatt@cide arm64v8]$ git push -u origin main
Counting objects: 4, done.
Delta compression using up to 3 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 335 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@192.168.114.129:adapted/arm64v8.git
   14f3e19..1142737  main -> main
Branch main set up to track remote branch main from origin.
[Brinnatt@cide arm64v8]$
  • gitlab 和 github 以后都默认使用 main 分支,不叫 master。

1.8.12、Eric 用户上传公钥到 gitlab

[root@cide ~]# useradd Eric && echo 'Greatwall487X' | passwd --stdin Eric
Changing password for user Eric.
passwd: all authentication tokens updated successfully.
[root@cide ~]#
[root@cide ~]# su - Eric 
[Eric@cide ~]$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/Eric/.ssh/id_rsa): 
Created directory '/home/Eric/.ssh'.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/Eric/.ssh/id_rsa.
Your public key has been saved in /home/Eric/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:+G/FQv61E/W3yN7FyPhTi+ybwAmDqtzv9R4J3IN7ArM Eric@cide
The key's randomart image is:
+---[RSA 2048]----+
|                 |
|                 |
|                 |
|       .o +     .|
|      .+SO +   ..|
|      ..+ O *ooo+|
|     . E.+ @+.=+*|
|  . o   ..= +**o.|
|   o .oo .ooo=o+ |
+----[SHA256]-----+
[Eric@cide ~]$ 

# 需要上传 Eric 公钥到 gitlab Eric 账户 SSH Key 下
[Eric@cide ~]$ cat .ssh/id_rsa.pub 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDkV2T9di6S//LiH6LhxBTxfeI5+ako4PPe5MMvRQ34L2q5GWFm8AWGnvTYDbXbfLg4rBejBRnPoo0Nx5jLUms3IDcPCWJWiNb/bgy0AzpKtCBkUM59RSYFfCdybCE+8ptyP78OCvUyekq18oJoneGLC+SV4+Z9v2EjzoVVB6sAlfjkcX/7x6MTH6qla3ysQrRjU2gw8kQ8J7sfGQ6yN6E8S0fu0JCLspz5H9GSAlROCHGtMptrKS8AoDuxYebmOcALrpCb/J1WKztDRsZpnNhyZmAcA7+3Q9joKklX9OCx6+daCHJa+PnkBjleZTB359gp8R6X95bm8+2XGhoP+eJ Eric@cide
[Eric@cide ~]$

1.8.13、Eric 用户 clone 项目

[Eric@cide ~]$ git config --global user.email 'brinnatt@163.com'
[Eric@cide ~]$ git config --global user.name 'Eric'
[Eric@cide ~]$ 
[Eric@cide ~]$ git clone git@192.168.114.129:adapted/arm64v8.git
Cloning into 'arm64v8'...
The authenticity of host '192.168.114.129 (192.168.114.129)' can't be established.
ECDSA key fingerprint is SHA256:VabnUICGwCT+kVr32Jybbvvpc9VmUSq7Psd0JJv+Jfg.
ECDSA key fingerprint is MD5:18:4f:e6:94:52:5b:b9:98:ca:e3:3c:10:77:ab:a8:d7.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.114.129' (ECDSA) to the list of known hosts.
remote: Enumerating objects: 10, done.
remote: Counting objects: 100% (10/10), done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 10 (delta 1), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (10/10), done.
Resolving deltas: 100% (1/1), done.
[Eric@cide ~]$

1.8.14、Eric 提交代码到 dev 分支

[Eric@cide ~]$ cd arm64v8/
[Eric@cide arm64v8]$ git branch 
* main
[Eric@cide arm64v8]$ ls
echo.sh  README.md
[Eric@cide arm64v8]$ 
[Eric@cide arm64v8]$ git checkout dev
Branch dev set up to track remote branch dev from origin.
Switched to a new branch 'dev'
[Eric@cide arm64v8]$ 
[Eric@cide arm64v8]$ git branch 
* dev
  main
[Eric@cide arm64v8]$ ls
README.md
[Eric@cide arm64v8]$ 
[Eric@cide arm64v8]$ vim eric.sh
[Eric@cide arm64v8]$ cat eric.sh
#!/bin/bash
echo "eric code"
[Eric@cide arm64v8]$ 
[Eric@cide arm64v8]$ git add .
[Eric@cide arm64v8]$ git commit -m "eric devlop"
[dev 0bf9864] eric devlop
 1 file changed, 2 insertions(+)
 create mode 100644 eric.sh
[Eric@cide arm64v8]$ 
[Eric@cide arm64v8]$ 
[Eric@cide arm64v8]$ git push -u origin dev
Counting objects: 4, done.
Delta compression using up to 3 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 296 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: 
remote: To create a merge request for dev, visit:
remote:   https://192.168.114.129/adapted/arm64v8/-/merge_requests/new?merge_request%5Bsource_branch%5D=dev
remote: 
To git@192.168.114.129:adapted/arm64v8.git
   fd95b3a..0bf9864  dev -> dev
Branch dev set up to track remote branch dev from origin.
[Eric@cide arm64v8]$

默认情况下,Developer 角色没有权限提交代码到 main 分支,如下:

[Eric@cide arm64v8]$ git branch 
* dev
  main
[Eric@cide arm64v8]$ git checkout main 
Switched to branch 'main'
[Eric@cide arm64v8]$ ls
echo.sh  README.md
[Eric@cide arm64v8]$ vim ericmain.sh
[Eric@cide arm64v8]$ cat ericmain.sh
#!/bin/bash
echo "Eric tries to push code to main"
[Eric@cide arm64v8]$ 
[Eric@cide arm64v8]$ git branch 
  dev
* main
[Eric@cide arm64v8]$ git add .
[Eric@cide arm64v8]$ git commit -m "eric to main"
[main c73eaee] eric to main
 1 file changed, 2 insertions(+)
 create mode 100644 ericmain.sh
[Eric@cide arm64v8]$ git push -u origin main
Counting objects: 4, done.
Delta compression using up to 3 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 346 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: GitLab: You are not allowed to push code to protected branches on this project.To git@192.168.114.129:adapted/arm64v8.git
 ! [remote rejected] main -> main (pre-receive hook declined)
error: failed to push some refs to 'git@192.168.114.129:adapted/arm64v8.git'
[Eric@cide arm64v8]$

1.8.15、Eric 通过 gitlab web 创建合并请求

merge

1.8.16、Brinnatt 审查执行 merge

gitlab check merge

1.9、Gitlab 备份与恢复

1.9.1、查看系统版本和软件版本

[root@cide ~]# cat /etc/redhat-release 
CentOS Linux release 7.9.2009 (Core)
[root@cide ~]# 
[root@cide ~]# cat /opt/gitlab/embedded/service/gitlab-rails/VERSION 
14.8.2

1.9.2、数据备份

1.9.2.1、查看备份相关的配置项

[root@cide ~]# vim /etc/gitlab/gitlab.rb
gitlab_rails['manage_backup_path'] = true
gitlab_rails['backup_path'] = "/data/gitlab/backups"
[root@cide ~]# mkdir /data/gitlab/backups -pv
[root@cide ~]# gitlab-ctl reconfigure
  • 该项定义了默认备份文件的路径,可以通过修改该配置,并执行 gitlab-ctl reconfigure 重载配置。

1.9.2.2、执行备份命令进行备份

[root@cide ~]# /opt/gitlab/bin/gitlab-rake gitlab:backup:create

1.9.2.3、添加到 crontab 中定时执行

[root@cide ~]# crontab -e
0 2 * * * bash /opt/gitlab/bin/gitlab-rake gitlab:backup:create
  • 可以到 /data/gitlab/backups 找到备份包,解压查看,会发现备份的还是比较全面的,数据库、repositories、build、upload 等分类还是比较清晰的。

1.9.2.4、设置备份保留时长

防止每天执行备份,有目录被爆满的风险,打开 /etc/gitlab/gitlab.rb 配置文件,找到如下配置:

[root@cide ~]# vim /etc/gitlab/gitlab.rb
gitlab_rails['backup_keep_time'] = 604800
  • 设置备份保留 7 天(7 x 3600 x 24 = 604800),秒为单位,如果想增大或减小,可以直接在该处配置,并通过 gitlab-ctl reconfigure 重载配置。

  • 备份完成,会在备份目录中生成一个当天日期的 tar 包。

1.9.3、数据恢复

1.9.3.1、安装部署 gitlab server

具体步骤参见上面:gitlab server 搭建过程

1.9.3.2、恢复 gitlab

1.9.3.2.1、查看备份相关的配置项
[root@cide ~]# vim /etc/gitlab/gitlab.rb
gitlab_rails['backup_path'] = "/data/gitlab/backups"
  • 该路径就是备份时输出备份文件的路径,恢复时需要该路径下的备份文件。
1.9.3.2.2、恢复前需要先停掉数据连接服务
[root@cide ~]# gitlab-ctl stop unicorn
[root@cide ~]# gitlab-ctl stop sidekiq
ok: down: sidekiq: 0s, normally up
  • 如果是台新搭建的主机,不需要操作,理论上不停这两个服务也可以。停这两个服务是为了保证数据一致性。
1.9.3.2.3、同步备份文件到新服务器

将老服务器 /data/gitlab/backups 目录下的备份文件拷贝到新服务器上的 /data/gitlab/backups。

[root@cide ~]# rsync -avz 1646911227_2022_03_10_14.8.2_gitlab_backup.tar 192.168.114.130:/data/gitlab/backups/ 

注意权限:600 权限是无权恢复的。 实验环境可改成了 777,生产环境建议修改属主属组。

[root@cide ~]# cd /data/gitlab/backups/
[root@cide backups]# chown -R git.git 1646911227_2022_03_10_14.8.2_gitlab_backup.tar
[root@cide backups]# ll
total 392
-rw------- 1 git git 399360 Mar 10 19:20 1646911227_2022_03_10_14.8.2_gitlab_backup.tar
1.9.3.2.4、执行命令进行恢复

后面再输入两次 yes 就完成恢复了。

[root@cide backups]# gitlab-rake gitlab:backup:restore BACKUP=1646911227_2022_03_10_14.8.2
  • 后面再输入两次 yes 就完成恢复了。

恢复的时候可能报下面的错误,当前使用的是 gitlab v14.8.2 版本。

Restoring PostgreSQL database gitlabhq_production ... ERROR:  must be owner of extension pg_trgm
ERROR:  must be owner of extension btree_gist
ERROR:  must be owner of extension btree_gist
ERROR:  must be owner of extension pg_trgm

使用下面的步骤解决:

  1. 修改 postgresql 配置
[root@cide ~]# vim /var/opt/gitlab/postgresql/data/postgresql.conf
listen_addresses = '*'    # what IP address(es) to listen on;

# 新增下面两行
[root@cide ~]# vim /var/opt/gitlab/postgresql/data/pg_hba.conf
local   all         all                               trust
host    all         all                               127.0.0.1/32 trust
  1. 重启 gitlab 服务
[root@cide ~]# gitlab-ctl restart
ok: run: alertmanager: (pid 29316) 1s
ok: run: gitaly: (pid 29330) 0s
ok: run: gitlab-exporter: (pid 29346) 0s
ok: run: gitlab-kas: (pid 29348) 1s
ok: run: gitlab-workhorse: (pid 29358) 0s
ok: run: grafana: (pid 29367) 1s
ok: run: logrotate: (pid 29382) 0s
ok: run: nginx: (pid 29388) 1s
ok: run: node-exporter: (pid 29395) 0s
ok: run: postgres-exporter: (pid 29401) 0s
ok: run: postgresql: (pid 29410) 1s
ok: run: prometheus: (pid 29422) 0s
ok: run: puma: (pid 29439) 0s
ok: run: redis: (pid 29444) 1s
ok: run: redis-exporter: (pid 29450) 0s
ok: run: sidekiq: (pid 29533) 1s
[root@cide ~]#
  1. 修改 gitlab 账号为超级用户
[root@cide ~]# su - gitlab-psql
Last login: Thu Mar 10 20:51:03 CST 2022 on pts/0
-sh-4.2$ /opt/gitlab/embedded/bin/psql -h 127.0.0.1 gitlabhq_production
psql (12.7)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

gitlabhq_production=# ALTER USER gitlab WITH SUPERUSER;
ALTER ROLE
gitlabhq_production=# \q
-sh-4.2$
  1. 再次执行恢复命令,不会出现该错误。
1.9.3.2.5、恢复完成启动服务

恢复完成后,启动刚刚的两个服务,或者重启所有服务,再打开浏览器进行访问,发现数据和之前的一致:

[root@cide ~]# gitlab-ctl start unicorn
[root@cide ~]# gitlab-ctl start sidekiq
ok: run: sidekiq: (pid 27384) 0s
[root@cide ~]#

注意:通过备份文件恢复 gitlab 必须保证两台主机的 gitlab 版本一致,否则会提示版本不匹配

标签云