Git分布式版本控制系统最佳实践

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Git分布式版本控制系统最佳实践相关的知识,希望对你有一定的参考价值。

今天在高铁闲来无事,决定把我之前遗漏的Git好好整理一番。

首先感谢老男孩架构师班赵班长深入讲解Git,综合自己实践整理而来,特此在今天分享给大家。

笔者QQ572891887

Linux架构交流群:471443208

1.1Git诞生历史

我想大家还记得Linustorvalds1991年时发布了Linux操作系统吧,从那以后Linux系统变不断发展壮大,因为Linux系统开源的特性,所以一直接受着来自全球Linux技术爱好者的贡献,志愿者们通过邮件向Linus发送着自己编写的源代码文件,然后由Linus本人通过手工的方式将代码合并,但这样不仅没有效率,而且真的是太痛苦了。
一直到2002年,Linux系统经过十余年的不断发展,代码库已经庞大到无法再让Linus通过手工的方式管理了,但是Linus真的很不喜欢CVS或者Subversion版本控制系统,于是商业公司BitMover决定将其公司的BitKeeper分布式版本控制系统授权给Linux开发社区来免费使用,当时的BitKeeper可以比较文件内容的不同,还能够将出错的文档还原到历史某个状态,Linus终于放下了心里的石头。

技术分享

分布式版本控制流程图

CVSSubversion属于传统的版本控制系统,而分布式版本控制系统最大的特点是不需要每次提交都把文件推送到版本控制服务器,而是采用分布式版本库的机制,使得每个开发人员都够从服务器中克隆一份完整的版本库到自己计算机本地,不必再完全依赖于版本控制服务器,使得源代码的发布和合并更加方便,并且因为数据都在自己本地,不仅效率提高了,而且即便我们离开了网络依然可以执行提交文件、查看历史版本记录、创建分支等等操作,真的是开发者的福音啊。

就这样平静的度过了三年时间,但是Linux社区聚集着太多的黑客人物,2005年时,那位曾经开发Samba服务程序的Andrew因为试图破解BitKeeper软件协议而激怒了BitMover公司,当即决定不再向Linux社区提供免费的软件授权了,此时的Linus其实也早已有自己编写分布式版本控制系统的打算了,于是便用C语言花了2周创建了Git分布式版本控制系统,并上传了Linux系统的源代码。

技术分享

git_logo

Git不仅是一款开源的分布式版本控制系统,而且有其独特的功能特性,例如大多数的分布式版本控制系统只会记录每次文件的变化,说白了就是只会关心文件的内容变化差异,而Git则是关注于文件数据整体的变化,直接会将文件提交时的数据保存成快照,而非仅记录差异内容,并且使用SHA-1加密算法保证数据的完整性。

Git为了提高效率,对于没有被修改的文件,则不会重复存储,而是创建一个链接指向之前存储过的文件。

技术分享

git提交流程图

在正式使用前,我们还需要弄清楚Git的三种重要模式,分别是已提交、已修改、已暂存

已提交(committed):表示数据文件已经顺利提交到Git数据库中。

已修改(modified):表示数据文件已经被修改,但未被保存到Git数据库中。

已暂存(staged):表示数据文件已经被修改,并会在下次提交时提交到Git数据库中。

提交前的数据文件可能会被随意修改或丢失,但只要把文件快照顺利提交到Git数据库中,那就可以完全放心了,流程为:

1.在工作目录中修改数据文件。

2.将文件的快照放入暂存区域。

3.将暂存区域的文件快照提交到Git仓库中。

技术分享

git工作模式

1.2Git环境准备

[[email protected]~]# cat /etc/redhat-release   #查看系统版本

CentOSLinux release 7.1.1503 (Core)

[[email protected]~]# uname -r  #查看内核版本

3.10.0-229.el7.x86_64

[[email protected]~]# getenforce  #确认Selinux关闭状态

Disabled

[[email protected] ~]# systemctlstop firewalld  #关闭防火墙

[[email protected]~]# ifconfig eth0|awk -F ‘[ ]+‘ ‘NR==2{print $3}‘  #查看当前主机IP地址

192.168.56.115

1.3Git安装部署

Git是分布式的版本控制系统,我们只要有了一个原始Git版本仓库,就可以让其他主机克隆走这个原始版本仓库,从而使得一个Git版本仓库可以被同时分布到不同的主机之上,并且每台主机的版本库都是一样的,没有主次之分,极大的保证了数据安全性,并使得用户能够自主选择向那个Git服务器推送文件了,其实部署一个git服务器是非常简单的。

[[email protected]~]# yum install git  #安装Git

[[email protected]~]# git config --global user.name"xubusi"  #配置git使用用户

[[email protected]~]# git config --global user.email"[email protected]"  #配置git使用邮箱

