博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Git学习日记(1)——什么是版本控制
阅读量:5110 次
发布时间:2019-06-13

本文共 4040 字,大约阅读时间需要 13 分钟。

版本控制是一种记录若干文件内容变化,以便将来查阅特定版本修订情况的系统。你可以对任何类型的文件进行版本控制。

采用版本控制系统 (VCS)是个明智的选择。有了它你就可以将某个文件回溯到之前的状态,甚至将整个项目都回退到过去某个时间点的状态。你可以比较文件的变化细节,查出最 后是谁修改了哪个地方,从而导致出现怪异问题,又是谁在何时报告了某个功能缺陷等等。使用版本控制系统通常还意味着,就算你乱来一气把整个项目中的文件改 的改删的删,你也照样可以轻松恢复到原先的样子。但额外增加的工作量却微乎其微。

本地版本控制系统

许多人习惯用复制整个项目目录的方式来保存不同的版本,或许还会改名加上备份时间以示区别。这么做唯一的好处就是简单。不过坏处也不少:有时候会混淆所在的工作目录,一旦弄错文件丢了数据就没法撤销恢复。

为了解决这个问题,人们很久以前就开发了许多种本地版本控制系统,大多都是采用某种简单的数据库来记录文件的历次更新差异(见图 1-1)。

 

如何让在不同系统上的开发者协同工作?于是,集中化的版本控制系统( Centralized Version Control Systems,简称 CVCS )应运而生。这类系统,诸如 CVS,Subversion 以及 Perforce 等,都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。多年以来,这 已成为版本控制系统的标准做法(见图 1-2)。

图 1-2. 集中化的版本控制系统

这种做法带来了许多好处,特别是相较于老式的本地 VCS 来说。现在,每个人都可以在一定程度上看到项目中的其他人正在做些什么。而管理员也可以轻松掌控每个开发者的权限,并且管理一个 CVCS 要远比在各个客户端上维护本地数据库来得轻松容易。

事分两面,有好有坏。这么做最显而易见的缺点是中央服务器的单点故障。如果宕机一小时,那么在这一小时内,谁都无法提交更新,也就无法协同工作。要 是中央服务器的磁盘发生故障,碰巧没做备份,或者备份不够及时,就还是会有丢失数据的风险。最坏的情况是彻底丢失整个项目的所有历史更改记录,而被客户端 提取出来的某些快照数据除外,但这样的话依然是个问题,你不能保证所有的数据都已经有人事先完整提取出来过。本地版本控制系统也存在类似问题,只要整个项 目的历史记录被保存在单一位置,就有丢失所有历史更新记录的风险。

分布式版本控制系统( Distributed Version Control System,简称 DVCS )面世了。在这类系统中,像 Git,Mercurial,Bazaar 以及 Darcs 等,客户端并不只提取最新版本的文件快照,而是把原始的代码仓库完整地镜像下来。这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜 像出来的本地仓库恢复。因为每一次的提取操作,实际上都是一次对代码仓库的完整备份(见图 1-3)。

 

图 1-3. 分布式版本控制系统

 

更进一步,许多这类系统都可以指定和若干不同的远端代码仓库进行交互。籍此,你就可以在同一个项目中,分别和不同工作小组的人相互协作。你可以根据需要设定不同的协作流程,比如层次模型式的工作流,而这在以前的集中式系统中是无法实现的。

直接记录快照,而非差异比较

Git 和其他版本控制系统的主要差别在于,Git 只关心文件数据的整体是否发生变化,而大多数其他系统则只关心文件内容的具体差异。这类系统 (CVS,Subversion,Perforce,Bazaar 等等)每次记录有哪些文件作了更新,以及都更新了哪些行的什么内容,请看图 1-4。

 

图 1-4. 其他系统在每个版本中记录着各个文件的具体差异

 

Git 并不保存这些前后变化的差异数据。实际上,Git 更像是把变化的文件作快照后,记录在一个微型的文件系统中。每次提交更新时,它会纵览一遍所有文件的指纹信息并对文件作一快照,然后保存一个指向这次快照 的索引。为提高性能,若文件没有变化,Git 不会再次保存,而只对上次保存的快照作一链接。Git 的工作方式就像图 1-5 所示。

 

图 1-5. Git 保存每次更新时的文件快照

 

这是 Git 同其他系统的重要区别。它完全颠覆了传统版本控制的套路,并对各个环节的实现方式作了新的设计。Git 更像是个小型的文件系统,但它同时还提供了许多以此为基础的超强工具,而不只是一个简单的 VCS。稍后在第三章讨论 Git 分支管理的时候,我们会再看看这样的设计究竟会带来哪些好处。

 

在 Git 中的绝大多数操作都只需要访问本地文件和资源,不用连网。但如果用 CVCS 的话,差不多所有操作都需要连接网络。因为 Git 在本地磁盘上就保存着所有当前项目的历史更新,所以处理起来速度飞快。

举个例子,如果要浏览项目的历史更新摘要,Git 不用跑到外面的服务器上去取数据回来,而直接从本地数据库读取后展示给你看。所以任何时候你都可以马上翻阅,无需等待。如果想要看当前版本的文件和一个月 前的版本之间有何差异,Git 会取出一个月前的快照和当前文件作一次差异运算,而不用请求远程服务器来做这件事,或是把老版本的文件拉到本地来作比较。

