You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Git推送孤立分支重复上传相同文件的解决方案问询

Git推送独立分支时重复上传相同对象的问题与解决办法

问题场景复现

你大概率遇到过这种头疼的情况:

  • 创建新分支,提交一个10MB文件并完成推送,流程正常
  • 接着创建孤立分支(无父提交的空分支),提交同一个完全未修改的10MB文件(SHA哈希完全一致),推送时却发现Git又重新上传了一遍这个大文件

可以通过以下命令复现这个问题:

$ mkdir git-test && cd git-test
$ git init
$ git remote add origin git@gitlab.com:username/projectname.git
# 创建10MB测试文件
$ head -c 10000000 /dev/urandom > dummy
$ git add dummy
$ git commit -m 'init'
# 首次推送,上传全部内容,符合预期
$ git push origin master
Counting objects: 3, done.
Delta compression using up to 6 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 9.54 MiB | 1.13 MiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
# 创建不基于master的空孤立分支
$ git checkout --orphan branch2
# 再次添加相同文件
$ git add dummy
$ git commit -m 'init on branch2'
# 服务器已存在该对象,但仍重新上传10MB文件
$ git push origin branch2
Counting objects: 3, done.
Delta compression using up to 6 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 9.54 MiB | 838.00 KiB/s, done.

预期vs实际差异

按Git的设计逻辑,靠SHA识别文件对象,应该能检测到服务器上已经存在这个文件,从而避免重复上传;但实际情况是,只要分支完全独立(无共同历史),推送时所有关联对象都会被重新上传——哪怕是大量重复的小文件,在低带宽环境下特别影响效率,比如机器学习实验场景:每次创建无父提交的新提交并关联自定义引用(如refs/jobs/my-experiment-name),大量重复文件反复上传会严重拖慢工作节奏。

问题根源

这是Git本身的协议设计导致的:Git的pack同步协议是基于提交历史来判断需要传输哪些对象的。两个独立分支没有共同父提交,Git不会单独去校验服务器上是否存在某个孤立的对象,只会检查当前提交链里的对象在服务器的提交历史中是否存在,所以哪怕文件对象完全一致,也会被重复传输。

解决办法

我们可以用自定义逻辑绕过这个限制,核心思路是先让Git明确服务器上已有的对象,只推送缺失的部分:

  1. 提取目标提交关联的所有对象SHA(排除父提交相关的对象)
  2. 将SHA列表发送到服务器,获取服务器确实缺少的对象列表
  3. 仅基于这些缺失对象构建pack文件推送,最后更新对应的远程引用

你可以自己实现这个逻辑,也可以用现成的自定义脚本方案,使用后的效果非常明显:

marc@osx ~/git-test (branch11*) $ # 按前述方式创建branch11
marc@osx ~/git-test (branch11*) $ python git-sync.py refs/heads/branch11
Counting objects: 1, done.
Writing objects: 100% (1/1), 158 bytes | 158.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0)
marc@osx ~/git-test (branch11*) $ git push origin branch11
Everything up-to-date

可以看到,这次只同步了提交对象本身,重复的大文件和树对象都没有被重复上传。

内容的提问来源于stack exchange,提问作者MMM

火山引擎 最新活动