[[email protected]~]# git config --global color.ui true

 

[[email protected]~]# git config --list

user.name=xubusi

[email protected]

color.ui=true

1.4Git常用命令

   add         #添加文件内容至索引

   bisect    #通过二分查找定位引入 bug 的变更

   branch    #列出、创建或删除分支

   checkout   #检出一个分支或路径到工作区

   clone     #克隆一个版本库到一个新目录

   commit    #记录变更到版本库

   diff      #显示提交之间、提交和工作区之间等的差异

   fetch     #从另外一个版本库下载对象和引用

   grep      #输出和模式匹配的行

   init      #创建一个空的 Git 版本库或重新初始化一个已存在的版本库

   log       #显示提交日志

   merge     #合并两个或更多开发历史

   mv        #移动或重命名一个文件、目录或符号链接

   pull      #获取并合并另外的版本库或一个本地分支

   push      #更新远程引用和相关的对象

   rebase    #本地提交转移至更新后的上游分支中

   reset     #重置当前HEAD到指定状态

   rm        #从工作区和索引中删除文件

   show      #显示各种类型的对象

   status    #显示工作区状态

   tag       #创建、列出、删除或校验一个GPG签名的 tag 对象

1.5Git基本操作

1.5.1Git提交数据

我们可以简单的把工作目录理解成是一个被Git服务程序管理的目录,Git会时刻的追踪目录内文件的改动,另外在安装好了Git服务程序后,默认就会创建好了一个叫做master的分支,我们直接可以提交数据到了

[[email protected]~]# mkdir xubusi  #创建本地工作目录

[[email protected]~]# cd xubusi/     #进入本地工作目录

[[email protected]]# git init  #初始为git工作目录

Initializedempty Git repository in /root/xubusi/.git/

[[email protected]]# touch readme #创建文件

 

[[email protected]]# git status  #查看git状态

#Untracked files:

#   (use "git add <file>..." toinclude in what will be committed)

#       readme.txt  #发现新建的readme.txt文件

 

 

[[email protected]]# git add readme.txt  #git添加文件至暂存区

[[email protected]]# git status  #再次查看状态

#Changes to be committed:

#   (use "git rm --cached<file>..." to unstage)

#       new file:   readme.txt #发现新建立的文件readme.txt已经变绿

 

[[email protected]]# git commit -m "thefirst commit"  #git cmmit提交暂存取文件至git版本仓库

[master(root-commit) dde9e40] the first commit

 1 file changed, 1 insertion(+)

 create mode 100644 readme.txt

1.5.2Git移除数据

有些时候会向把已经添加到暂存区的文件移除,但仍然希望文件在工作目录中不丢失,换句话说,就是把文件从追踪清单中删除。

[[email protected]]# touch database  #建立文件

[[email protected]]# git add database   #添加文件至暂存区

[[email protected]]# git status  #查看当前git状态

# Onbranch master

# Yourbranch is ahead of ‘origin/master‘ by 4 commits.

#   (use "git push" to publish yourlocal commits)

#

#Changes to be committed:

#   (use "git reset HEAD<file>..." to unstage)

#

#       new file:   database

[[email protected]]# git rm --cached database  #将文件从git暂存区域的追踪列表移除(并不会删除当前工作目录内的数据文件)

rm‘database‘

[[email protected]]# git status  #此时文件已经是未追踪状态了

# Onbranch master

#Untracked files:

#   (use "git add <file>..." toinclude in what will be committed)

#

#       database

nochanges added to commit (use "git add" and/or "git commit-a")

#如果想将文件数据从git暂存区和工作目录一起删除,可以做如下操作。

[[email protected]]# git add database  #再将database文件提交到git暂存区

[[email protected]]# git rm -f database  #但如果在删除之前数据文件已经被放入到暂存区域的话,git会担心你误删未提交的文件而报错信息,此时可追加强制删除-f参数。

rm‘database‘

[[email protected]]# ls  #查看工作区也没database文件

LICENSE  deploy help.md  readme.txt

[[email protected]]# git status  #查看当前状态

# Onbranch master

nochanges added to commit (use "git add" and/or "git commit-a")

1.5.3Git移动数据

[[email protected]]# git mv readme.txt test.txt  #git如果要修改文件名称,则使用git mv命令

[[email protected]]# git status  #查看状态发现下次提交会有一个改名操作

# Onbranch master

#Changes to be committed:

#   (use "git reset HEAD<file>..." to unstage)

#

#       renamed:    readme.txt -> test.txt

[[email protected]]# git commit -m "changedname"  #提交到git版本仓库

[master88f3791] changed name

 2 files changed, 31 deletions(-)

 delete mode 100644 1

 rename readme.txt => test.txt (100%)

 

#其实可以如下方法改名

