git原理
# Git与SVN的区别
Git 和 SVN(Subversion)是两种常见的版本控制系统,它们在工作流程、数据模型和分布式特性等方面有一些显著的区别。
分布式 vs 集中式:
Git 是一种分布式版本控制系统,每个克隆(clone)都是一个完整的仓库,包含完整的历史记录和版本信息。这意味着开发者可以在本地进行提交、分支和合并等操作,而不需要与中央服务器保持连接。 SVN 是一种集中式版本控制系统,开发者需要与中央服务器进行交互。历史记录和版本信息都保存在中央服务器上,开发者需要从中央服务器获取文件并提交更改。 数据模型:
Git 使用快照(snapshots)来存储数据,它记录文件在每个提交时的状态,并且在本地存储完整的历史记录。 SVN 使用增量变化(delta-based changes)来存储数据,它记录文件的每次变化,并且需要连接到中央服务器来获取完整的历史记录。 分支和合并:
在 Git 中,分支和合并操作非常轻量和快速,因为每个克隆都包含完整的版本历史。 在 SVN 中,分支和合并操作相对复杂,因为它们需要与中央服务器进行交互,而且操作相对慢一些。 性能:
由于 Git 的分布式特性,它通常在性能上比 SVN 更快,尤其是在处理大型仓库和执行分支操作时。 历史记录:
Git 的历史记录是不可更改的,每个提交都有一个唯一的 SHA-1 标识符。 SVN 的历史记录可以被修改,因为它使用版本号来标识提交。 总的来说,Git 更适合于分布式团队和开源项目,因为它提供了更强大的分支和合并功能,以及更快的性能。而 SVN 更适合于传统的集中式开发模型。
# 使用Hash算法
Git底层使用了SH1加密算法,用途是:
一个哈希算法,加密结果长度固定
输入数据确定,输出结果保证不变
输入数据有变化,输出结果一定变化
# git结构
工作区,暂存区,本地代码库 ,远程仓库
# git数据类型
在 Git 中,有四种主要的数据类型,它们分别是:blob、tree、commit 和 tag。
- Blob(文件内容):Blob 对象存储了文件的数据,每个文件对应一个 Blob 对象。它们代表了文件的内容,但不包含文件名、权限等元数据。
- Tree(目录结构):Tree 对象存储了目录结构和文件名与 Blob 对象之间的映射关系。每个 Tree 对象代表一个目录,它包含了指向文件或其他目录的指针。
- Commit(提交):Commit 对象包含了提交的元数据,比如提交者、提交时间、提交消息等信息,以及指向一个或多个 Tree 对象(代表工作目录快照)和指向父提交的指针(如果是合并提交的话)。
- Tag(标签):Tag 对象用于给某个特定的提交打上标签,通常用于标记软件版本发布。Tag 对象包含了标签的信息,比如标签名、标签创建者、标签消息,以及指向被标记的提交或其他对象的指针。
这些数据类型构成了 Git 对象数据库的基础,它们组合在一起构成了版本控制系统的核心。通过这些对象,Git 能够跟踪文件的变化、记录项目的历史,以及支持分支、合并等操作。
# .git目录下的文件
.git 文件夹是 Git 仓库的核心,包含了整个仓库的版本控制信息和元数据。下面是一些主要文件和文件夹的作用:
- config: 这个文件包含了项目特定的配置选项,比如用户信息、远程仓库信息等。
- description: 一个简短的描述文件,一般情况下不太常用。
- hooks: 这个文件夹包含了客户端或服务器端的钩子脚本,可以用来在特定的 Git 事件发生时执行自定义的脚本。
- info: 这个文件夹包含了一些全局的 Git 仓库配置。
- objects: 这个文件夹是 Git 中最重要的部分之一,它包含了所有的数据内容。所有的提交、文件内容、树对象等都储存在这里。
- refs: 这个文件夹包含了指向数据(commits, tags, branches等)的指针。分支引用、标签引用等都储存在这里。
- HEAD: 这个文件指示了当前所在的分支。
- index: 这是暂存区(stage)的索引文件,它存储了下一次提交时要包含的文件列表信息。
这些文件和文件夹组成了 Git 仓库的核心结构,它们存储了版本控制所需的所有信息,包括历史提交、分支、标签、配置等。
# 常用命令
git cat-file-t SHA
查看当前文件的类型
git cat-file-p SHA
查看当前文件的内容
# Git add
新建一个文件a.txt
内容:aaaa
git add a.txt
这时候查看 ./git/objects 会发现多了这一行
git cat-file -t 5d30 显示git的类型
类型:blob
git cat-file -p 5d30
显示内容:aaaa
# Git Commit
git commit 生成了6b6c、b29c :
我们可以得知每次commit之后objects底下会生成两个文件一个Tree一个Commit
# 分支
# 新建分支
git branch dev
这时候refs/heads目录会多一个dev分支出来
# 切换分支
git switch dev
我们这时候可以发现Head指针已经指向refs,refs指向commit节点。如果在dev分支上commit一个文件c.txt,那么dev的refs将指向c.txt的commit节点,而master的refs将指向原来b.txt的commit节点。
# 链路关系
Head当前指针指向refs分支指针,refs分支指针指向commit,commit找到Tree和parent commit(即上一次提交的),Tree找到Tree和Object。借用大佬的图一用。
# 补充
# 相同内容复用
我们这里新建一个b.txt ,内容仍然是aaaa,我们发现objects中并没有出现新的内容。原因是git会对每次add加入到暂存区的数据进行一次RSA摘要算法的加密,加密后的内容会作为文件的名称,所以如果内容一致的话不会生成新的文件,以达到节省空间复用的功能。