Hello Git
本系列文章为本人学习 Git 的笔记,以供个人纪录和分享。
使用的教材为 Pro Git 。
什么是版本控制?
版本控制是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。
如果有以下几种情况那么你就可能会需要它:
- 你工作相关的文件不止一个,且互相关联。假想以下情况,你修改了文件A,同时由于相关性你也修改了文件B,当你后悔这个修改的时候,你就要将这两个文件都返回为未修改的状态,然而如何确保你不忘记修改文件B?又如何确保你能将两个文件退回到一个相同的版本?这时候你就会需要版本控制;
- 你的甲方有众多需求且易变,使得你不得不开发众多版本,为了协调好这些版本中不同和公用的部分,你也需要版本控制;
- 你工作需要团队协作,为了更好地同步工作进度,并且避免团队中个别成员的失误造成不可逆的影响,又想让每个成员都可以以完整的项目继续功能测试,那么你就需要版本控制;
总而言之,版本控制系统的初衷是为了解决项目开发中的复杂性,其中包括项目自身和人员等方面;这也意味着无脑使用版本控制也并非好事,其本身也会增加复杂性。版本控制系统可以分为三大类:本地版本控制系统;集中化的版本控制系统;分布式版本控制系统。
本地版本控制系统
很多人工作的文件夹中有类似“初版”、“一改”、“二改”、“改中改之最终改”等目录名,用以记录和区分各个版本。后来为了避免手动备份中不可避免的各种失误,开发了本地版本控制系统。
其中最流行的一种叫做 rcs,现今许多计算机系统上都还看得到它的踪影。值得注意的是该版本控制系统靠着记录每次文件的修改来保存不同版本的文件。
集中化的版本控制系统
为了让不同系统上的开发者协同工作,集中化的版本控制系统( Centralized Version Control Systems,简称 CVCS )应运而生。这类系统,诸如 CVS,Subversion 以及 Perforce 等,都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。
而数据集中也会带来风险集中的问题,主机宕机和数据丢失都会造成巨大问题,依靠员工碰巧保存的数据(图上的 Checkout )由于没有版本记录,既无法确认其具体版本,也无法用于重建完整的版本控制系统。
分布式版本控制系统
于是分布式版本控制系统( Distributed Version Control System,简称 DVCS )面世了。在这类系统中,像 Git,Mercurial,Bazaar 以及 Darcs 等,客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来。这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。因为每一次的提取操作,实际上都是一次对代码仓库的完整备份
在原书的语境中将这三种系统的关系视作一个不断上升的过程,本人认为不尽然。相对本地版本控制系统,后两者确实是进步;然而集中式和分布式则不是如此,分布式固然更加灵活更加可靠,但权限上只能限制开发者的提交和修改,从原理上并无法限制开发者获取项目文件,这对开源软件或许没有问题,然而对于闭源软件(没有额外的安全措施下),则增加了数据泄露的风险。并不能通过目前软件开发中 Git 使用最广泛,就认为其是万能的银弹。
什么是 Git ?
Git 是一个开源的分布式版本控制系统。其诞生于 Linux 开源社区的需求中,Linux 的缔造者 Linus Torvalds 对其制定了以下目标:
- 速度
- 简单的设计
- 对非线性开发模式的强力支持
- 完全分布式
- 有能力高效管理类似 Linux 内核一样的超大规模项目
时刻保持数据完整性
Git 使用 SHA-1 算法计算数据的校验和作为文件的指纹,不同版本的不同文件都保有其唯一的指纹。Git 的工作完全依赖于这类指纹字串,所以你会经常看到这样的哈希值。实际上,所有保存在 Git 数据库中的东西都是用此哈希值来作索引的,而不是靠文件名,其由 40 个十六进制字符(0-9 及 a-f)组成,看起来就像是:
1 | 24b9da6552252987aa493b52f8696cd6d3b00373 |
文件索引由文件内容决定,这样子 Git 便可以轻易识别文件内容是否发生改变,并轻易确保文件的一致性。
直接记录文件副本
Linux 直接存储文件的快照,而不是像其他版本控制系统一样关注文件的改动,这为 Git 带来了速度和稳健性,但当一个大文件有一个小修改的时候也会整体备份一边,导致其可能有些滥用存储空间,然而如今的电脑在除极少数情况下,时间复杂度远比空间复杂度来得重要(硬盘总比 CPU 便宜)。开发者每次提交更新时候,Git 会纵览一遍所有文件的指纹信息并对文件作一快照,然后保存一个指向这次快照的索引。为提高性能,若文件没有变化,Git 不会再次保存,而只对上次保存的快照作一链接。
稍后在第三章讨论 Git 分支管理的时候,我们会再看看这样的设计究竟会带来哪些好处。
三个区域、三个状态
在 Git 中任何文件都只有三种状态:已提交(committed)、已修改(modified)以及已暂存(staged)。同时 Git 有三个工作区域:Git 的工作目录(working directory),暂存区域(staging area)以及本地仓库(repository)。其关系如下:
- 在工作目录中修改某些文件,其状态变为已修改;
- 对修改后的文件进行快照,保存到暂存区域,其状态变为已暂存;
- 提交更新,将暂存区的文件快照永久转储到 Git 的本地仓库中,其状态变为以提交。