Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Git原理以及使用分享(周五分享) #176

Open
soapgu opened this issue Nov 29, 2022 · 0 comments
Open

Git原理以及使用分享(周五分享) #176

soapgu opened this issue Nov 29, 2022 · 0 comments
Labels

Comments

@soapgu
Copy link
Owner

soapgu commented Nov 29, 2022

  • PPT主要脉络

  • 为什么要做这次分享?我的目标是什么?
    为了能用好Git,能解决平时Git中使用中碰到的常见问题

  • 不讲道理只讲规范就是耍流氓
    这次先不是重点在How,而是What和Why

  • 到底Git是个什么?
    The stupid content tracker 傻瓜式内容跟踪器
    从代码管理工具角度来说狭隘的一些,其实是内容管理工具
    那他是怎么跟踪法的那,需要先了解下Git的内部结构

  • 探索Git的空间组织形式

首先从物理存储角度,一切都在.git这个文件夹中
图片

  1. index 文件
    不可通过文件查看器直接查看,是git的暂存区的内存映射文件

  2. HEAD
    当前指向分支

  3. object 文件夹

图片

文件结构不不算复杂 组织形式为 {2位16进字符}文件夹 {38位16进制字符}文件 就是对象数据库,这个后面详细讲
  1. refs

图片

本地分支

图片

远端分支

以及Tag等

  • 探索Git的存储形式
    回答下前面“追踪”系统怎么个追法

其实是一个“内容寻址”系统
而前面的objects文件夹其实是一个,键值对数据库(key-value data store)

Key是什么?
就是20个byte组成
其中1个byte用16进制表示,正好高低字节占用2个字符
所以前面objects的文件结构长这样。

对象数据的统一结构

文件头:{type} {lenght}
内容:{deflate压缩算法内容}

  1. 数据对象(blob object)
    数据对象是对象中最基础的。数据针对的就是你想要进入版本管理的内容数据。万物皆可blob,源代码/图片/视频等等等等
    这属于内容本身了,就是内容以压缩的形式存储了

  2. 树对象(tree object)
    树对象对应文件夹的描述,包含blob数据对象和子树对象。如果你把blob对象想象成叶子,可以能更理解一些。
    所以blob object/tree object已经可以描述任何存储形式了

  3. 提交对象(commit object)
    提交对象是一个很特别的对象。他指向了一个树(tree)来描述当时整个版本的描述。记录下下作者和时间
    同时有一个或者多个 parent commit,如果是没有就是第一次提交
    parent commit为啥有多个?那是因为有merge操作

  4. tag对象
    只有带注释的标签有tag对象,可以指向一个commit。
    我们针对分支打tag,本质其实是对这个分支打当前commit打tag
    简单tag是没有的

图片

blob object <- tree object <- commit object <- tag object

  • Git的逻辑分区
    图片

  • Git的暂存区(stage)详解
    物理存储是index文件
    文件存储结构是

cache_header
cache_entry 列表
SHA1签名

cache_entry 列表的存储形式

struct cache_entry {
struct cache_time ce_ctime;
struct cache_time ce_mtime;
unsigned int ce_dev;
unsigned int ce_ino;
unsigned int ce_mode;
unsigned int ce_uid;
unsigned int ce_gid;
unsigned int ce_size;
unsigned char sha1[20];
unsigned short ce_flags;
char name[0];
};

  • 几个反直觉的Git知识
  1. 每次commit的内容是增量存储还是全量存储?文件夹是如何存储?
    commit对应了根目录的tree,tree包含的所有的文件的引用(SHA1),Git只存内容,文件夹只是“顺便”存储,所以实际上你不能操作把一个空的目录 ,add 到 stage

