出处大神git_她来了,她来了,她带着「Git 原理」走来了

一如既往的开场白

酱酱酱酱!Hello 大家好 我是你们的梨花酱 好久不见 我带着干货又回来了!因为 Git 是我们常用的代码协作工具 正好近期学习了 Git 原理 特来和大家分享~ 下面多图预警 ❗️❗️❗️

前言

首先 我们熟悉一下 git 的核心概念

拥有 Working Directory、Staging Area 和 Local Repository 三个分区

Local Repository 以 object 形式存储数据,object 分为三种类型

commit

tree

blob

commit 可视化以后是一个有向无环图(DAG-Directed Acyclic Graph),每个箭头都往前指

1 初始化

以上命令分为三步:

创建一个新的文件夹 git-demo

进入 git-demo 目录下

初始化项目,以进行版本管理

git init 命令的作用就是在当前目录下创建一个 .git 子文件夹,用来保存版本信息

2 查看 .git

温馨提示:先执行 brew install tree 下载 tree command 方便查看文件夹的树形结构

如上图所示,.git 目录下还有一些子目录,下面解释几个重点目录的含义👇

hooks---钩子,执行各种操作的时候会先执行这个钩子,可以做事先的校验或事后的处理,比如提交前检查提交信息等。这个目录下可以存放 git 脚本,一般用于规范 git 操作。

info---存放配置,比如 .gitignore

objects---数据存储,存放所有 git objects。其包含三种对象类型:blob、tree、commit

refs---存放远端以及各个分支的信息、版本信息、本地所有分支的 HEAD 指针

3 数据存储 --- objects 目录

3.1 创建并提交一个文件

创建并提交一个文件到本地仓库

3.2 查看 objects 目录

如上图红框所示,此目录下增加了三个子目录,分别是9b、e6 和 fc,每个子目录下都存放着一个名字巨长(38位字母)的文件

git 以键值对存储内容,key 值使用 SHA1 算法生成40位哈希值,前两位作为目录名,后38位作为该目录下的文件名,value 以二进制形式存储在该文件里

3.3 查看 object 类型

通过观察,我们发现创建并提交一个文件到本地仓库,会在 objects 目录下新生成三个 object,分别是 commit、blob 和 tree 类型

git cat-file [-t], -t 可以查看 object 的类型

3.4 查看 object 内容

9b1445 是 commit 类型的 object,一般存储着 tree、parent、author 和 committer等信息(注意,因为是第一个提交,所以没有 parent 信息

e69de2 是 blob 类型的 object,一般存储着文件的内容。(注意,因为 hello.txt 中没有写入内容,所以此处没有打印为空

fcb545 是 tree 类型的 object,一般存储着 blob object 的权限、类型、SHA1哈希值以及文件名信息

git cat-file [-p], -p 可以查看 object 的内容

3.5 可视化 object 关系

为了方便表述,以下的 commit、tree、blob 分别指 commit object、tree object、blob object

上图表示之前一系列操作后得到的可视图,由此可见 commit 存储着 tree,tree 存储着 blob。那么,一个 commit 能存储几个 tree 呢?tree 可以存储 tree 吗?别急,我们下面揭晓

一个 commit 存储一个 tree ,parent 存储上一次提交的 commit ( 图中用向前指的 parent 箭头表示

tree 可以存储 N 个 blob, M 个 tree ( N >= 1,M >= 0

Q:为什么需要 tree,commit 不能直接存储 blob 信息吗?

A:因为需要利用 tree 来存储 blob 的权限和命名等。在文件重命名的场景中,tree 的作用就体现出来了。假如没有 tree ,将文件名保存在 blob 中,那么 git 只能复制原始内容加上新命名形成一个新的 blob。假如有 tree,这个时候就只需要更新 tree 中对应的文件名,原来的 blob 就得以复用,节约了空间。

review:git 是以 object (对象)的形式存储数据的,位于 .git 目录下的 objects 子目录中

接下来我们对比一下 git 常用命令之间的区别

推荐:👉 Learn Git Branching 👈 这个网站可以可视化练习 git 的使用(是那种有趣的游戏闯关形式哦

分支合并 ---- git merge 和 git rebase

注:以下 gif 动图中,分为 topic 分支和 master 分支,在 topic 分支上执行 git merge/rebase master

git merge:优势是会保留详细的合并信息,但是会产生一个新的 merge commit 节点,

fast-forward: 发生在 master 分支的状态没有被更改过

non fast-forward:发生在 master 分支的历史记录自 topic 分支分叉出去后有新的更新

git rebase:优势是可以创造更线性的提交历史,不过 commit 的提交顺序会被打乱

撤销更改 --- git revert 和 git reset

git revert 用于“反做”某一个 commit,相当于撤销其操作。用场景是想撤销之前的某一个 commit ,但是又想保留该 commit 之后的所有 commit 。

举个🌰,在 pushed 分支上,我们有 c2、c6、c7三个提交,现在,我们想撤销 c2,但是又想保留 c6 和 c7。这个时候就可以使用 git revert c2,生成新的 commit c2' ,c2' 中保留了 c6 和 c7 的代码提交但是撤销了 c2 中的代码修改。这种形式的撤销支持将更改推送到远程仓库与别人分享。

git reset 改写历史,向上移动分支,原来指向的提交记录就跟从来没有提交过一样。

举个🌰,在 local 分支上,我们有 c3、c4、c5 三个提交,现在,我们想重置提交到 c3,c4 和 c5 都不要了。这个时候就可以使用 git reset c3 ,c3 之后的提交都不见了!(注意,reset 默认使用 mixed 模式 ,即 c4 和 c5 所做的变更还在,只不过保存在 working directory ,还未加入 stage area。 详情见 git reset 的三种模式

拉取代码 --- git fetch 和 git pull

从阮大神博客扒来的一张图,大神已经画的很详细了,我就不再画蛇添足了

git fecth 相当于将远端代码拉取到本地仓库,更新本地仓库的代码

git pull 相当于直接将远端代码拉取到工作目录,默认等价于执行了 fetch + merge

git best practice :和远端仓储同步时,尽量使用 git pull --rebase 而不是 git pull 。或者使用 git fetch,再根据个人需要,使用 rebase 或 merge 同步修改

结束语

看资料 + 编辑 + 画图,这篇文章差不多花了两天写完,还是收货满满~ 毕竟是第一次学习 git 原理,文中有些表述可能有误,欢迎大家积极指正。最后,希望看完这篇文章的你能有所收获哦!

参考资料

银平老师的《git 原理》(链接就不放了,放了也访问不了🤣

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值