[[email protected]]# mv test.txt readme.txt  #先修改名称

[[email protected]]# git rm test.txt  #然后删除git版本仓库内的文件快照

rm‘test.txt‘

[[email protected]]# git add readme.txt  #最后再将新的文件添加进入

[[email protected]]# git commit -m "changedthe file name"  #提交至git版本仓库

[master2caa209] changed the file name

 1 file changed, 0 insertions(+), 0deletions(-)

 rename test.txt => readme.txt (100%)

1.5.4Git历史记录

[[email protected]]# git log  #查看提交历史记录

commit2caa2090efa1aaf5c32524a13c500c1524e0a5ee

Author:xubusi <[email protected]>

Date:   Sat Jan 16 18:32:53 2016 +0800

 

    changed the file name

 

commit88f379175b5ead7e0d84e47bd6db6f5a3b072921

Author:xubusi <[email protected]>

Date:   Sat Jan 16 18:31:03 2016 +0800

 

    changed name

 

commit76c486fcf5d70b6a443ba9e7dad209c6722c8bee

Author:xubusi <[email protected]>

Date:   Sat Jan 16 18:22:39 2016 +0800

 

    tet

[[email protected]]# git log -2  #查看最近几条记录

commit2caa2090efa1aaf5c32524a13c500c1524e0a5ee

Author:xubusi <[email protected]>

Date:   Sat Jan 16 18:32:53 2016 +0800

 

    changed the file name

 

commit88f379175b5ead7e0d84e47bd6db6f5a3b072921

Author:xubusi <[email protected]>

Date:   Sat Jan 16 18:31:03 2016 +0800

 

    changed name

[[email protected]]#

[[email protected]]# git log -p -1  #-p显示每次提交的内容差异,例如仅查看最近一次差异

commit2caa2090efa1aaf5c32524a13c500c1524e0a5ee

Author:xubusi <[email protected]>

Date:   Sat Jan 16 18:32:53 2016 +0800

 

    changed the file name

 

diff--git a/readme.txt b/readme.txt

newfile mode 100644

index0000000..a9b574e

---/dev/null

+++b/readme.txt

@@-0,0 +1,3 @@

+1hehe

+Createnew mode two

+Createnew branch is linux

diff--git a/test.txt b/test.txt

deletedfile mode 100644

indexa9b574e..0000000

---a/test.txt

+++/dev/null

@@-1,3 +0,0 @@

-1hehe

-Createnew mode two

-Createnew branch is linux

[[email protected]]# git log --stat -2#--stat简要显示数据增改行数,这样能够看到提交中修改过的内容,对文件添加或移动的行数,并在最后列出所有增减行的概要信息

commit2caa2090efa1aaf5c32524a13c500c1524e0a5ee

Author:xubusi <[email protected]>

Date:   Sat Jan 16 18:32:53 2016 +0800

 

    changed the file name

 

 readme.txt | 3 +++

 test.txt  | 3 ---

 2 files changed, 3 insertions(+), 3deletions(-)

 

commit88f379175b5ead7e0d84e47bd6db6f5a3b072921

Author:xubusi <[email protected]>

Date:   Sat Jan 16 18:31:03 2016 +0800

 

    changed name

 

 1         | 31 -------------------------------

 readme.txt | 3 ---

 test.txt  |  3 +++

 3 files changed, 3 insertions(+), 34deletions(-)

[[email protected]]# git log --pretty=oneline #--pretty根据不同的格式展示提交的历史信息

2caa2090efa1aaf5c32524a13c500c1524e0a5eechanged the file name

88f379175b5ead7e0d84e47bd6db6f5a3b072921changed name

76c486fcf5d70b6a443ba9e7dad209c6722c8beetet

[[email protected]]# git log --pretty=fuller -2 #以更详细的模式输出提交的历史记录

commit2caa2090efa1aaf5c32524a13c500c1524e0a5ee

Author:     xubusi <[email protected]>

AuthorDate:Sat Jan 16 18:32:53 2016 +0800

Commit:     xubusi <[email protected]>

CommitDate:Sat Jan 16 18:32:53 2016 +0800

 

    changed the file name

 

commit88f379175b5ead7e0d84e47bd6db6f5a3b072921

Author:     xubusi <[email protected]>

AuthorDate:Sat Jan 16 18:31:03 2016 +0800

Commit:     xubusi <[email protected]>

CommitDate:Sat Jan 16 18:31:03 2016 +0800

 

    changed name

 

还可以使用format参数来指定具体的输出格式,这样非常便于后期编程的提取分析哦,常用的格式有:

%s   提交说明。

%cd  提交日期。

%an  作者的名字。

%cn  提交者的姓名。

%ce  提交者的电子邮件。

%H   提交对象的完整SHA-1哈希字串。

