认识git

目录

  • 版本控制系统历史
  • git历史与特点
  • git内部设计
  • 总结与思考

1.何为版本控制

版本控制最主要的功能就是追踪文件的变更,版本控制系统(Version Control System)是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。版本控制系统不仅可以应用于软件源代码的文本文件,而且可以对任何类型的文件进行版本控制。

本地版本控制系统(LVCS)
最开始我们以文件副本的形式来保存一个文件的多个版本,通过复制整个工作目录,加上不同的命名进行区分,但这种方式很难对比每个版本之间的差异,也容易出错。为了解决这个问题,发明了多种本地版本控制系统,采用某种简单的数据库来记录文件的历次更新差异,其中的代表有RCS。

集中式版本控制系统系统(CVCS)
然而,人们发现本地版本控制系统无法进行多人协作,于是集中式版本控制系统系统诞生了,协作者通过客户端连接到集中管理的服务器,取出最新的文件或者提交更新,其中的代表有CSV,SVN。相较于老式的LVCS来说,每个人都可以在一定程度上看到项目中的其他人正在做些什么,管理员也可以轻松掌控每个开发者的权限,并且管理一个 CVCS 要远比在各个客户端上维护本地数据库来得轻松容易。但如果中央服务器出现故障,谁都无法提交更新,也就无法协同工作。如果中心数据库所在的磁盘发生损坏,又没有做恰当备份,就会丢失所有数据,包括项目的整个变更历史,只剩下人们在各自机器上保留的单独快照。

分布式版本控制系统(DVCS)

这类系统中,客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来,包括完整的历史记录。这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。这类系统也可以指定和若干不同的远端代码仓库进行交互,你就可以在同一个项目中,分别和不同工作小组的人相互协作,这些都是集中式系统无法实现的。其中代表有Git,Mercurial等。

分类 说明 特点 代表
本地版本控制系统
采用简单的数据库来记录文件的历次更新差异 方便对比版本差异,无法多人协作 RCS
集中式版本控制系统 有一个单一的集中管理服务器,保存所有文件的修订版本,协作者都通过客户端连到这台服务器,取出最新的文件或者提交更新 方便多人协作,权限管理,服务器压力大,存在数据丢失风险 SVN
分布式版本控制系统 客户端并不只提取最新版本的文件快照, 而是把代码仓库完整地镜像下来,包括完整的历史记录 每个协作者都拥有完成的仓库,可以和不同的远端进行协作 Git

认识git_第1张图片

2.git简史

