1.何为版本控制
版本控制最主要的功能就是追踪文件的变更,版本控制系统(Version Control System)是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。版本控制系统不仅可以应用于软件源代码的文本文件,而且可以对任何类型的文件进行版本控制。
本地版本控制系统(LVCS) 最开始我们以文件副本的形式来保存一个文件的多个版本,通过复制整个工作目录,加上不同的命名进行区分,但这种方式很难对比每个版本之间的差异,也容易出错。为了解决这个问题,发明了多种本地版本控制系统,采用某种简单的数据库来记录文件的历次更新差异,其中的代表有RCS。
集中式版本控制系统系统(CVCS) 然而,人们发现本地版本控制系统无法进行多人协作,于是集中式版本控制系统系统诞生了,协作者通过客户端连接到集中管理的服务器,取出最新的文件或者提交更新,其中的代表有CSV,SVN。相较于老式的LVCS来说,每个人都可以在一定程度上看到项目中的其他人正在做些什么,管理员也可以轻松掌控每个开发者的权限,并且管理一个 CVCS 要远比在各个客户端上维护本地数据库来得轻松容易。但如果中央服务器出现故障,谁都无法提交更新,也就无法协同工作。如果中心数据库所在的磁盘发生损坏,又没有做恰当备份,就会丢失所有数据,包括项目的整个变更历史,只剩下人们在各自机器上保留的单独快照。
分布式版本控制系统(DVCS)
这类系统中,客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来,包括完整的历史记录。这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。这类系统也可以指定和若干不同的远端代码仓库进行交互,你就可以在同一个项目中,分别和不同工作小组的人相互协作,这些都是集中式系统无法实现的。其中代表有Git,Mercurial等。
分类 | 说明 | 特点 | 代表 |
---|
本地版本控制系统
| 采用简单的数据库来记录文件的历次更新差异 | 方便对比版本差异,无法多人协作 | RCS | 集中式版本控制系统 | 有一个单一的集中管理服务器,保存所有文件的修订版本,协作者都通过客户端连到这台服务器,取出最新的文件或者提交更新 | 方便多人协作,权限管理,服务器压力大,存在数据丢失风险 | SVN | 分布式版本控制系统 | 客户端并不只提取最新版本的文件快照, 而是把代码仓库完整地镜像下来,包括完整的历史记录 | 每个协作者都拥有完成的仓库,可以和不同的远端进行协作 | Git |
2.git简史
从2002年开始,林纳斯·托瓦兹 (Linus Torvalds) 决定使用BitKeeper作为Linux内核主要的版本控制系统用以维护代码。2005年,由于一些原因,BitKeeper公司收回无偿使用BitKeeper的许可,林纳斯·托瓦兹决定自行开发版本控制系统替代BitKeeper,以十天的时间编写出git第一个版本[[1]](https://zh.wikipedia.org/wiki/Git)。林纳斯对SCM的要求是速度快,高效的分支管理与合并,适用大项目,完全分布式。自2005年git问世,随着不断完善,仍保留着其背后对象数据、工作区、分支管理等的优秀的设计理念和最初设定的目标,成为主流的分布式版本控件系统。
3.git特点[[2]](https://git-scm.com/about)
- 分支与合并
- 速度快性能高
- 完全分布式
- 数据一致性
- 暂存区
- 自由开源
4.git设计原理
git是一个内容寻址文件系统,数据以K-V的形式存储在.git目录。通过git init 创建一个新的仓库,查看.git目录内容如下:
$ git init
$ ls -F1 .git
HEAD
config
description
hooks/
info/
objects/
refs/
index
COMMIT_EDITMSG
logs/
-
三种区
- 工作区:是我们直接修改代码的地方
- 暂存区:数据暂时存放的区域,用于在工作区和提交区之间进行数据交流
- 提交区:存放已经提交的数据
可以通过git status 来查看工作区情况 -
数据结构 下面用一个简单git仓库来说明git的三种数据对象,目录内容如下: 我们可以用git cat-file -t <sha1> 来查看一个对象对应的数据类型,git cat-file -p <sha1> 来取出一个对象对应的内容,git cat-file -p master^{tree} 查看master分支对象的tree对象,结果如下图: 可以看到有commit、blob、tree三种数据类型,具体含义是:
-
blob对象:保存文件内容。一个文件对应一条内容,以该内容加上特定头部信息一起的 SHA-1 校验和为文件命名。校验和的前两个字符用于命名子目录,余下的 38 个字符则用作文件名 -
tree对象:记录文件目录和blob数据索引。一个树对象包含了一条或多条树对象记录,每条记录含有一个指向数据对象或者子树对象的 SHA-1 指针,以及相应的模式、类型、文件名信息 -
commit对象:包含着指向前述 tree 对象的指针和所有提交信息。它先指定一个顶层树对象,代表当前项目快照; 然后是可能存在的父提交;之后是作者/提交者信息; 留空一行,最后是提交注释 -
tag对象:轻量标签和附注标签。轻量标签只是某个特定提交的引用,附注标签是存储在 Git 数据库中的一个完整对象, 它们是可以被校验的,其中包含打标签者的名字、电子邮件地址、日期时间, 此外还有一个标签信息。 由此可见,这个简单的仓库整个数据模型是这样子的: 进一步,继续查看.git/objects目录下的具体数据,并与上图可以对应起来 ? -
命令 git命令大致分为主流命令、辅助命令、与其他VCS交互命令、低级命令。可通过git help -a 查看。命令学习网址: Git - Reference (git-scm.com) Git Reference -
引用 引用:用一个文件来保存SHA-1值,用简单的文件名指针来替代原始的 SHA-1 值,这种简单的名字的称为引用 git引用分为HEAD引用、标签引用、远程引用,数据存储在.git/refs 目录下,具体含义是:
-
HEAD引用:通常是一个符号引用,指向目前所在的分支。当你在检出一个标签、提交或远程分支,让你的仓库变成 “分离 HEAD”状态时,HEAD 文件可能会包含一个 git 对象的 SHA-1 值。数据保存在.git/refs/heads -
标签引用:保存标签对象信息,标签引用通常指向一个提交对象,像是一个永不移动的分支引用。数据保存在.git/refs/tags -
远程引用:记录远程服务器上各分支最后已知位置状态。切换分支与commit都不会将本地HEAD指向远程引用,push后HEAD与远程引用指向最新的提交记录。数据保存在.git/refs/remotes 我们继续以上面的data 仓库为例,当前data仓库只有一个master 分支,可以通过git symbolic-ref HEAD 来查看当前HEA指向的分支,整个git数据库看起来如下图 在第一个提交"init" 上创建一个标签v0.1 ,把master分支推送到服务器接着再创建分支test ,新增加一个提交记录"second" ,至此,整个数据情况和分支情况如下: -
分支管理 通过引用的学习,我们知道Git 分支的本质是一个指向某一系列提交之首的指针或引用,因此切换分支只需要移动HEAD指针,删除分支只需要删除分支对应HEAD引用数据,分支管理很快速高效。 -
维护与数据恢复
-
维护:git默认是以松散格式对象存储的,如果有太多松散对象或者太多包文件,Git 会运行一个完整的 gc ,收集所有松散对象并将它们放置到包文件中, 将多个包文件合并为一个大的包文件,移除与任何提交都不相关的陈旧对象。gc的目的是减少磁盘占用体积。包文件存放在.git/objects/pack 目录。可以通过git gc 来触发一次gc 比如我添加了鲁迅-狂人日记.txt(大小约15kb),接着在这个文件末尾插入了读后感,再次将这个文件添加到数据库中,可以看到两次都将这个文件完整的存放到数据库中,占用了30KB,每次都完整的保存会很占用空间(即松散格式对象存储)。那如果 Git 只完整保存其中一个,再保存另一个对象与之前版本的差异内容,岂不更好?可以手动触发一次gc来将这些松散格式对象打包成一个包文件,来减少存储空间。 可以用git cat-file -s <sha1> 查看一个数据对象大小,git verify-pack -v <idx> 查看打包内容 -
恢复:每次HEAD引用发生变化时(如切换分支、commit、reset等),git都会保存在.git/logs/HEAD 文件中,只要数据对象依旧存在数据库中,可以通过git reflog 来进行恢复。 比如误删一个本地分支后进行恢复 -
zlib压缩 git数据压缩采用zlib Home Site
5.git编译
git源码:git/git: Git Source Code Mirror - This is a publish-only repository but pull requests can be turned into patches to the mailing list via GitGitGadget (https://gitgitgadget.github.io/). Please follow Documentation/SubmittingPatches procedure for any of your improvements.
环境:ubuntu-16.04.7
进入到git目录,make 即可
可能出现的错误:
git-compat-util.h:353:25: fatal error: openssl/ssl.h: No such file or directory
sudo apt-get install openssl-dev
git-curl-compat.h:3:23: fatal error: curl/curl.h: No such file or directory sudo apt-get install libcurl4-openssl-dev
http-push.c:22:19: fatal error: expat.h: No such file or directory sudo apt-get install libexpat1-dev
查看生成的可执行文件:
$ find . -maxdepth 1 -name "git-*" | sort
6.参考文档
Git (github.com)
About - Git (git-scm.com)
git-first-commit (github.com)
|