这样不是特别会特别大?
不会。首先因为虽然tree是全量的,但是他只是引用,容量并不大。只有修改的文件才会产生一个新版本,我改一行代码,就会产生一个全量的存储,是不是有点浪费。
这里git帮我们想到了,使用git会定时GC
图片
obejcts文件夹里面又个pack文件夹,会帮你做压缩,其实他会帮你把历史版本的文件和当前文件做一个压缩,把diff单独diff出来再压缩,等需要的时候再还原出来

  1. 缓存区(Stage)存的是不是只存我git add进去的文件?
    其实Stage中存了所有文件的索引,不只你本次add进去的文件,当前版本的所有文件都在!
    实际上因为是文件的快照,容量实际很小。基本上没有压力
  • Git使用的介绍说明

时间篇幅有限
不介绍常规使用
只介绍对git有误解的操作

  • 本地分支?远端分支?傻傻分不清楚
  1. 分支只是一个commit的引用
    我们分别可以在refs里面head文件夹(本地分支)和remote(远端分支)
    打开文件我们可以看到就是一个SHA1,指向最新的commit
    所以这里就是一个引用和refs文件夹表意一致

  2. 本地分支和远端分支本来并无联系
    你管你我管我。只是默认我们在checkout的时候会帮我们--track,--set-upstream-to

图片

  1. 远程分支其实并不远,他是本地的只读分支
    首先你也可以checkout远程分支
guhui@guhuideMacBook-Pro ipad % git checkout origin/main
注意:正在切换到 'origin/main'。

您正处于分离头指针状态。您可以查看、做试验性的修改及提交,并且您可以在切换
回一个分支时,丢弃在此状态下所做的提交而不对分支造成影响

因为是分离头指针所以会有警告

  • 谨慎使用 git pull,git merge,放心使用git fetch
  1. git fetch 只是获取远端分支和tag,并不操作本地分支,他是“安全”的
  2. 不在全局配置和参数的git pull 的本质是 git fetch + git merge origin/
  3. 为啥要回避git merge
    因为merge会产生多个parent
    造成“回溯困难”,特别如果是某一个版本出现bug,要从历史中翻出一个健康版本找到问题,会增加复杂度
  4. 为啥我们喜欢fast-forward?
    相对merge,个人分支的提交是直接追加到main分支上,少一个merge的commit,都大大减少复杂度
  • 不要恐惧git reset

学习后正确姿势是git reset commitid
但是三剑客教程里面没有说详细用法,一共有三种mode

  1. mix
  2. soft
  3. hard

如果要搞清楚这三个mode的区别,还是要重新捋一捋工作区(working tree)、缓存区(index file)、指针(HEAD)
其实很多git的操作就是对状态的操作

  • 工作区(working tree):本地工作阶段
    图片
  • 工作区(working tree)->缓存区(index file): git add
    图片
  • 缓存区(index file)-> 指针(HEAD): git commit,提交后HEAD指针后移
    图片

其实,git工作的过程就是追求状态一致性的过程,我们在完成工作以后,工作区(working tree)、缓存区(index file)、指针(HEAD)的状态都是一致的

好了,前面讲的都是正向工程。
那么git reset commit mode 就是妥妥的逆向工程

初始状态:
图片

  1. --mix
    也是默认参数,重置 缓存区(index file),保留 工作区(working tree),指针移动
    就是回到了
    图片
    如图这个状态。
    使用场景:我反悔我的提交了,原来的提交太大了,我撤回来只add了一个文件先commit,其他的文件再提交

  2. --soft,保留 缓存区(index file),保留 工作区(working tree),指针移动
    就是回到了
    图片
    使用场景:我反悔我的提交了,上一个提交交了好多文件,但是我只要撤回一个文件的修改。

  3. --hard,重置 缓存区(index file),重置 工作区(working tree),指针移动
    简而言之就是“一夜回到解放前”
    图片
    使用场景:我都提交了点啥垃圾代码,交上去非社死不可,不要了不要了

  • 什么是git rebase变基?
    图片
    图片

  • 变基的两个方向的主要用法

  1. 合并远端分支提交
  2. 本地分支历史调整(合并提交,修改commit等)

命令
git rebase <newbase>

  • 答疑
@soapgu soapgu added the Git label Nov 29, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant