GIT | 浅析原理篇

news2024/11/28 7:50:03

在这里插入图片描述

此篇文章主要是讲讲 一些 git 操作发生的时候 , .git 文件如何变化,git 背后发生了什么。磨刀不误砍柴工嘛!算是一篇视频观后笔记(文末取视频地址)

基础概念

Git 是一个代码版本管控的工具,是一个内容寻址文件系统,即简单的键值对数据库。

Git 的一些基础基础知识

  • 版本库:git在本地开辟的一个存储空间,一般在 .git 文件里。

  • 工作区(workspace): 就是编辑器里面的代码,平常开发直接操作的就是工作区。

  • 索引区/暂存区(index/stage):暂时存放文件的地方,git add 后也就将工作区代码放到了暂存区(缓冲区)。

  • 本地仓库(Repository)git commit 后就是将暂存区的代码放到本地仓库。

  • 远程仓库(Remote):线上代码存放的地方,如 github/gitee。

他们之间的关系是这样子的:

本文伊始,需要知晓一些git 相关 基础命令

如果对基础linux的命令不熟悉请查看 这里

git cat-file -t <sha1-hash> # 查看文件类型 commit 取前四位即可
git cat-file -p <sha1-hash> # 查看文件内容
cat .git/refs/heads/master # 查看master指向的文件
git ls-files # 查看索引区文件, 也就是index的内容
git ls-files -s #查看 索引/暂存 区的文件内容

初始化

本文环境 前面是win10 => cmder,后面是mac => iterm2+zsh

先在 porn…呸,github 先创建一个清爽的远程仓库
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cU6Bh2tL-1685028681289)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2022-08-10-23-09-41-image.png?msec=1684158868612)]41-image.png" title="" alt="" width="50">

推荐三种方式 往空仓库“填充”代码。

咱们先别顺着 Git 这小子,先把它克隆下来, 看看 .git 文件

D:\assets
λ git clone https://github.com/OFreshman/gitTest.git
Cloning into 'gitTest'...
warning: You appear to have cloned an empty repository.
λ rm -rf .git/*.sample # 为了看起来干净,删除了sample文件 
D:\assets\gitTest (main -> origin)
λ tree .git /f # 以树形结构递归查看所有文件夹即文件夹,
D:\ASSETS\GITTEST\.GIT
│  config # 仓库本地配置文件
│  description # 描述 用于GitWeb
│  HEAD # 工作区目录指向的分支
├─hooks # 存放一些shell脚本,可以设置特定的git命令后触发相应的脚本
├─info # 附加信息 
│      exclude # git文件排除规则。类似 .gitnore
├─objects # 所有文件存储对象
│  ├─info # 对象存储的附加信息,存储着打包后的文件名
│  └─pack # git 压缩对象
└─refs # 夹存储着分支和标签的引用
    ├─heads # 分支对应对象
    └─tags # 标签

各文件详情补充

.git/info

info/exclude,初始化时只有这个文件,用于排除提交规则,与 .gitignore 功能类似。区别在于**.gitignore 这个文件本身会提交到版本库中去,用来保存的是公共需要排除的文件**;而info/exclude 设置的则是你自己本地需要排除的文件,他不会影响到其他人,也不会提交到版本库中去。

info/refs,如果新建了分支后,会有info/refs文件, 用于跟踪各分支的信息。对于刚克隆下来的仓库 可以通过命令去生成 info/refs 文件
在这里插入图片描述

FETCH_HEAD

指向上一次的 fetch 的commit

➜  gitTest git:(main) cat .git/FETCH_HEAD
> d4166b7319f1c85b7a86718f6a0387e0e9b1fa2c		branch 'main' of github.com:OFreshman/gitTest

如果需要合并可以这样

git merge FETCH_HEAD

因为刚刚 fetch 的是main分支, 上面命令相当于执行 git merge remote/main

.git/index

二进制暂存区(stage)

COMMIT-EDITMSG

COMMIT-EDITMSG 是一个临时文件,存储最后一次提交的message。有提交才会有这个文件夹。

logs

存储提交、操作日志,git reflog 依赖此文件夹。
在这里插入图片描述

refs

refs/heads/ 文件夹内的 ref 一般通过 git branch 生成。git show-ref --heads 可以查看;
refs/tags/ 文件夹内的 ref 一般通过 git tag 生成。git show-ref --tags 可以查看。
refs/remotes/ 文件一般是存放远程的分支。git fetch 就会更新里面的内容


上面大概说明了.git 各子文件的作用。因为这是个空仓库(warning: You appear to have cloned an empty repository),所以没有分支,即使看起来像有(main -> origin), 此时已经初始化了一个git仓库了(相当于执行了 git init),再次执行 git init 会提示 重复初始化已经存在的仓库了。

λ git init
> Reinitialized existing Git repository in D:/assets/gitTest/.git/ 

注意:线上的默认分支是main,本地是master。

另外此时本地 git branch 无法查看分支,需要 git add && git commit 后才能查看。如果是 git init 初始化 会有 分支,且 存在 .git/branchs 文件夹。

refs/heads, refs/tags 目前都为空(因为克隆的就是空仓库), HEAD 指向工作区的分支

λ cat .git/HEAD
ref: refs/heads/main

git status 查看到未提交的代码时为啥不一样,其实就是对比了暂存区和工作区的文件内容。index(索引区) 始终保存着最新的待提交的文件

工作区到暂存区(add)

新建一个文件,并写入内容 hello txt

echo 'hello txt'>hello.txt

此时 该文件在工作区(workspace),未被追踪(untracked),将其添加至 索引区(index)

git add hello.txt

可以看到增加了两个文件 index, objects/32,objects 里面是一个个hash对象,hash值前两位为一级文件夹名,剩余值为相应二级文件夹名,前两位相同的会被归到同一个文件夹,而index是存放暂存区文件的文件夹。

这里就产生了一个疑问:为什么Git要这么设计目录结构,而不直接用Git对象的40位hash作为文件名?原因是有两点:

  1. 有些文件系统对目录下的文件数量有限制。例如,FAT32限制单目录下的最大文件数量是65535个,如果使用U盘拷贝Git文件就可能出现问题。
  2. 有些文件系统访问文件是一个线性查找的过程,目录下的文件越多,访问越慢。

objects 一级子目录数量就变成了 <= (10+26)^2。大大减少了数量,相应的也提升了检索速度

objects 里面的hash对象类型有三种: blobcommittree

git 提供了相应的命令去查看类型, 查看的时候只需要带上文件夹名(32)+ hash子文件前四位(4b9a)。四位也可以只要是唯一。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rQktlLkM-1685028681289)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-09-23-21-03-image.png?msec=1684158868494)]

可以查看该文件内容

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OM8IvIw4-1685028681289)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-09-23-25-24-image.png?msec=1684158868493)]

也可以查看文件长度

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O0X47B72-1685028681289)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-10-00-13-46-image.png?msec=1684158868495)]

当重复添加相同内容的不同文件时,objects 不会改变,因为 32-4b9a6927b8f2217f751be4f8379e0d093856ab 存的是文件内容且Git有重复检测。

32-4b9a6927b8f2217f751be4f8379e0d093856ab 不止是文件内容的hash,而是包含 类型 + 长度 + \0(linux字符串结束符) + 文件内容 的 sha1 hash 值,可验证一下。(shasum 是mac 安装的命令包,默认输出sha1 hash)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hyUJlU3G-1685028681289)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-10-00-04-16-image.png?msec=1684158868517)]
还有个命令可以佐证 得到的hash

how-is-the-git-hash-calculated

(printf "commit %s\0" $(git cat-file commit 324b9a | wc -c); git cat-file commit 324b9a)|shasum
> 324b9a6927b8f2217f751be4f8379e0d093856ab

shasum 是获取文件的各种hash值 的函数,默认SHA1。参考mac下如何获取文件MD5校验值和SHA1校验值 - 掘金

此时索引区文件(-s 是 --stage 的缩写)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O52fyC4A-1685028681289)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-10-20-49-38-image.png?msec=1684158868513)]

-s 得到的事索引区 文件的 权限 + blob对象 + 0 + 文件名

为了对比看效果,此时 增加新文件hello.txt并去修改文件 hello.txt , git status查看状态的时候 之前是 未跟踪(untracked), 现在是修改(modify)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-40I0ffRc-1685028681290)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-10-21-07-48-image.png?msec=1684158868639)]

将新文件提交,那么 .git/objects 中的 blob 对象就会改变

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j0JCRMHb-1685028681290)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-10-21-11-33-image.png?msec=1684158868529)]

索引区到本地仓库(commit)

接下来对上面的文件进行commit
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x20P3EEC-1685028681290)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-10-21-23-41-image.png?msec=1684158868530)]

附带的信息:这是根提交(root-commit ,第一次),提交对象的hash值,文件改变数量和行数,文件权限(之前提到过),文件名。

commit 之后 可使用 git rev-parse HEAD:<file> 查看当前版本对象的 sha1值

git rev-parse HEAD:hello.txt
5b10c6a97b7b4132c2ad4d6d80ceddd2b8a4fdba

此次提交的对象类型为 commit
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YGy1N4xG-1685028681290)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-10-21-32-03-image.png?msec=1684158868580)]

这个 commit 对象的内容含有 tree 类型对象,以及仓库作者和提交者信息,提交信息。

.git 文件 也有一些变化
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GveYfJNT-1685028681290)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-10-21-38-50-image.png?msec=1684158868655)]

logs 是 git 历史相关的文件。objects 里增加了前面提的的两个对象(commit,tree)以及heads 里面增加了main。也就在此时本地也有了分支 main (git branch 查看)。

HEAD 是一个指向当前工作分支的指针,目前指向main, refs/heads/main 是啥?就是 main 分支指向的 最新提交对象。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZYiKGGuY-1685028681290)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-10-21-59-31-image.png?msec=1684158868512)]

tree 对象含有两个blob 文件,仔细观察可以发现就是之前 add 时 添加的两个blob对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CEfEvQZp-1685028681290)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-10-21-46-34-image.png?msec=1684158868529)]

现在 objects 的里对象的关系如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kzrKIdz1-1685028681290)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-10-23-42-54-image.png?msec=1684158868514)]

为了探究其中的奥秘,再次更改 hello.txt(vim hello.txt, git add, git commit),具体细节就不展示了,给一个objects对比图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nmM4VbCJ-1685028681290)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-10-23-17-26-image.png?msec=1684158868655)]

新增了 四个对象, git cat-file -p 一一查看新增的四个内容

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t6geeXsx-1685028681290)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-10-23-24-32-image.png?msec=1684158868627)]

对于这次commit 对象 多了一个 父级对象(parent)。 简单梳理一下就是

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FQLAvLEE-1685028681290)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-11-12-45-57-image.png?msec=1684158868563)]

或许能从前面两张图总结出一些规律

  • 每次 add 都会生成一个blob 对象

  • 每次 commit 都会生成 commit 和 tree 对象以及若干个blob对象 (blob数量 = 新增/修改的文件数)

  • tree 对象 始终包含最新的所有文件

接着验证一下,更改 test.txthello.txt, 增加文件 demo.txt

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-njdaANQO-1685028681291)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-11-00-16-05-image.png?msec=1684158868596)]

git add . 时会增加三个 对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F61JFFRb-1685028681291)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-11-00-10-30-image.png?msec=1684158868687)]

git commit 之后增加了两个对象, 一个是commit类型(), 一个是commit类型包含的tree类型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GLWlH6r9-1685028681291)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-11-08-36-44-image.png?msec=1684158868661)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7rkRWOaC-1685028681291)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-11-08-43-34-image.png?msec=1684158868607)]

总共增加了五个对象,它们的关系如下图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TORAD9KZ-1685028681291)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-11-21-02-03-image.png?msec=1684158868591)]

至此,前面的推断被证实,且在用户添加/提交文件的时候,objects 的内部变化也能很好的体现。objects 里保存在暂存区和本地仓库的文件对象。

main 分支指向最新的提交,暂存区包含最新的所有文件。

➜  gitTest git:(main) cat .git/refs/heads/main
0d8d0eb0446d7bf92a32512089fa927314675ac9
➜  gitTest git:(main) git ls-files -s
100644 598bc0d8552fb08de29c7fcd317cacf09c0f237b 0    demo.txt
100644 acdf79a141b2f07dca7b715d606b23307d669f94 0    hello.txt
100644 ba0ba9399c8a2336b1aab6a61fa499b012561588 0    test.txt

此时提交历史就是上图中 三个 commit 的提交

git log --oneline
* 0d8d0eb (HEAD -> main) 2nd commit
* de07e86 change hello.txt
* 779c005 added two files

仓库含有文件

这是常见的情况,但是前面为了简化变化,仅仅使用了文件。

使用文件夹有一些不一样,前面说过 每次提交都会产生一个 committree、若干个blob(取决于文件数量) 对象,当有文件夹时,committree(root) 依旧会存在, 仓库的一级 文件/文件夹 会分别作 blob/tree(1-level) 被包含在 tree(root) 下面,如果一级文件夹里面包含文件夹,那么其子文件依旧会作为 tree(2-level), 包含在 其 父级 tree(1-level) 下, 该子文件夹的子文件 会被作为blob包含在子 tree(1-level)

比如仓库有 一个文件夹 FF里有个文件 f.txt,两个文件 a.txt, b.txt
add 会产生 三个 blob(f.txt, a.txt, b.txt)
commit 会产生 两个tree(本身一个, F文件夹一个), 一个commit

在这里插入图片描述

commit > tree > [tree(F) > blob(f.txt) , blob(a.txt), blob(b.txt)]

不一样的就是 文件F 也作为一个tree, 这个 tree 含有一个 blob, 即该文件夹下的子文件。

前面文字说的可能有点绕,补一张图(某仓库下添加了若干个文件夹,文件,在第一次提交之后 .git/objects 的情况)

现在再举个🌰,我在仓库建立一些文件
在这里插入图片描述
第一次 add 后,有五个 blob 对象,就是那五个文件
在这里插入图片描述
commit 后 会有 1个 commit、6个tree(1+5),总共 12 个对象
在这里插入图片描述

和Objects对象图

分支

分支大家都不陌生, 在Git 里,分支就是一个特殊(具有名字)的指针,指向某个 commit。

另外 git 里面还有个 HEAD 文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hD9ekjuZ-1685028681291)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-11-21-23-17-image.png?msec=1684158868476)]

这也是个指针,在活跃的分支上指向最新的提交。简单理解就是 切到哪个分支,它就指向哪个分支。可以相关命令查看一下

➜  gitTest git:(main) cat .git/HEAD
ref: refs/heads/main
➜  gitTest git:(main) cat .git/refs/heads/main
0d8d0eb0446d7bf92a32512089fa927314675ac9

有这样的关系: HEAD => main => lastest commit

接着新建一个 dev 分支,此时 .git/refs, .git/logs 都改变了

tree -I <ignore-file> <file> 树形展开file文件并忽略 ignore-file

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IDGbxYh5-1685028681291)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-11-21-46-45-image.png?msec=1684158868611)]

前面说过 logs 表示git 的提交历史,此时查看提交历史

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r9YS86lW-1685028681291)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-11-21-51-21-image.png?msec=1684158868475)]

括号里面表示分支 main 和 dev 都指向 0d8d0ed 的 commit 对象,且 HEAD 指向 main(当前在main分支上);

简单画了个图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nMxaaEbY-1685028681291)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-11-22-07-02-image.png?msec=1684158868497)]

master 上产生一个 commitdev 也产生一个(停在此分支),就有如下关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AOKr67Oi-1685028681291)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-11-22-21-07-image.png?msec=1684158868514)]

然后 再去合并main 会发生什么?

  1. 产生一个新的 commit;
  2. dev 指向新的 commit;
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WNL3i4p1-1685028681291)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-11-22-45-48-image.png?msec=1684158868532)]

那么删除分支会删除分支指向的 commit 吗?答案是不会的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QqaSdn9B-1685028681292)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-11-22-55-28-image.png?msec=1684158868626)]

至此,分支的 创建、切换、合并、删除都演示完了。

记住一句话: 分支是一个有名字的指针,指向 某个 commit

变基 Rebase

有了上面的知识,变基就很好理解了。主要有两种情况

  1. git rebase <branch> 变基分支

  2. git rebase -i <commit-id> 变基提交

先说情况2,理解了情况2,情况1就很好理解了。

变基到某个提交

变基,变基,就是改变基底,通俗一些就是基于哪个commit。变基到某个提交也有两种情况, 本分支或者其它的分支上的提交。其实原理差不多,这里演示变基其他分支的提交。

为了方便查看效果,删除原有仓库及文件,重新初始化,并且进行一个提交。

# 清空仓库
➜  gitTest git:(new) rm -rf .git
➜  gitTest rm hello.txt test.txt

# 初始化
➜  gitTest git init
已初始化空的 Git 仓库于 /Users/Public/Learn/git/gitTest/.git/
➜  gitTest git:(master) echo "master txt" > master.txt
➜  gitTest git:(master)git add . && git commit -m "1st commit"
[master(根提交) b505c69] add master.txt
 1 file changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 one.txt

接着切出 dev 分支,产生三个提交, master 上产生两个

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5C3gr4yJ-1685028681292)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-13-12-35-45-image.png?msec=1684158868578)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zvt2l8MM-1685028681292)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-13-12-36-12-image.png?msec=1684158868564)]

可以看到 b505c6 是他们的共同提交,也可成为基底。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UGmPtfnb-1685028681292)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-13-12-54-42-image.png?msec=1684158868515)]

然后 dev 上变基 到 master上第一个提交 80b77b

git rabse -i 80b77b

我选择 sword 更改三条提交注释, 后面都加上了 rebase
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ziqKnS3c-1685028681292)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-13-12-58-50-image.png?msec=1684158868515)]

变基成功。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CxMniO6y-1685028681292)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-13-08-45-09-image.png?msec=1684158868592)]

新产生了三个 commit 对应着 dev 上原来的三个 commit, 并且原来的三个commit 消失了,dev的提交历史如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gfamxwTg-1685028681292)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-13-16-18-56-image.png?msec=1684158868533)]

master 分支不受影响,关系如下图。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vppbmqEU-1685028681292)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-13-16-36-35-image.png?msec=1684158868549)]

变基分支

假设现在 main 分支有1个提交 9b789c,新建分支 dev, 此时 main 、dev 分支的基底就为9b789c2

接着 在 dev 上产生了一个提交, main 上产生了2个提交,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8uouHjBo-1685028681292)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-13-17-03-15-image.png?msec=1684158868498)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-paXVdaVD-1685028681292)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-13-17-30-12-image.png?msec=1684158868498)]

用图总结一下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BxXeZB69-1685028681292)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-13-17-14-12-image.png?msec=1684158868498)]

此时 在 dev 分支上执行 git rebase main(不加 -i 就是啥都不改变,就是直接产生若干新提交到 main指向的提交后)。

dev 提交历史

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wT3iLKN7-1685028681292)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-13-17-18-13-image.png?msec=1684158868516)]

main分支不受影响

关系如图。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R3VmyYnS-1685028681292)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-13-17-23-35-image.png?msec=1684158868516)]

总结

变基就是 将当前分支 的所有commits都变为新的 commits,这些新commits的第一个的上一个提交为变基的目标 commit。前面说过,分支其实是个有名字的指针(类似HEAD),指向当前分支的最新 commit,分支变基不过是变基目标commit 不一样而已!

远程仓库

本地初始化仓库,并添加 远程(remote)配置, 远程名为 origin

git init
git remote add origin https://github.com/OFreshman/gitTest.git

配置 文件 .git/config 会增加 origin 的配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UehRhyso-1685028681293)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-13-17-49-10-image.png?msec=1684158868565)]

此时再建立本地与远程追踪,并推送至远程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RKfyYeS4-1685028681293)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-13-18-18-45-image.png?msec=1684158868566)]

objects也有一些小变化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LAEdvas6-1685028681293)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-13-18-20-13-image.png?msec=1684158868609)]

去查看这两个文件可以看到文件内容 含有的对象都是一个 29906142d145c9bcf6438088b7e4e5ac13853174

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5E43BQsy-1685028681293)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-13-18-23-21-image.png?msec=1684158868551)]

此时日志也表明 main与 origin/main 都指向 299061 ,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V3H37E9R-1685028681293)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-13-18-24-42-image.png?msec=1684158868479)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PAUU7X11-1685028681293)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-13-18-29-52-image.png?msec=1684158868499)]

总结起来就是远程仓库其实就相当于一个分支,只是 分支名有些特殊: origin/main, 相关的数据配置保存在 根目录和logs 的 refs/remotes

对象压缩

git作为代码库,有的代码仓库上G,甚至更大,如果不对这些仓库 代码文件做优化策略那么只要涉及文件的读取存改(在git这又是高频操作)会变得很慢,且存储下载占用大量带宽! 所以 Git 采取压缩的策略

现在 gitTest 文件夹下有两个文件 init.txt 、test.txt, 并且初始化仓库

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fc4bELan-1685028681293)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-22-20-06-19-image.png?msec=1684757179198)]

接着提交,objects 里增加了一些对象,9d、d5 为相应的blob 对象,可以看到大小都得到了压缩。

压缩使用的是zlib的deflate算法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7leDBfFY-1685028681293)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-23-08-39-24-image.png?msec=1684802364701)]

之前是 2.3M,155k。

通过 命令 git gc 主动压缩

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-leyLrvfM-1685028681293)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-23-23-24-42-image.png?msec=1684855483007)]

压缩之后,info 和 pack 增加了一些文件,主要关注 pack,里面含有 idx 和 pack 后缀的文件,压缩的所有文件对象都含在 pack 文件里, idx 相当于是个索引文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-axz5tks5-1685028681293)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-23-23-36-03-image.png?msec=1684856163533)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ww7BpYrW-1685028681293)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-23-23-46-55-image.png?msec=1684856815098)]

git 提供了命令去查看压缩文件内容 git verify-pack -v [<file>]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ckvMrc6F-1685028681293)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-23-23-41-25-image.png?msec=1684856485745)]

显示的信息依次为

SHA-1 type size size-in-packfile offset-in-packfile

git 也提供解压缩的 命令

git unpack-objects < <pack-file> #解压 .pack 文件

解压缩需要注意,需要将压缩文件移动位置(比如到 .git 根目录),因为

Objects that already exist in the repository will not be unpacked from the packfile Therefore, nothing will be unpacked if you use this command on a packfile that exists within the target repository.

git push 也是一个压缩的过程。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bTOgxIG5-1685028681293)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-23-23-23-43-image.png?msec=1684855423555?msec=1684856335821)]

git clone 也会产生压缩

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M6gWIXCh-1685028681294)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-25-22-09-19-image.png?msec=1685023759822)]

刚克隆的仓库只有 objects/pack 含有相应的压缩文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2W2aVuEH-1685028681294)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-25-22-11-39-image.png?msec=1685023899506)]

对于修改文件。 .idx内 只保留最新版本(因为用的最频繁),以前版本只保留diff

垃圾对象

垃圾对象是指 .git/objects 里面那些无用的对象。常见的两种情况下会产生:

  1. git add n次,执行commit,n-1次的add就会产生 n-1 个垃圾对象。TODO diff 差量存储咋做的。

  2. 分支删除后该分支上产生的 objects。

针对情况1,涉及到对象压缩(git gc)的操作时会去清除对象,这里我主动触发

In most cases, users should run git gc, which calls git prune.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v5OA2dZV-1685028681294)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-25-22-51-23-image.png?msec=1685026283958)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HNgBkX9U-1685028681294)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-25-22-52-29-image.png?msec=1685026349793)]

没被压缩的就被视为了垃圾对象(前两次修改时添加的), 执行 git prune 取清理掉垃圾对象(96,b1), 加 -n 可以看到 此命令会清除哪些对象。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AgyW3LbB-1685028681294)(file:///Users/ethanyin/Library/Application%20Support/marktext/images/2023-05-25-23-00-06-image.png?msec=1685026806455)]

针对情况2,就复杂一些,分支被删除,我们可以 通过reflog找到想要的提交再去拿出来。这也是 Git 的的想法:这些提交对象被视为将来可能会被用,所有就不会被当做垃圾对象,即使 执行 git prune 。但是有些情况下我确定那分支上的提交永远不会用了,而且这个分支上的提交对象都还比较大,不删除的话空间资源比较浪费(磁盘,云)。那该如何删除呢,网友提供了这样一条命令:

参考 #How to remove unused objects from a git repository?

git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 \
  -c gc.rerereresolved=0 -c gc.rerereunresolved=0 \
  -c gc.pruneExpire=now gc "$@"

最后

全文主要介绍了 git 常规的一些场景下 .git 文件的变化,主要是 .git/objects,基本讲清楚了git 背后的那些事。

本文拖了很久,前期看到自己文章池(写了,但没有写完的文章)有git 的一篇,去年开始写的,每天下班就补一补,总算是写完了。

参考

Git基本原理介绍-Blibli

一文讲透 Git 底层数据结构和原理

用21张图,把Git 工作原理彻底说清楚-腾讯云开发者社区-腾讯云

这才是真正的Git——Git内部原理 - 掘金

这个 git 命令你每天都在用,但你却不知道 - 掘金

Git不要只会pull和push,试试这5条提高效率的命令 - 掘金

45个 GIT 经典操作场景,专治不会合代码 - 掘金

前端架构师的 git 功力,你有几成火候? - 掘金

「一劳永逸」一张脑图带你掌握Git命令 - 掘金

多年 Git 使用心得 & 常见问题整理 - 掘金

Git原理与高级使用(2) - 掘金

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/590449.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

剑指 Offer 14- I. 剪绳子解题思路

文章目录 题目解题思路优化 题目 给你一根长度为 n 的绳子&#xff0c;请把绳子剪成整数长度的 m 段&#xff08;m、n都是整数&#xff0c;n>1并且m>1&#xff09;&#xff0c;每段绳子的长度记为 k[0],k[1]…k[m-1] 。请问 k[0]k[1]…*k[m-1] 可能的最大乘积是多少&…

Spring Boot + vue-element 开发个人博客项目实战教程(二十六、前端首页统计完善及完结)

⭐ 作者简介&#xff1a;码上言 ⭐ 代表教程&#xff1a;Spring Boot vue-element 开发个人博客项目实战教程 ⭐专栏内容&#xff1a;个人博客系统 ⭐我的文档网站&#xff1a;http://xyhwh-nav.cn/ 后端代码gitee地址&#xff1a;https://gitee.com/whxyh/personal_blog …

设计模式六大原则的理解

本文参考&#xff1a; 设计模式简介 | 菜鸟教程 (runoob.com) 六大设计原则之依赖倒置原则&#xff08;DIP&#xff09; - 简书 (jianshu.com) 设计模式的六大原则有&#xff1a; 1、开闭原则&#xff08;Open Close Principle&#xff09; 开闭原则的意思是&#xff1a;对扩…

设计模式之~桥接模式

桥接模式&#xff1a; 将抽象部分与它的实现部分分离&#xff0c;使他们都可以独立地变化。这种类型的设计模式属于结构型模式&#xff0c;它通过提供抽象化和实现化之间的桥接结构&#xff0c;来实现二者的解耦。 什么叫抽象与它的实现分离&#xff0c;这并不是说&#xff0c;…

图解系列 图解Spring Boot 最大连接数及最大并发数

文章目录 概序架构图TCP的3次握手4次挥手时序图核心参数AcceptCountMaxConnectionsMinSpareThread/MaxThreadMaxKeepAliveRequestsConnectionTimeoutKeepAliveTimeout 内部线程AcceptorPollerTomcatThreadPoolExecutor 测试参考 每个Spring Boot版本和内置容器不同&#xff0c;…

树状数组学习总结

今天本初中生蒟蒻学习了一下 树状数组 \color{red}{树状数组} 树状数组&#xff0c;总结一下~~~ 树状数组的实现 功能简介 快速求前缀和&#xff08; O ( l o g 2 n ) \color{purple}{O(log_2n)} O(log2​n)&#xff09;修改某一个数&#xff08; O ( l o g 2 n ) \color{gr…

SpringBoot+原生awt,实现花花绿绿的图形验证码

图形验证码是用于验证用户身份的一种方式&#xff0c;通常在网站注册、登录或进行某些敏感操作时会使用。它通过展示一个包含随机字符或数字的图形&#xff0c;要求用户输入相应的字符或数字来证明其为真人而非机器人。图形验证码能有效地防止机器人攻击和恶意注册行为&#xf…

Excel·VBA自动生成日记账的对方科目

如图&#xff1a;根据日记账/序时账的日期、凭证号为一组&#xff0c;按借贷方向生成相反的科目&#xff0c;并写入H列。可能存在一对一、一对多、多对多等情况的账目 目录 数组法遍历、判断、写入测试结果 多对多问题处理测试结果 数组法遍历、判断、写入 适用日期凭证号连续…

HTTPS的加密流程——巨详细!

文章目录 前言HTTPS的工作过程引入对称加密引入非对称加密引入证书完整的加密流程总结 前言 HTTPS 也是一个应用层协议. 是在 HTTP 协议的基础上引入了一个加密层. HTTP 协议内容都是按照文本的方式明文传输的. 这就导致在传输过程中出现一些被篡改的情况. 比如&#xff1a;臭…

民宿预订系统的设计与实现(ASP.NET,SQLServer)

这个民宿预订系统是由第三方的运营公司来运营&#xff0c;他提供了一个民宿和客户都使用的一个信息平台&#xff0c;民宿注册之后把自己的民宿信息发布到网站平台上&#xff0c;然后发布自己的房间信息&#xff0c;打折信息等供客户查看和选择。客户可以在网站平台上查看民宿信…

深度学习:大模型的正则化

l1l2正则和dropout正则化[https://youzipi.blog.csdn.net/article/details/75307522] LN和BN归一化 [深度学习:批归一化Batch Normalization] 主流大模型使用的Normalization主要有三类,分别是Layer Norm,RMS Norm,以及Deep Norm。 Post-Norm和Pre-Norm 根据Normalizat…

网工内推 | 快手、瑞芯微招运维,思科、红帽认证优先

01 快手 招聘岗位&#xff1a;IT系统运维 职责描述&#xff1a; 1、负责IT基础架构运维体系的建设和优化改进&#xff1b; 2、负责IT核心基础服务&#xff08;如DNS、负载均衡、容器&#xff09;的架构设计、平台建设和运维&#xff1b; 3、负责IT内部日志系统、监控系统、报警…

SpringCloud微服务框架(通俗易懂,一秒上手)

&#x1f381;&#x1f381;资源&#xff1a;https://pan.baidu.com/s/1zRmwSvSvoDkWh0-MynwERA&pwd1234 SpringCloud微服务框架 &#xff08;一&#xff09;认识微服务服务架构演变SpringCloud &#xff08;二&#xff09;微服务拆分案例服务拆分服务间调用 &#xff08;三…

ROS:订阅者Subscriber的编程实现(C++)

目录 一、话题模型二、创建功能包三、创建Subscriber代码四、编译代码五、运行 一、话题模型 图中&#xff0c;我们使用ROS Master管理节点。 有两个主要节点&#xff1a; Publisher&#xff0c;名为Turtle Velocity&#xff08;即海龟的速度&#xff09; Subscriber&#xff0…

Rocketmq面试(一) Rocketmq同一个消费组订阅不同的Tag,会有什么问题?

先说结果&#xff1a;会造成数据丢失 再说依据&#xff1a; RocketMQ要求同一个消费者组内的消费者必须订阅关系一致&#xff0c;如果订阅关系不一致会出现消息丢失的问题。 官网入口&#xff1a;订阅关系一致 | RocketMQ 不想看官网的&#xff0c;直接看结论 什么叫订阅关…

复杂SQL实践-MYSQL

MySQL 8.0窗口函数 MySQL从8.0版本开始支持窗口函数。 窗口函数总体上可以分为序号函数, 分布函数, 前后函数, 首尾函数和其他函数。 描述 题目&#xff1a;现在运营想要查看用户在某天刷题后第二天还会再来刷题的平均概率。请你取出相应数据。 示例1 drop table if exist…

对远程http服务的拨测体验

背景&#xff1a; 过程是这样的&#xff0c;需要与合作方数据进行交互&#xff08;肯定是不允许直接连对方数据源的&#xff09;&#xff0c;对方提供了两台server&#xff0c;后端同事在server上面作了proxy搭建了桥接的应用&#xff08;两台server没有公网ip&#xff0c;通过…

Eclipse 教程Ⅹ

本次内容会涉及到Eclipse 重构菜单、Eclipse 添加书签和Eclipse 任务管理&#xff0c;老规矩&#xff0c;直接开始吧&#xff01; Eclipse 重构菜单 使用Eclipse重构 在项目开发中我们经常需要修改类名&#xff0c;但如果其他类依赖该类时&#xff0c;我们就需要花很多时间去…

机器学习模型的生命周期

动动发财的小手&#xff0c;点个赞吧&#xff01; 您的模型如何变化&#xff1f;Source[1] 诞生 当我们构建、训练、拟合或估计我们的模型时&#xff0c;这些数字工具就诞生了。这个阶段几乎从拥有分析目标、数据、计算机、算法以及数据科学家现在已经非常了解的其他一切开始。…

Linux [权限]

Linux 权限 Linux用户分类切换成root方法例子 切换成普通用户方法例子 短暂提权 什么是权限理论知识展示区域 修改权限(1)修改文件属性1. 采用 w/r/x的形式2. 采用八进制的形式 (2)修改身份1. 修改拥有者2. 修改所属组3. 修改拥有者 && 所属组 问题区问题1问题2问题3 L…