V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
git
Pro Git
Atlassian Git Tutorial
Pro Git 简体中文翻译
GitX
weishao666
V2EX  ›  git

git fork 200M 的仓库,服务端磁盘占用并不会变大,是怎么做到的

  •  
  •   weishao666 · 253 天前 · 2797 次点击
    这是一个创建于 253 天前的主题,其中的信息可能已经有所发展或是发生改变。

    git fork 一个 200M 的仓库 A ,得到 B ,我在 B 的裸库查看大小 du -sh ,可以看到是 200M ,但是我整个磁盘的大小并不会增加 200M ,机会没变化。这是 git 的什么机制做到的呢?假如我把 B copy 到/tmp/B ,那磁盘就增加了 200M ,又是什么原理?肯定跟底层的文件引用啥的有关系,但是我在 B 的裸库中并没有见到软链接

    第 1 条附言  ·  251 天前
    其实一楼就给到了答案,可以理解就是 gitlab 的 fork 吧,答案就是硬链接。
    V2 依然这么有趣,谢谢大家
    47 条回复    2024-08-22 17:22:03 +08:00
    Muniesa
        1
    Muniesa  
       253 天前 via Android
    没见到软链接,那硬链接呢
    Trim21
        2
    Trim21  
       253 天前 via Android
    git 有 fork 这个命令吗…
    mxT52CRuqR6o5
        3
    mxT52CRuqR6o5  
       253 天前
    git 的原理没了解过吗?
    cc666
        4
    cc666  
       252 天前
    @mxT52CRuqR6o5 #3 git 有 fork 这玩意儿么,还原理
    所以楼主你具体是怎么操作的
    mxT52CRuqR6o5
        5
    mxT52CRuqR6o5  
       252 天前 via Android
    @cc666 op 在服务器建了个 git 服务(可以理解成 gitlab ),然后在 gitlab 里进行 fork 操作,fork 了一个很大的仓库,但 git 服务占用的服务器磁盘空间没有增加很多,这都看不明白吗
    而这个现象和 git 在本地的存储原理是息息相关的
    cc666
        6
    cc666  
       252 天前
    @mxT52CRuqR6o5 什么本地存储原理,本质上来说不就是一堆 blob 和 pack 对象么,这怎么解释 OP 的问题:空间没有增长? git 本身就没有 fork 这玩意儿,他规定了服务端是实现 fork 是复制一个新的目录还是软硬链接实现 fork 么,规定了 fork 的时候是否执行一次 aggressive gc 么?规定了服务端是否使用去重文件系统么?你要是能回答就回答,不会回答就别嚷嚷着:你不懂“git 在本地的存储原理”
    mxT52CRuqR6o5
        7
    mxT52CRuqR6o5  
       252 天前
    @cc666 #6 一堆 blob 和 pack 对象还不够解释吗?
    cc666
        8
    cc666  
       252 天前
    @mxT52CRuqR6o5 那你解释一下?快解释,为什么 fork 了一个空间没有增长
    mxT52CRuqR6o5
        9
    mxT52CRuqR6o5  
       252 天前
    @cc666 #6 一堆 blob 和 pack 对象还不够解释吗?你干脆从 CPU 是怎么从沙子造出来开始解释好了
    cc666
        10
    cc666  
       252 天前
    @mxT52CRuqR6o5 你干脆从因为这样所以这样来回答所有问题好了
    mxT52CRuqR6o5
        11
    mxT52CRuqR6o5  
       252 天前
    @cc666 #8 fork 了又没增加新 blob 和 pack ,为啥会增长,为啥不能解释
    cc666
        12
    cc666  
       252 天前
    @mxT52CRuqR6o5 你 fork 的仓库和别人的仓库放在 path 么? git 规定了么? gitlab (假设是 gitlab )用的不是复制而是软硬链接么?还是用的去重文件系统?
    mxT52CRuqR6o5
        13
    mxT52CRuqR6o5  
       252 天前
    @cc666 #12 fork 行为不增加 blob 和 pack ,基于此原理就能实现一个 fork 不增加存储占用的 git 服务,还有啥不够吗?你再往下深究什么软硬链接去重文件系统这个系统背后的细节具体是怎么设计的,不就是我之前说的干脆从 CPU 是怎么从沙子造出来开始解释好了
    说得好像软硬链接文件去重我就不能继续往下深究一样,你咋不再往下解释解释软硬链接文件去重怎么就能节省存储空间了,为啥存储数据会增加存储空间,为啥磁盘会用容量上限,为啥磁盘能存储数据
    cc666
        14
    cc666  
       252 天前
    @mxT52CRuqR6o5
    “基于此原理就能实现一个 fork 不增加存储占用的 git 服务”
    你这个回答就是假设了 OP 用的是一个能能够做到重复文件不增加存储空间的 git 托管实现或者服务器了
    mxT52CRuqR6o5
        15
    mxT52CRuqR6o5  
       252 天前
    @cc666 #14 服务器存 blob 和 pack 就行了,都不需要去重
    cc666
        16
    cc666  
       252 天前
    @mxT52CRuqR6o5 不管是 blob 还是 pack ,还是小猫小狗存,结果都是一样的,答案就是:服务器存小猫小狗就行了
    并且为什么假定服务器在复制一个仓库之后不对仓库进行 gc 呢,存 blob 和 pack 如果遇到 hash 冲突呢( git 的 hash 冲突是存在的并且很坑的),这都是很复杂的情况,这其实和 git 的实现没什么关系,这完全是 git 服务的实现有关
    mxT52CRuqR6o5
        17
    mxT52CRuqR6o5  
       252 天前
    @cc666 #16 你说的这些不还是我最开始说的问题「干脆从 CPU 是怎么从沙子造出来开始解释好了」
    hash 冲突这些不还是实现细节,而且还是 blob 、pack 实现的(必须处理的) edge case ,fork 一个仓库服务端存储没有大幅度增加,到底是因为 blob 、pack 的设计呢?还是因为你说的这些 edge case 呢?而且为啥你会假定 fork 一个仓库就非得把所有东西复制一遍再 gc ,不是很能理解
    blob 、pack 的设计不就是 git 的基本原理的一部分吗?所以我说让 OP 去了解 git 的原理到底有什么问题? fork 后服务端存储没有大幅度增加,blob 、pack 的设计就是最最最最主要的原因
    cc666
        18
    cc666  
       252 天前
    @mxT52CRuqR6o5 即使不是 blob 和 pack 存,是用小猫小狗存,只要他要在磁盘上存东西,结果都是一样,所以这个问题的本质和 git 的原理没什么关系,而是服务器的实现
    cc666
        19
    cc666  
       252 天前
    @cc666 而我们没法假定 OP 的服务用的是什么,在 OP 给出更多信息之前,也不知道问题的答案
    mxT52CRuqR6o5
        20
    mxT52CRuqR6o5  
       252 天前
    @cc666 #18 我十分怀疑你还是没明白 OP 问的问题是什么,OP 是在服务器建了个 git server ( gitlab 这种),而不是在服务器 git clone 了一个仓库然后又复制了一份
    什么叫「即使不是 blob 和 pack 存」,git 底层那些东西不就是 blob 、pack ,不存这些存什么,fork 一个仓库没增加 blob 、pack ,自然存储占用不会大幅增加
    cc666
        21
    cc666  
       252 天前
    @mxT52CRuqR6o5 我理解 OP 的问题和你的每一条回复,但你没明白我的观点:导致这个现象的原因根本不是 git 的底层实现,而是 git 服务( gitlab GitHub or 自建的其他任何一种 git 托管服务)的服务实现,你所说的 edge case ,gc 等不重要更加应证了这一点:这不是 git 管的事情,不是 git 的底层原理,这是服务的事
    mxT52CRuqR6o5
        22
    mxT52CRuqR6o5  
       252 天前
    @cc666 #21 难道你想要 git server 完全抛弃 blob 、pack 这些原生概念,设计一个不包含 blob 、pack 概念的存储系统?你也是有点离谱
    但凡 git server 基于 blob 、pack 去进行存储,blob 和 pack 都没增加,我为啥还要考虑 git server 是怎么存储 blob 、pack 的,最重要的去重你说是在 blob 、pack 这个抽象层发生的还是在存储层发生的?除非你去设计一个命名存储的东西每增加,存储占用仍会大量增加的存储系统
    cc666
        23
    cc666  
       252 天前
    @mxT52CRuqR6o5
    首先:"但凡 git server 基于 blob 、pack 去进行存储", 你这已经是在假设 git 服务的实现了
    其次:我为什么不能直接使用 path 进行存储,非得用 blob ,pack 存储,将仓库所在 path 里的所有文件都存储在一个去重的文件系统/第三方存储服务里,不就实现了这个功能了么,并且抽象层次更好,不用记录 blob 、pack 和仓库的关系,直接目录作为仓库,和原生的 git 概念完全一致
    最后:我这里不是在讨论什么样的服务设计更好,而是证明,问题讨论到这个范畴,已经不是 git 的问题了,而是 git 服务怎样实现才导致了这个情况,git 本身是保证不了复制( fork )一个仓库不增加存储空间的
    mxT52CRuqR6o5
        24
    mxT52CRuqR6o5  
       252 天前
    @cc666 #23
    「为什么不能直接使用 path 进行存储,非得用 blob ,pack 存储」是真离谱,blob 、pack 本来就是底层的东西,你说你不用这些底层的概念去存储,要把底层的这些东西揉碎了再重新设计一套系统去存,真是离谱他妈给离谱开门
    c3de3f21
        25
    c3de3f21  
       252 天前
    打起来了。。。。
    cc666
        26
    cc666  
       252 天前
    @mxT52CRuqR6o5
    path 为什么是打散的,目录是 path ,文件也是 path ,用 path 存就是直接简单直观的,甚至直接加一个 bucket://prefix 就可以同步到任何一个文件存储系统,加一个本地路径前缀就是本地文件系统,你自己电脑上 git 仓库不就是存在一个 path 么
    deorth
        27
    deorth  
       252 天前 via Android
    /go/flamewar
    笑死,这也能打起来
    cc666
        28
    cc666  
       252 天前
    @c3de3f21 不是打起来了,对任意技术一个问题,知道答案就回答,不知道就说不知道,不瞎猜,问题有误有不充分的就提出疑问,说一句“XXX 的原理没了解过么”,让别人猜谜语去吧,你看吵了半天,OP 的问题答案,还是不知道具体原因,在 OP 出来给出自己的配置之前,谁也答不上来真实具体的原因
    mxT52CRuqR6o5
        29
    mxT52CRuqR6o5  
       252 天前
    @cc666 #26 你对一个 git 仓库的理解就是当前 HEAD 表面的那些文件吗?所有的历史提交的所有版本的文件你不管?同一个 path 下可能有 100 个版本的文件
    cc666
        30
    cc666  
       252 天前
    @mxT52CRuqR6o5 一个 git 的仓库,不管是裸仓库还是普通仓库,PATH 不包含你说的那些 blob pack 等等等等文件么?
    root71370
        31
    root71370  
       252 天前
    各位,我来说一句
    atuocn
        32
    atuocn  
       252 天前
    @mxT52CRuqR6o5 @cc666

    这问题不能怪 cc666 一直追问。git 没有 fork 命令,所谓 fork 是 gitlab, github 等仓库管理系统的功能。fork 后是 2 个独立仓库,否则你的提交历史、分支、Tag 岂不是混在一起了。那么 2 个独立的 git 仓库,各自有自己的的 blob, pack 一堆巴拉巴拉的东西了。git 本身机制是无法解释一个仓库目录复制一份后,server 的空间没有增长多少。我搭建的 gitlab ,里面的仓库 fork 了许多次,在我担心磁盘空间的时候,我发现这个现象后也很惊讶。但我没有仔细深究,大约猜测是 gitlab 在 fork 仓库的时候,使用硬连接,而不是把相同的文件再复制一份。
    lisxour
        34
    lisxour  
       251 天前
    这一波我只能说 OP 问的问题很有问题,git 并没有 fork 功能,所以你这么一描述,我这个 git 专业户都被你描述得一愣一愣的
    weishao666
        35
    weishao666  
    OP
       251 天前
    @Muniesa 是的,就是硬链接
    Corybyte
        36
    Corybyte  
       251 天前   ❤️ 1
    v2 的技术氛围真浓厚
    ysc3839
        37
    ysc3839  
       250 天前
    @atuocn git 本身没有 fork 功能,其他第三方 git 管理软件实现 fork 一般是类似共用仓库新建 branch 的做法,commit 是会混在一起的。

    比如我最近在 GitHub 上 fork 一个仓库后的 commit ,在原仓库下也是能访问到的
    https://github.com/zhongyang219/TrafficMonitor/commit/717d3afbbb836986b7f0abea8de18d87c8f3a4d5
    atuocn
        38
    atuocn  
       250 天前
    @ysc3839 github 上建立 fork 的时候,上面会提示:“A fork is a copy of a repository. Forking a repository allows you to freely experiment with changes without affecting the original project. ”
    atuocn
        39
    atuocn  
       250 天前
    从实际使用来看,也没有发现两个仓库共用了存储的迹象。你那个提示,我觉得更像是 github 在查询 commits 时,兼顾查询了其他 fork 的仓库后,对你的一个友好提示。op 已经回复,是使用硬链接进行的复制,他应该是查过自己用的 git 管理系统的存储吧。
    ysc3839
        40
    ysc3839  
       250 天前 via Android
    @atuocn 首先面向普通用户的说明文本并不能代表底层架构如何。
    其次从实际来看,“git 仓库”可以看成只包含 tag 和 branch ,底层的 object 可以认为和仓库无关,那 fork 后确实不会影响源仓库的 tag 和 branch 。
    从另一个角度看,GitHub 也没必要“在查询 commits 时,兼顾查询了其他 fork 的仓库”,因为现在查看这类 commit 时,会加上一个警告“This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.”,以前是出现过利用这种机制去骗人的。
    最后 OP 的回复只是猜测。
    e3c78a97e0f8
        41
    e3c78a97e0f8  
       249 天前 via iPhone
    本地的 git clone 就是硬链接
    atuocn
        42
    atuocn  
       249 天前
    @ysc3839 github 如何实现内部存储的是个黑匣子,既然它说了 fork 是个 copy, 用起来也像个 copy (你提到的 commit 查询,只是 github 页面上的功能,本地应该是查不到的),那对我们来说就是一个 copy.

    另外,我登入到 gitlab 的 server 上看了一下,它的 git 仓库就是一个一个的目录.
    atuocn
        43
    atuocn  
       249 天前
    好吧,33 楼给了答案。gitlab 使用了 git alternates 机制

    At the Git level, we achieve deduplication by using Git alternates. Git alternates is a mechanism that lets a repository borrow objects from another repository on the same machine.
    Shatyuka
        44
    Shatyuka  
       249 天前
    Shatyuka
        45
    Shatyuka  
       249 天前   ❤️ 1
    proxychains
        46
    proxychains  
       249 天前
    @Shatyuka #45 哈哈哈哈哈哈哈哈哈
    mxT52CRuqR6o5
        47
    mxT52CRuqR6o5  
       78 天前
    压根就没人说过 fork 是个 copy, 实际用起来也不像 copy
    依赖文件系统的 link 能力去管理重复文件非常地工程实践层面的不合理,如果文件系统不支持 link 那我 git 服务岂不是还部署不上去了?如果不同文件系统的 link 行为不一致,那我写实际业务代码时还得去考虑这些区别?压根儿就不应该往文件系统 link 这个方向去思考,在 git 自身已经提供了复用相同文件的机制的情况下,任何不借助 git 自身能力去管理重复文件的实践都是不合理的,完全属于画蛇添足脱裤子放屁的行为
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1110 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 18:55 · PVG 02:55 · LAX 10:55 · JFK 13:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.