用 CVCS 的话,没有网络或者断开 VPN 你就无法做任何事情。但用 Git 的话,就算你在飞机或者火车上,都可以非常愉快地频繁提交更新,等到了有网络的时候再上传到远程仓库。同样,在回家的路上,不用连接 VPN 你也可以继续工作。换作其他版本控制系统,这么做几乎不可能,抑或非常麻烦。比如 Perforce,如果不连到服务器,几乎什么都做不了(译注:默认无法发出命令p4 edit file 开始编辑文件,因为 Perforce 需要联网通知系统声明该文件正在被谁修订。但实际上手工修改文件权限可以绕过这个限制,只是完成后还是无法提交更新。);如果是 Subversion 或 CVS,虽然可以编辑文件,但无法提交更新,因为数据库在网络上。看上去好像这些都不是什么大问题,但实际体验过之后,你就会惊喜地发现,这其实是会带来很大不同的。

时刻保持数据完整性

在保存到 Git 之前,所有数据都要进行内容的校验和(checksum)计算,并将此结果作为数据的唯一标识和索引。换句话说,不可能在你修改了文件或目录之后,Git 一无所知。这项特性作为 Git 的设计哲学,建在整体架构的最底层。所以如果文件在传输时变得不完整,或者磁盘损坏导致文件数据缺失,Git 都能立即察觉。

Git 使用 SHA-1 算法计算数据的校验和,通过对文件的内容或目录的结构计算出一个 SHA-1 哈希值,作为指纹字符串。该字串由 40 个十六进制字符(0-9 及 a-f)组成,看起来就像是:

1
24b9da6552252987aa493b52f8696cd6d3b00373

Git 的工作完全依赖于这类指纹字串,所以你会经常看到这样的哈希值。实际上,所有保存在 Git 数据库中的东西都是用此哈希值来作索引的,而不是靠文件名。

多数操作仅添加数据

常用的 Git 操作大多仅仅是把数据添加到数据库。因为任何一种不可逆的操作,比如删除数据,都会使回退或重现历史版本变得困难重重。在别的 VCS 中,若还未提交更新,就有可能丢失或者混淆一些修改的内容,但在 Git 里,一旦提交快照之后就完全不用担心丢失数据,特别是养成定期推送到其他仓库的习惯的话。

这种高可靠性令我们的开发工作安心不少,尽管去做各种试验性的尝试好了,再怎样也不会弄丢数据。至于 Git 内部究竟是如何保存和恢复数据的,我们会在第九章讨论 Git 内部原理时再作详述。

文件的三种状态

好,现在请注意,接下来要讲的概念非常重要。对于任何一个文件,在 Git 内都只有三种状态:已提交(committed),已修改(modified)和已暂存(staged)。已提交表示该文件已经被安全地保存在本地数据库 中了;已修改表示修改了某个文件,但还没有提交保存;已暂存表示把已修改的文件放在下次提交时要保存的清单中。

由此我们看到 Git 管理项目时,文件流转的三个工作区域:Git 的工作目录,暂存区域,以及本地仓库。

图 1-6. 工作目录,暂存区域,以及本地仓库

每个项目都有一个 Git 目录(译注:如果 git clone 出来的话,就是其中 .git 的目录;如果git clone --bare 的话,新建的目录本身就是 Git 目录。),它是 Git 用来保存元数据和对象数据库的地方。该目录非常重要,每次克隆镜像仓库的时候,实际拷贝的就是这个目录里面的数据。

从项目中取出某个版本的所有文件和目录,用以开始后续工作的叫做工作目录。这些文件实际上都是从 Git 目录中的压缩对象数据库中提取出来的,接下来就可以在工作目录中对这些文件进行编辑。

所谓的暂存区域只不过是个简单的文件,一般都放在 Git 目录中。有时候人们会把这个文件叫做索引文件,不过标准说法还是叫暂存区域。

基本的 Git 工作流程如下:

1. 在工作目录中修改某些文件。 2. 对修改后的文件进行快照,然后保存到暂存区域。 3. 提交更新,将保存在暂存区域的文件快照永久转储到 Git 目录中。

所以,我们可以从文件所处的位置来判断状态:如果是 Git 目录中保存着的特定版本文件,就属于已提交状态;如果作了修改并已放入暂存区域,就属于已暂存状态;如果自上次取出后,作了修改但还没有放到暂存区域,就 是已修改状态。到第二章的时候,我们会进一步了解其中细节,并学会如何根据文件状态实施后续操作,以及怎样跳过暂存直接提交。

 

转载于:https://www.cnblogs.com/amywu2015/p/4974374.html

你可能感兴趣的文章
http方式接口响应实现步骤
查看>>
[转]Java compiler level does not match解决方法
查看>>
多线程中的Lock小结
查看>>
[算法]和为S的两个数字
查看>>
【Lintcode】104.Merge k Sorted Lists
查看>>
怎样把U盘制成驱动盘?
查看>>
Python多线程,多进程,并行,并发,异步编程
查看>>
配置storeconfigs以及解决 Error 400 on SERVER: Could not autoload active_record
查看>>
git 添加新分支后可能报错及解决方案
查看>>
signalR的集群与负载均衡
查看>>
KEILC51编译问题ERROR L104: MULTIPLE PUBLIC DEFINITIONS重复定义
查看>>
PHP反射类的理解(代码篇)
查看>>
怎么安装Apache,php,mysql (二)——php和apache怎么配置mysql?
查看>>
android:hint属性对TextView的影响
查看>>
opencv源代码分析:icvGetTrainingDataCallback简单介绍
查看>>
MVC返回JSON,IE下无法接收JSON,IE下JSON提示另存为
查看>>
Python元类(metaclass)以及元类实现单例模式
查看>>
Codeforces.GYM101612E.Equal Numbers(贪心)
查看>>
树莓派开启SSH
查看>>
大数据Hadoop Hive HBase Spark Storm
查看>>