%h   提交对象的简短SHA-1哈希字串。

%T   树对象的完整SHA-1哈希字串。

%t   树对象的简短SHA-1哈希字串。

%P   父对象的完整SHA-1哈希字串。

%p   父对象的简短SHA-1哈希字串。

%ad  作者的修订时间。

 

[[email protected]]# git log--pretty=fomat:"%h %cn"#查看当前所有提交记录的简短SHA-1哈希字串与提交着的姓名

fomat:2caa209xubusi

fomat:88f3791xubusi

fomat:76c486fxubusi

1.5.5Git还原数据

[[email protected]]# echo "Git is a versioncontrol system" >> readme.txt#追加一段话

[[email protected]]# git add readme.txt  #添加至暂存区

[[email protected]]# git commit -m"introduction software" #提交至git版本仓库

[master4bf5b29] introduction software

 1 file changed, 1 insertion(+)

 

此时觉得写得不妥,想还原某一次提交的文件快照

[[email protected]]# git log --pretty=oneline #提交的历史信息

4bf5b296db9678f1851b896ed040fe37e6d7efb5introduction software

2caa2090efa1aaf5c32524a13c500c1524e0a5eechanged the file name

88f379175b5ead7e0d84e47bd6db6f5a3b072921changed name

Git服务程序中有一个叫做HEAD的版本指针,当用户申请还原数据时,其实就是将HEAD指针指向到某个特定的提交版本,但是因为Git是分布式版本控制系统,为了避免历史记录冲突,故使用了SHA-1计算出十六进制的哈希字串来区分每个提交版本,另外默认的HEAD版本指针会指向到最近的一次提交版本记录,而上一个提交版本会叫HEAD^,上上一个版本则会叫做HEAD^^,当然一般会用HEAD~5来表示往上数第五个提交版本。

 

[[email protected]]# git reset --hard HEAD^  #还原历史提交版本上一次

HEADis now at 2caa209 changed the file name

[[email protected]]#  cat readme.txt  #查看文件内容(已经还原)

Createnew branch is linux

 

刚刚的操作实际上就是改变了一下HEAD版本指针的位置,就是你将HEAD指针放在那里,那么你的当前工作版本就会定位在那里,要想把内容再还原到最新提交的版本,先看查看下提交版本号

[[email protected]]# git log --pretty=oneline

2caa2090efa1aaf5c32524a13c500c1524e0a5eechanged the file name

88f379175b5ead7e0d84e47bd6db6f5a3b072921changed name

 

怎么搞得?竟然没有了Introduction software这个提交版本记录?

原因很简单,因为我们当前的工作版本是历史的一个提交点,这个历史提交点还没有发生过Introduction software更新记录,所以当然就看不到了,要是想“还原到未来”的历史更新点,可以用git reflog命令来查看所有的历史记录:

 

[[email protected]]# git reflog  #查看未来历史更新点

[email protected]{0}: reset: moving to HEAD^

4bf5b29 [email protected]{1}: commit:introduction software

[email protected]{2}: commit: changed the file name

 

[[email protected]]# git reset --hard4bf5b29  #找到历史还原点的SHA-1值后,就可以还原(值不写全,系统会自动匹配)

HEADis now at 4bf5b29 introduction software

[[email protected]]# cat readme.txt  #查看文件内容(已经还原)

Createnew branch is linux

Git isa version control system

 

如是只是想把某个文件内容还原,就不必这么麻烦,直接用git checkout命令就可以的,先写一段话

[[email protected]]# echo "Some mistkes words">> readme.txt

[[email protected]]# cat readme.txt  #查看内容

Git isa version control system

Somemistkes words

我们突然发现不应该写一句话的,可以手工删除(当内容比较多的时候会很麻烦),还可以将文件内容从暂存区中恢复

[[email protected]]# git checkout -- readme.txt

[[email protected]]# cat readme.txt

Git isa version control system

这其中是有一套规则,如果暂存区中有该文件,则直接从暂存区恢复,如果暂存区没有该文件,则将还原成最近一次文件提交时的快照。

1.6Git管理分支结构

分支即是平行空间,假设你在为某个手机系统研发拍照功能,代码已经完成了80%,但如果将这不完整的代码直接提交到git仓库中,又有可能影响到其他人的工作,此时我们便可以在该软件的项目之上创建一个名叫“拍照功能”的分支,这种分支只会属于你自己,而其他人看不到,等代码编写完成后再与原来的项目主分支合并下即可,这样即能保

以上是关于Git分布式版本控制系统最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

万字详解!Git 入门最佳实践 !

万字详解!Git 从入门到入土最佳实践 !

Git最佳实践-Git flow

保留旧版本的 Git 最佳实践

Git工程开发实践——Git分布式工作流程

GIT分支管理最佳实践