Git 工作原理

程序员书单

共 2584字,需浏览 6分钟

 ·

2021-01-14 20:25

Git 是最先进的开源分布式版本控制系统,最初由 Linus 为解决 Linux 的代码管理而发明。版本控制系统(Version Control System, VCS)有很多实现,比如早期的 CVS,主要用于控制、协调文件的一致性。目前使用最多的主要是 SVN 和 Git。



SVN vs Git



SVN 是 subversion 的缩写,使用一个中央版本库来进行集中控制并记录文件变更历史,支持多个分支并行开发,采用了客服端/服务器模式,文件的各个版本、分支都储存在服务器上。SVN 采用的是 Copy-Modify-Merge(拷贝-修改-合并)模式对文件进行管理。


在 Copy-Modify-Merge 模式下,当用户想修改文件时,先将服务器文件 update 到本地,然后在本地对副本进行修改,修改完成后,再将副本 commit 到服务器。如果 commit 前其他用户修改了文件,则文件版本号发生冲突,需要先 update 到本地进行合并,才能继续 commit。


与 SVN 不同,Git 是分布式版本管理系统。从 Git 服务器 clone 文件到本地,成为本地仓库,包含了全部文件和变更记录,与之相对的服务器仓库被称为远程仓库。当用户想修改文件时,直接对本地副本进行修改,修改完成后把改动 commit 到本地仓库,需要同步时再 push 改动到远程仓库。由于使用本地仓库,Git 减少了很多网络开销,使得性能比 SVN 有极大的提升,即使在断网情况下也能继续工作。


大多数 VCS 应用是基于增量的版本控制,即存储了文件信息和对每个文件所做的更改。而 Git 是基于快照的版本控制,在每个版本都记下文件的快照,并存储对快照的引用。为了提高效率,如果文件没有更改,Git 不会再次存储该文件,而只是指向它已经存储的先前相同文件的链接。因此,本质上,Git 是一套内容寻址(content-addressable)文件系统。



Git 仓库



Git 中的文件和操作都以 Git 对象来保存。Git对象分为 BLOB、tree 和 commit 三种类型,BLOB对象可以存储几乎所有的文件类型,tree对象是用来组织BLOB对象的一种数据类型,commit对象表示每一次的提交操作commit对象存储了对tree对象的引用,tree对象存储了对BLOB对象的引用。进行版本控制所需要的所有数据都在 .git 文件夹中,如图所示。



.git 文件夹核心文件包括:config文件、objects文件夹、HEAD文件、index文件以及refs文件夹。

  • config文件:主要记录针对该项目的一些配置信息,例如是否以bare方式初始化、remote的信息等;

  • objects文件夹:主要包含git对象,保存在以其sha-1值的前两位为子文件夹、后38位为文件名的文件中。为了节省磁盘空间,会定期对Git对象进行压缩和打包,并存储在pack文件夹中,相关的查找信息存储在info文件夹中;

  • refs文件夹:存储指向分支的 commit 对象的指针。其中heads文件夹存储本地每一个分支最近一次commit的sha-1值,每个分支一个文件;remotes文件夹记录最后一次推送到远程仓库的每个分支的值;

  • HEAD文件:存储当前分支在 refs 中的信息,如ref: refs/heads/master;

  • index文件:存储暂存区域(staging area)的信息,内容包括文件的时间戳、文件名、sha-1值等;



Git 文件状态



Git 的文件有已提交(committed)、已修改(modified) 和已暂存(staged)三种状态。

  • 已修改表示修改了文件,但还没保存到仓库中;

  • 已暂存表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中;

  • 已提交表示数据已经安全地保存在本地仓库中;


与之对应,Git 中还有工作区(Working Directory)和暂存区(Staging Area)。工作区存放从仓库 checkout 出来的文件,用户可以进行修改。下次将要 commit 的文件信息存储在暂存区。commit 操作实际上是从暂存区 commit 到本地仓库中。



Git 命令



在 Git 中,包括 porcelain 命令(高层命令)和 plumbing 命令(底层命令)两种类型。按照最初的设计,Git 是一个工具集,底层命令用于以 UNIX 风格使用或由脚本调用。高层命令用于方便用户进行操作。我们平时使用的都是高层命令,内部实际上封装了底层命令的调用。


Git 的常用命令如图所示。首次从远程仓库创建本地仓库使用 clone 命令;使用 checkout 命令从本地仓库切换分支到工作区;增加文件后,使用 add 命令提交变更到暂存区;修改完成后,使用 commit 命令提交变更到本地仓库;需要同步时,使用 push 命令推送变更到远程仓库;远程仓库变化后,使用 pull 命令拉取变更到工作区。以上这些命令都是高层命令。



当我们执行 git add 高层命令时,内部实际上封装了 git hash-object 和 git update-index 两个底层命令。其中 git hash-object 将需要暂存的文件进行 key-value 转化生成 git 对象,存储到 objects 文件夹中,获取了这些文件的 key,git update-index 命令把这些文件存储到暂存区。


当我们执行 git commit 高层命令时,内部实际上封装了 git commit-tree key –p key2 底层命令。该命令创建 commit 对象,并挂载到前继对象之后。


— 【 THE END 】—
本公众号全部博文已整理成一个目录,请在公众号里回复「m」获取!


3T技术资源大放送!包括但不限于:Java、C/C++,Linux,Python,大数据,人工智能等等。在公众号内回复「1024」,即可免费获取!!




浏览 8
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报