本文主要介绍Git的入门知识。首先讲述版本控制工具的一些背景, 然后介绍如何在你自己的系统上安装.配置和运行Git。学完本文,你将明白Git是怎么来的、为什么需要Git,并掌握使用Git的基础知识。
一、版本控制
什么是“版本控制”,为什么需要它?版本控制是一套系统,该系统按时间顺序记录某一个或一系列文件的变更,让你可以查看其以前的特定版本。以软件源代码文件为例讲解版本控制的方法,但实际上这种方法对于计算机上几乎所有文件类型都适用。
如果你是一位平面或网页设计师,那么可能(几乎必然)想要保存一幅图片或一个布局的每一个版本, 这时使用版本控制系统( vcs )就是非常明智的选择。使用版本控制系统,你可以将文件或整个项目恢复到先前的状态,还可以比对文件随时间的变更,查看什么人最后做出的更改可能会造成麻烦,谁在何时引入了一个问题,等等。使用版本控制系统通常意味着,如果你把事情搞砸了或是弄丢了文件,都可以轻而易举地恢复原状。而且,你要为所有这些福利付出的开销也很低。
1.1 本地版本控制系统
很多人控制版本的方法是将文件复制到另一个文件目录下(如果他们够聪明,还会给目录加上时间戳)。这种做法之所以常见,是因为它实现起来非常简单。然而它又非常容易导致错误,你很容易忘记当前所处的目录,不小心写入了错误的文件,或是把不该覆盖的文件给覆盖掉了。
为了解决这个问题,开发人员在很久以前就开发了一些本地版本控制系统,使用简单的数据库来保存文件的所有变更。
RCS是一个常用的VCS工具,至今还部署在很多计算机上。在流行的MacOS X操作系统中,只要你安装了开发者工具,就会包含一个rcs命令。RCS会在磁盘上以一种特殊的格式保存补丁集( patch set,也就是文件之间的差异)。通过叠加补丁来将文件恢复到某个历史状态。
1.2 集中式版本控制系统
另一个主要的问题,是不同系统上开发人员之间的协作。为了解决这个难题,集中式版本控制系统( Centralized Version Control System, CVCS)应运而生。像CVS、Subversion以及Perforce这类系统,都有一个包含文件所有修订版本的单一服务 器,多个客户端可以从这个中心位置检出文件。多年以来,这已成为版本控制的标准。
这种方案有多方面的优势,尤其是与本地版本控制系统相比。例如,所有人都可以在一定程度上掌握其他人在项目中都做了什么,管理员可以精细地控制每个人的权限;同时,维护一个集中式版本控制系统要比在每台客户机上都维护一个数据库简单得多。
然而,这种做法也存在一些严 重的缺陷。最显著的一点,就是集中式服务器所带来的单点故障。如果服务器宕机一小时,那么在这期间任何人都不能协作或提交更改。如果中央数据库所在的硬盘受损,备份也没保住,那你可就一无所有了: 除了人们保存在各自本地机器上的快照,项目的整个历史记录全都没了。本地版本控制系统也会碰到同样的问题,只要你将项目完整的历史记录保存在一个地方,搞不好就会全盘皆无。
1.3 分布式版本控制系统
分布式版本控制系统( Distributed Version Control System, DVCS)就是为了解决这一问题 而出现的。对于一个分布式版本控制系统(比如Git、Mercurial 、Bazaar或Darcs) 来说,客户端并非仅仅是检出文件的最新快照,而是对代码仓库( repository )进行完整的镜像。这样一来,不管是哪个服务器出现故障,任何一个客户端都可以使用自己的本地镜像来恢复服务器。每一次检出操作实际上都是对数据的一次完整备份。
不仅如此,许多分布式版本控制系统可以很好地处理多个远程仓库,因此你可以与不同的人以不同的方式就同一个项目进行协作。如此一来,你就可以设置诸如层次模型等不同类型的工作流,而这在集中式系统中是不可能的。
二、Git简史
同许多伟大的事物一样,Git的诞生伴随着些许颠覆式的创新以及激烈的争论。Linux内核是一个超大规模的开源软件项目。在Linux内核大部分的维护时间里( 1991~2002 ),其更新都是通过传递补丁和归档文件来实现的。在2002年, Linux内 核项目开始采用一个叫作BitKeeper的专有分布式版本控制系统。
2005年,Linux内核开发者社区与BitKeeper的研发公司关系破裂,该公司收回了软件的免费使用权。这促使Linux开发社区(尤其是Linux之父林纳斯. 托瓦兹)在汲取BitKeeper使用过程中的经验教训的基础上,开发出了自己的版本控制系统。新系统的一些目标如下:
- 速度快
- 设计简洁
- 对于非线性开发强有力的支持(数以千计的并行分支)
- 完全的分布式设计
- 能够有效地处理像Linux内核这种大型项目(速度以及数据量)
自2005年诞生以来,Git不断发展,日趋成熟易用,同时仍保留着最初的这些品质。它的速度飞快,处理大型项目时效率极高,有着一套 令人惊叹的非线性开发分支系统。
三、Git基础
那么,简单来说,Git到底是什么?这是一个非常重要的问题,因为如果你正确理解了Git的基本思想和工作原理,那么就更容易发挥其功效。在学习Git的过程中,试着忘掉你在Subversion和Perforce这类VCS中学到的那些东西,否则容易引起混淆。尽管用户界面相差无几,但是在存储信息与对待信息的方式上,Git与其他版本控制系统大不相同,理解这些差异有助于避免使用中的困惑。
3.1 快照,而非差异
Git与其他版本控制系统(包括Subversion等)最大的不同在于其对待数据的方式。从概念上来说,其他大多数版本控制系统以文件变化列表的方式存储信息。这类系统( CVS、Subversion、Perforce、Bazaar等 )将其存储的信息视为一组文件以及对这些文件随时间所做出的变更。
Git并没有采用这种方式对待或存储数据。它更像是将数据视为一个微型文件系统的一组快照。每次提交或在Git中保存项目的状态时,Git基本上会抓取一张所有文件当前状态的快照,然后存储一个指向该快照的引用。出于效率的考虑,如果文件并没有发生变动,Git则不会再重新保存文件,而只是留下一个指向先前已保存过的相同文件的链接。Git更 多的是将数据作为一个快照流。
这是Git与其他绝大部分版本控制系统的一处重要区别。它使得Git对那些沿袭自上一代版本控制系统中的几乎每个方面进行了重新考量。比起单纯的版本控制系统,Git更像是一个微型文件系统,另外还包含了一些建立在该系统之上的强大工具。在第3章讲到Git分支时,我们会探究这种数据思考方式所带来的益处。
3.2 几乎所有操作都在本地执行
Git中的大部分操作只需要用到本地文件和资源,一般无需从网络中的其他计算机中获取信息。如果你之前用的是集中式版本控制系统,习惯了多数操作都有网络延时开销,Git的这种特性会让你觉得速度之神赐予了Git不可思议的力量。因为项目完整的历史记录都存放在本地磁盘上,所以绝大多数操作几乎瞬间就能完成。
比如说,浏览项目的历史记录时,Git根本不需要到服务器上获取历史信息然后再展示出来,它只需要直接从本地数据库中读取就行了。这意味着你瞬间就能看到项目历史。如果你比较文件的当前版本与上个月的版本有什么不同,Git可以找到一个月之前的该文件,然后在本地进行差异计算,既不需要麻烦远程服务器,也不需要从远程服务器上将旧版本的文件拉取到本地再进行处理。
这同样意味着即便是处于离线状态或是断掉了VPN,你仍然可以执行几乎所有的操作。要是你在飞机上或者火车上想干点活儿,大可畅快地进行提交操作,等到有了网络连接之后再完成上传就行了。如果你在家没法使用VPN客户端,那也不会影响工作。要想在很多别的版本控制系统中这么做,要么是不可能,要么会让你抓耳挠腮。比如说,在Perforce中如果没有连上服务器,你干不了多少事;在Subversion 和CVS中,你可以编辑文件,但是没法向数据库提交变更(因为你的数据库处于离线状态)。这可能看起来也没什么大不了的,但由此引发的巨大差异也许会让你大吃一惊。
3.3 Git的完整性
Git中的所有数据在存储前都会执行校验和计算,随后以校验和来引用对应的数据。这意味着不可能在Git不知情的情况下更改文件或目录的内容。这项功能根植于Git的最底层,是其设计理念中不可或缺的一环。只要有Git在,它就能检测出传输过程中丢失的信息或者受损的文件。Git所采用的校验和机制叫作SHA-1散列。这是一个由40个十六进制字符( 0-9和a-f)所组成的字符串,它是根据文件内容或Git的目录结构计算所得到的。一个SHA-1散列类似于如下的字符串:
24b9da6552252987aa493b52f8696cd6d3b00373
因为用途极广,你在Git中到处都会看到这种散列值。实际上,Git并不是通过文件名在数据库中存储信息,而是通过信息的散列值。
3.4 Git通常只增加数据
当你在Git中进行处理时,基本上所有的操作都只是向Git数据库中添加数据。很难让系统执行无法撤销的操作或是把数据搞丢。与其他版本控制系统一样, 在Git中你有 可能会弄丟或弄乱尚未提交的变更,不过一旦向Git提交了快照,那就不大可能会丢失了,尤其是在你还会定期向其他仓库推送数据库时。
这使得使用Git充满了乐趣,因为我们知道自己可以尽情实验,反正不会有搞砸的风险。
3.5 三种状态
现在要注意了,如果你希望一帆风顺地完成余下的学习过程,一定要记住下面的内容。在Git中,文件可以处于以下三种状态之一已提交( committed)、已修改( modified)和已暂存( staged)。已提交表示数据已经被安全地存入本地数据库中。已修改表示已经改动了文件,但尚未提交到数据库。已暂存表示对已修改文件的当前版本做出了标识并将其加入下一次要提交的快照中。
由此便引人了Git项目中三个主要的区域: Git目录、工作目录以及暂存区。
Git目录是Git保存项目元数据和对象数据库的地方。这是Git最重要的部分,也是从其他计算机中克隆仓库时要复制的内容。
工作目录是项目某个版本的单次检出。这些文件从Git目录下的压缩数据库内被提取出,放置在磁盘上以供使用或修改。
暂存区是一个文件,一般位于Git目录中。它保存了下次所要提交内容的相关信息。有时候它也被称为“索引”,不过通常还是叫作暂存区。
Git的基本工作流如下:
- (1)修改工作目录中的文件;
- (2)暂存文件,将这些文件的快照加入暂存区;
- (3)提交暂存区中的文件,将快照永久地保存在Git目录中。
如果一个文件的某个特定版本出现在Git目录中,该版本的文件就被认为处于已提交状态。如果这个文件已被修改,并且已被放入暂存区,那么它就处于已暂存状态。如果在上次检出之后文件发生了变更,但并没有被暂存,则处于已修改状态。
四、 命令行
从最初的命令行工具到各种功能各异的GUI, Git的使用方法各式各样。我们将在命令行中使用Git。一方面是因为命令行是唯一可以执行所有Git命令的地方,大多数GUI出于简化的目的,只实现了Git的部分功能。如果你知道如何使用命令行,那大概也能猜出如何使用GUI;不过,反过来可就不一定了。另一方面,尽管图形化客户端的选择属于个人喜好问题,但命令行工具是所有的Git用户都拥有的。
因此我们假定你知道如何在Mac下打开终端,如何在Windows下打开命令行提示符或Powershell。如果你还不知道这些命令行工具,最好还是先停下来,赶紧补补功课,以便能够跟上随后的内容。
五、安装Git
开始使用Git之前,你得先把它安装在计算机上。就算是已经安装过了,也最好更新到最新版。你可以通过软件包或者安装程序来安装,也可以下载源代码自行编译。
5.1 Linux上的安装方法
如果你想在Linux中通过二进制安装程序来安装Git,通常得借助所使用的发行版中的软件包管理工具。以Fedora为例, 你可以使用yum:
$ sudo yum install git-all
要是你用的是像Ubuntu这种基于Debian的发行版,可以使用apt-get:
$ sudo apt-get install git-all
要想了解更多的方法,可以到Git的官 方网站: http//:git-scm.com/download/linux, 那里介绍
了在各种Unix版本中安装Git的操作步骤。
5.2 Windows. 上的安装方法
在Windows中安装Git的方法也有好几种。官方版本可以在Git的网站上下载。只需要进入http//git-scm.com/download/win就会自动开始下载。要注意这是一个叫作Git for Windows的项目,该项目独立于Git。
另一种简单的方法是安装Windows版的GitHub。这个安装程序既包括命令行版本的Git,也包括GUI。它在Powershell下也运行良好,另外还提供了稳定的凭证缓存( credential cache)以及健全的CRLF设置。我们随后会学习有关这些内容的更多细节,现在可以说你需要的东西已经应有
尽有了。
六、Git的首次配置
Git现在已经在系统中安家落户了,你接下来需要自定义一下Git环境。这些自定义工作只需要在计算机上执行一次,就算是以后升级,已配置好的环境也会如影随形。你也可以随时执行命:令来修改环境设置。
Git包含了一个叫作git config的工具, 可以用来获取和设置配置变量,这些变量控制着Git外观和操作的方方面面。可以将配置变量存储在三个不同的位置。
(1) /etc/gitconfig文件: 包含了系统中所有用户及其仓库的值。如果你向git config传入--system选项,那么它就会专门从该文件中读写配置变量。
(2) ~/.gitconfig或~/.config/git/config文件:针对的是你自己。你可以通过传入--global选项使Git专门从该文件中读写配置变量。
(3)当前仓库的Git目录(也就是.git/config )中的config文件:针对单个仓库。
每一级都会覆盖上一级中的设置,因此.git/config中 的值要优于/etc/gitconfig中的值。
在Windows系统中,Git会 在$HOME目录中(对于多数人来说就是C:\Users\$USER )查找.gitconfig文件。它也查找/etc/gitconfig,不过这是相对于MSys的根目录,该目录是在安装程序运行时你所选择的安装目录。
6.1 用户身份
安装好Git后的第一件事就是设置用户名和电子邮件地址。这一步 非常重要,因为Git的每一次提交都需要用到这些信息,而且还会被写人到所创建的提交中,不可更改。设置命令如下:
$ git config --global user.name "your name xxx"
$ git config --global user.email xxx@example.com
如果传入了--global选项,那只需要设置一次就行了,之后不管在系统中执行什么操作,Git都会使用这些已设置好的信息。如果你想在某个项目中使用不同的用户名或电子邮件地址,可以在项目中使用不带--global选项的命令。
很多图形界面工具首次运行的时候都会帮你完成以上设置。
6.2 个人编辑器
设置好身份信息之后就可以配置默认的文本编辑器了,当Git需 要输人消息的时候会用到这个编辑器。如果没有配置,Git会使用系统默认的编辑器。
如果你想使用不同的文本编辑器,比如Emacs,可以执行以下命令。
$ git config --global core.editor emacs
在Windows系统中,如果你想使用不同的文本编辑器,例如Notepad++,可以执行下列操作。
在x86系统上:
$ git config --global core.editor "'C:/Progran Files/Notepad++/notepad++.exe' -multiInst -nosession"
在x64系统上:
$ git config --global core.editor "'C:/Program Files (x86)/Notepad++/notepad++.exe' -multiInst"
6.3 检查个人设置
如果想查看你的设置,可以通过执行git config --list命令来列出当前Git可以找到的所有设置,如下所示。
$ git config --list
user.name=xxx
user.email=xxx@example.com
color.status=auto
color.branch=auto
color.interactive=auto
color.diff=auto
你可能会多次看到同一个键的输出,这是因为Git会从不同文件(例如/etc/gitconfig和~.gitconfig)中读取相同的键。这种情况下,Git会使用这个键最后输出的值。
你可以通过键入git config <key>来查看Git中当前某个键的值,如下所示。
$ git config user.name
you name xxx
七、获取帮助
如果在使用Git的过程中需要帮助,有以下三种方法可以查看Git任何命令的帮助页面。
$ git help <verb>
$ git <verb> --help
$ man git-<verb>
例如,可以通过执行以下命令获得config命令的帮助信息。
$ git help config
你可以在任何时候键入以上命令来获取帮助,即使在离线的情况下。