git是一个分布式版本控制软件,最初由林纳斯创造,于2005年以GPL许可协议发布。最初的目的是为了更好地管理Linux内核开发而设计。
git最初的开发动力来自于BitKeeper和Monotone。git最初只是作为一个可以被其它前端包装的后端而开发的,但后来git内核已经成熟到可以独立地用作版本控制。
The name “git” was given by Linus Torvalds when he wrote the very first version. He described the tool as “the stupid content tracker” and the name as (depending on your way):
林纳斯在编写第一个版本时就使用了“git”这个名称。 他将工具描述为“愚蠢的内容跟踪器”,并将其描述为(取决于您的方式):
git是用C语言开发的,以追求最高的性能。
git和其它版本控制系统(如CVS)有很大的差别,git本身关系文件的整体性是否有改变,但多数的版本控制系统如CVS或Subversion系统则在乎文件内容的差异。git拒绝保持每个文件的版本修订关系。因此查看一个文件的历史需要遍历各个history快照;git隐式处理文件更名,即同名文件默认为其前身,如果没有同名文件则在前一个版本中搜索具有类似内容的文件。
git更像一个文件系统,直接在本地上获取资料,不必连线到主机端获取资料。每个开发者都可有全部开发历史的本地副本,changes从这种本地repository复制给其他开发者。这些changes作为新增的开发分支被导入,可以与本地开发分支合并。
分支是非常轻量级的,一个分支仅是对一个commit的引用。
git存储每个新创建的object作为一个单独文件。为了压缩空间占用,packs操作把很多文件使用差分压缩入一个文件中(packfile),并创建一个对应的索引文件,指明object在packfile中的偏移值。新创建的对象仍然作为单独文件存在。repacks操作非常耗时,git会在空闲时间自动做此操作。也可用命令git gc
来直接启动repack。packfile与索引文件都用SHA-1作为校验和并作为文件名。git fsck
命令做校验和的完整性验证。
byte ojects = tree | blob | commit
def store (o):
id = sha(o)
object[id] = o
def load (id):
return object[id]
git有两种数据结构:可变的索引(index、stage或cache)用于缓冲工作目录信息与下一次提交的版本信息;不变的、仅追加的对象数据库。
对象数据库包括4类对象(用其内容的SHA-1哈希值标识:哈希值的前两个字符作为存放的目录名字,其余哈希字符昨晚这个对象的文件名):
使用zlib压缩算法对一个文件的内容压缩后的结果。blobs没有保存文件名、时间戳或其他元数据。git将其存储在位于隐藏的.get/objects文件夹中。文件的名称为使用SHA-1哈希函数对原文件内容生成的哈希值。这些对象文件称为blob,每次将新文件添加到存储库时会创建blob对象。
byte blob = array<byte>
tree对象对应于文件目录。包含文件名列表以及文件的类型比特、到blob(对应于文件)或tree对象的引用。tree对象是源树的快照,用默克尔树实现。
byte tree = map<byte, blob | tree>
commit对象链接tree对象在一起而成为history,包含顶层源目录的tree对象名字、时间戳、log信息、0个或多个父commit对象的名字。用于保存特定版本的树形文件夹结构以及提交作者、电子邮件地址、日期和描述性提交消息。
byte commit = struct {
parents array<commit>;
String author;
String message;
tree snapshot;
}
tag对象是一个容器,包含了到另一个对象的应用,也可以增加关于另外对象的元数据。通常它保存需要追溯的特定版本数据的commit对象的数字签名。
git数据库中不变引用的对象将会被垃圾回收清楚。git命令可以创建、移动、删除引用。git show -ref
列出所有引用。
每个head可以指任意一个这样的指针。可以包含任意数量的heads。而“HEAD”,仅仅指的是当前有效的head。默认情况下,在每个仓库下都有一个head,叫做master。
引用远程repository中的一个对象
引用一个还没有committed的对象
一个bare repository中的配置,用户权限;refs/meta/config命名空间等
某些操作(例如,将提交推送到远程存储库,存储太多对象或手动运行git的垃圾收集命令)可能会导致git将对象重新打包为打包文件,在打包过程中,采用反向差异并进行压缩以消除多余的内容并减小尺寸。该过程将生成包含对象内容的.pack文件,每个文件都有一个对应的.idx索引文件,其中包含对打包对象及其在打包文件中位置的引用。当将分支推送到远程存储库或从远程存储库拉出分支时,这些打包文件将通过网络传输。提取或获取分支时,将打包文件解压缩以在对象存储库中创建松散对象。