十分钟理解 Git 原理
历史
2002 年,Linus(Linux 作者)决定使用 BitKeeper 作为 Linux 内核主要的版本控制系统。Linus 曾考虑过采用现成软件作为版本控制系统,但这些软件都存在一些问题,比如:性能不佳。
2005 年,Andrew(Samba 作者)写了一个简单程序,可以连接 BitKeeper 的存储库,BitKeeper 作者反对这种逆向工程的行为,因此收回了无偿使用 BitKeeper 的许可。Linux 内核开发团队与其磋商无果后,Linus 决定自行开发版本控制系统替代 BitKeeper,然后用了十天的时间编写出 Git。
Git(英国俚语“混帐”)名字来源于 Linus 的自嘲:
I’m an egotistical bastard, and I name all my projects after myself. First Linux, now Git.
基本原理
因为 Git 是一个分布式版本控制系统,因此 Git 的操作大部分都是在本地的,除非明确说明,下面的原理或命令都是本地操作。
每个 Git 项目的根目录下有一个 [代码].git[代码] 目录,它是 Git 默默进行版本控制时读写的“数据库”。有几个概念需要提一下:
工作区:代码所在目录;
暂存区: [代码].git/index[代码] 文件;
本地仓库: [代码].git[代码] 目录;
一个典型的工作流程如下图,绿色部分为工作区(Working Directory),对它进行任何修改(包括:新建文件、删除文件、文件重命名等)都和单纯的修改文件一样,不会涉及到版本控制。
只有当你把工作区的修改提交(commit)到仓库([代码].git[代码] 目录)中,Git 才会真正的进行版本控制。
[图片]
暂存区是一个包含文件索引的目录树([代码].git/index[代码] 文件),记录了文件的元数据(文件名、文件长度、修改时间等),而文件内容则存放在 [代码].git/objects[代码] 目录下。
用 Git 进行版本控制,实际上就是在工作区、暂存区、仓库三个地方进行文件信息的记录。
[图片]
Git 将提交(commit)、文件、目录统统视为对象。对象以 [代码]SHA1[代码] 值作为指纹,与其他对象相区分。Git 命令操作的最小单位是对象。 Git 会将文件的副本存放在 [代码].git[代码] 文件夹下,每个文件都根据文件内容进行操作。以下图为例:
[代码]98ca9[代码] 对象是一次提交,它记录了本次提交的元信息以及 [代码]92ec2[代码] 树对象;
[代码]92ec2[代码] 树对象记录了文件名和对象的印射关系;
本次提交修改的三个文件一一对应了一个对象;
[图片]
Git 项目的文件始终在四种状态之间迁移,如下图所示:
[图片]
如果是新文件,典型的操作流程如下:
创建一个新文件 [代码]foo.txt[代码],此时它处于未跟踪(Untracked)的状态,未被 Git 进行版本控制;
[图片]
通过 [代码]add[代码] 命令将它纳入 Git 管理,此时 [代码]foo.txt[代码] 变为已暂存(Staged)状态;
[图片]
提交此次操作,[代码]foo.txt[代码] 转变为未修改(Unmodified)状态;
[图片]
如果是修改文件,典型的操作流程如下:
修改 [代码]foo.txt[代码] 文件,它转变为已修改(Modified)状态;
[图片]
通过 [代码]add[代码] 命令将它的修改记录到暂存区,为已暂存(Staged)状态;
[图片]
提交此次操作,[代码]foo.txt[代码] 转变为未修改(Unmodified)状态;
[图片]
如果是删除文件,典型的操作流程如下:
删除 [代码]foo.txt[代码] 文件,它转变为已修改(Modified)状态;
[图片]
通过 [代码]add[代码] 命令将操作记录到暂存区,为已暂存(Staged)状态;
[图片]
提交此次操作,[代码]foo.txt[代码] 转变为未修改(Unmodified)状态(文件历史版本依然在 [代码].git[代码] 中被记录着);
[图片]
常用命令
下面列举一下常用的 Git 命令,方便速查。更详细的速查可以看 快速回忆你用过的 Git。
查看信息
[代码]# 列出处于未跟踪、已修改或已暂存状态的文件
git status
# 查看提交日志
git log
# 查看已暂存文件和最后一次提交相比的详细修改
git diff --staged
[代码]
状态变更
[代码]# 暂存或添加
git add .
# 提交
git commit -m "commit description"
[代码]
远程仓库(Remote Repository)
[代码]# 下载到本地
git clone http://git.code.oa.com/<USER>/<PROJECT>.git
# 更新代码
git pull
# 将本地仓库的 commit 提交到远程仓库
git push origin master
# 显示远程仓库信息,比如:url(不涉及网络通信)
git remote -v
[代码]