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

关于 git push -f 覆盖提交的疑问

  •  
  •   Kasumi20 · 2022-01-11 14:28:56 +08:00 · 2178 次点击
    这是一个创建于 1077 天前的主题,其中的信息可能已经有所发展或是发生改变。

    好奇,假如提交了一个 1G 的文件,然后--amend 修改成一个小文件,最后 git push -f 强制推送,别人从 Github 上拉下来能恢复那个 1G 的文件吗?

    8 条回复    2022-01-12 02:55:38 +08:00
    codehz
        1
    codehz  
       2022-01-11 14:43:48 +08:00
    1G 的话实际也推不上去(得用 LFS (然后问题就很复杂了))
    不考虑这个问题的话,其他人可以通过记录第一次推送时的 commit hash 来强行获取旧的文件(在 github gc 之前都能存在)
    maichael
        2
    maichael  
       2022-01-11 14:43:51 +08:00
    我觉得是可以得,实际上可以反过来想,按照常用的删除历史大文件的文档(比如 https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/removing-sensitive-data-from-a-repository ),远不是 --amend 那么简单。
    Explr
        3
    Explr  
       2022-01-11 14:45:54 +08:00   ❤️ 2
    我在本地测试的结果是能。假定你是说先提交大文件 -> 推送 -> --amend 修改成小文件 -> 强制推送的话。

    git 的提交记录是有向无环图,--amend 只是创建一个新结点,新结点的父结点指针指向原提交的父结点。如果把这个局部看成树的话,--amend 提交产生的新结点和原结点是兄弟关系。

    而强制推送后,只是强制将 HEAD 指针从原结点指向了新结点,而原结点依旧存在,使用 git checkout <原提交 id>即可检出。但据我测试,如果按照提交大文件 -> --amend 修改成小文件 -> 推送这个顺序进行,git 不会将原结点推送到服务器。这意味着你可以在本地检出原结点,但另一个克隆这个仓库的人不能检出原结点。
    iamzuoxinyu
        4
    iamzuoxinyu  
       2022-01-11 14:47:05 +08:00   ❤️ 2
    多数情况下可以通过 git reflog 再 checkout 恢复。
    SoloCompany
        5
    SoloCompany  
       2022-01-11 15:35:35 +08:00
    理论上可以做到禁止
    如果在你 force push 之前别人已经 fetch 过那当然无法禁止
    其余情况下可以通过在服务器上执行 prune 删掉 dangling object (前提是你可以操作服务器), 或者最彻底的方法是删除 repo 然后重建

    至于 github, 这里说的很详细

    BTW, 印象中之前好像基于安全或其它原因一直是不允许 git fetch origin <SHA> 的, 但貌似新版的 git 服务器 (2.20.1?) 又允许了 https://stackoverflow.com/questions/14370157/git-fetch-a-specific-commit-by-hash/62463160#62463160
    skiy
        7
    skiy  
       2022-01-11 17:57:53 +08:00
    自己本机有记录的话,应该可以吧? git reflog 获取 commit id 。但是别人那边的话,没实测过。

    话说你自己本机也可以测试的啊,测试时不一定要放 1G 的文件。

    如果是 *NIX 系统,那直接在 root/USER 就相当于两个用户了。(可以跑 Docker + Git )
    msg7086
        8
    msg7086  
       2022-01-12 02:55:38 +08:00
    主要是看你有没有把对象 push 到服务器。
    你可以把 Git 想象成对象存储数据库。你本地写入的数据都会进这个数据库,但是你 push 的时候只会把有效数据 push 到服务器。如果你提交了 1G 的大文件,但是没有把这个文件 push 到服务器,那么服务器的数据库里就不会有这个对象,别人也就无法检出了。反过来说,如果你已经把对象 push 上去了,以后再删除的话也不会从服务器上删除,别人还是可以检出这个文件。

    Force push 只是允许你在非 FF 状态下修改分支指针,不会影响数据库里已有的对象。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1177 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 18:16 · PVG 02:16 · LAX 10:16 · JFK 13:16
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.