从2002年开始,林纳斯·托瓦兹 (Linus Torvalds) 决定使用BitKeeper作为Linux内核主要的版本控制系统用以维护代码。2005年,由于一些原因,BitKeeper公司收回无偿使用BitKeeper的许可,林纳斯·托瓦兹决定自行开发版本控制系统替代BitKeeper,以十天的时间编写出git第一个版本[[1]](https://zh.wikipedia.org/wiki/Git)。林纳斯对SCM的要求是速度快,高效的分支管理与合并,适用大项目,完全分布式。自2005年git问世,随着不断完善,仍保留着其背后对象数据、工作区、分支管理等的优秀的设计理念和最初设定的目标,成为主流的分布式版本控件系统。

3.git特点[[2]](https://git-scm.com/about)

  • 分支与合并
  • 速度快性能高
  • 完全分布式
  • 数据一致性
  • 暂存区
  • 自由开源

4.git设计原理

git是一个内容寻址文件系统,数据以K-V的形式存储在.git目录。通过git init创建一个新的仓库,查看.git目录内容如下:

$ git init
$ ls -F1 .git
HEAD	      # 指向目前被检出的分支
config        # 项目的配置文件
description   # 仅供GitWeb程序使用
hooks/        # 客户端或服务端的钩子脚本
info/         # 全局性排除文件,用以放置那些不希望被记录在.gitignore文件中的忽略模式
objects/      # 储存所有数据内容
refs/         # 存储指向数据(分支、远程仓库和标签等)的提交对象的指针

index         # 保存暂存区信息
COMMIT_EDITMSG # 每次提交时,写的提交说明,只会保存最后一次写的
logs/         # 所有更新的引用记录
  1. 三种区
    • 工作区:是我们直接修改代码的地方
    • 暂存区:数据暂时存放的区域,用于在工作区和提交区之间进行数据交流
    • 提交区:存放已经提交的数据
      认识git_第2张图片

    可以通过git status 来查看工作区情况
    认识git_第3张图片

  2. 数据结构

    下面用一个简单git仓库来说明git的三种数据对象,目录内容如下:
    认识git_第4张图片
    我们可以用git cat-file -t 来查看一个对象对应的数据类型,git cat-file -p 来取出一个对象对应的内容,git cat-file -p master^{tree}查看master分支对象的tree对象,结果如下图:
    认识git_第5张图片
    可以看到有commit、blob、tree三种数据类型,具体含义是:

    • blob对象:保存文件内容。一个文件对应一条内容,以该内容加上特定头部信息一起的 SHA-1 校验和为文件命名。校验和的前两个字符用于命名子目录,余下的 38 个字符则用作文件名

    • tree对象:记录文件目录和blob数据索引。一个树对象包含了一条或多条树对象记录,每条记录含有一个指向数据对象或者子树对象的 SHA-1 指针,以及相应的模式、类型、文件名信息

    • commit对象:包含着指向前述 tree 对象的指针和所有提交信息。它先指定一个顶层树对象,代表当前项目快照; 然后是可能存在的父提交;之后是作者/提交者信息; 留空一行,最后是提交注释

    • tag对象:轻量标签和附注标签。轻量标签只是某个特定提交的引用,附注标签是存储在 Git 数据库中的一个完整对象, 它们是可以被校验的,其中包含打标签者的名字、电子邮件地址、日期时间, 此外还有一个标签信息。

    由此可见,这个简单的仓库整个数据模型是这样子的:
    认识git_第6张图片
    进一步,继续查看.git/objects目录下的具体数据,并与上图可以对应起来
    认识git_第7张图片
    认识git_第8张图片

  3. 命令

    git命令大致分为主流命令、辅助命令、与其他VCS交互命令、低级命令。可通过git help -a查看。命令学习网址:

    Git - Reference (git-scm.com)

    Git Reference

  4. 引用

    引用:用一个文件来保存SHA-1值,用简单的文件名指针来替代原始的 SHA-1 值,这种简单的名字的称为引用

    git引用分为HEAD引用、标签引用、远程引用,数据存储在.git/refs目录下,具体含义是:

    • HEAD引用:通常是一个符号引用,指向目前所在的分支。当你在检出一个标签、提交或远程分支,让你的仓库变成 “分离 HEAD”状态时,HEAD 文件可能会包含一个 git 对象的 SHA-1 值。数据保存在.git/refs/heads

    • 标签引用:保存标签对象信息,标签引用通常指向一个提交对象,像是一个永不移动的分支引用。数据保存在.git/refs/tags

    • 远程引用:记录远程服务器上各分支最后已知位置状态。切换分支与commit都不会将本地HEAD指向远程引用,push后HEAD与远程引用指向最新的提交记录。数据保存在.git/refs/remotes

    我们继续以上面的data仓库为例,当前data仓库只有一个master分支,可以通过git symbolic-ref HEAD来查看当前HEA指向的分支,整个git数据库看起来如下图
    认识git_第9张图片
    认识git_第10张图片
    在第一个提交"init"上创建一个标签v0.1,把master分支推送到服务器接着再创建分支test,新增加一个提交记录"second",至此,整个数据情况和分支情况如下:
    认识git_第11张图片

  5. 分支管理

    通过引用的学习,我们知道Git 分支的本质是一个指向某一系列提交之首的指针或引用,因此切换分支只需要移动HEAD指针,删除分支只需要删除分支对应HEAD引用数据,分支管理很快速高效。

  6. 维护与数据恢复
    • 维护:git默认是以松散格式对象存储的,如果有太多松散对象或者太多包文件,Git 会运行一个完整的 gc ,收集所有松散对象并将它们放置到包文件中, 将多个包文件合并为一个大的包文件,移除与任何提交都不相关的陈旧对象。gc的目的是减少磁盘占用体积。包文件存放在.git/objects/pack目录。可以通过git gc 来触发一次gc

      比如我添加了鲁迅-狂人日记.txt(大小约15kb),接着在这个文件末尾插入了读后感,再次将这个文件添加到数据库中,可以看到两次都将这个文件完整的存放到数据库中,占用了30KB,每次都完整的保存会很占用空间(即松散格式对象存储)。那如果 Git 只完整保存其中一个,再保存另一个对象与之前版本的差异内容,岂不更好?可以手动触发一次gc来将这些松散格式对象打包成一个包文件,来减少存储空间。

      可以用git cat-file -s 查看一个数据对象大小,git verify-pack -v 查看打包内容
      认识git_第12张图片

    • 恢复:每次HEAD引用发生变化时(如切换分支、commit、reset等),git都会保存在.git/logs/HEAD文件中,只要数据对象依旧存在数据库中,可以通过git reflog来进行恢复。

      比如误删一个本地分支后进行恢复
      认识git_第13张图片

  7. zlib压缩

    git数据压缩采用zlib Home Site

5.git编译

git源码:git/git: Git Source Code Mirror - This is a publish-only repository but pull requests can be turned into patches to the mailing list via GitGitGadget (https://gitgitgadget.github.io/). Please follow Documentation/SubmittingPatches procedure for any of your improvements.

环境:ubuntu-16.04.7

进入到git目录,make即可

可能出现的错误:

git-compat-util.h:353:25: fatal error: openssl/ssl.h: No such file or directory

sudo apt-get install openssl-dev

git-curl-compat.h:3:23: fatal error: curl/curl.h: No such file or directory
sudo apt-get install libcurl4-openssl-dev

http-push.c:22:19: fatal error: expat.h: No such file or directory
sudo apt-get install libexpat1-dev

查看生成的可执行文件:

$ find . -maxdepth 1 -name "git-*" | sort

6.参考文档

Git (github.com)

About - Git (git-scm.com)

git-first-commit (github.com)

你可能感兴趣的:(git,git)