Git使用:大体积的历史commit无法推送到远程仓库的解决方案

0 介绍

场景:把本地仓库全量推送到远程的空仓库,保留提交历史,所有分支,所有tag;

大部分代码托管服务都会有免费推送的限制(如gitlab,Free push limit | GitLabAccount and limit settings | GitLab),所以当提交中包含大于指定体积的commit时,会遇到如下的失败:

如上的失败,可以通过git 命令,批量改写提交历史来解决;

本文以在GitHub建立远程的空仓库为例,介绍本地仓库推送至远程仓库,保留提交历史,所有分支,所有tag,和批量改写提交历史的步骤,以解决『大体积的历史commit无法推送到远程仓库』的问题;

1 新建远程的空仓库

不要添加默认的README,仓库必须为空,否则会push失败;

2 改写本地仓库的远程目标仓库

cd <你的本地仓库路径>/
# 查看远程目标
git remote -v
# 删除远程目标
git remote rm origin
# 或者,你也可以更改原有的远程目标的名字
# git remote rename origin old-origin
git remote -v

# 添加1.1节中新建的远程仓库
git remote add origin [email protected]:<你的GitHub用户名>/<你的仓库名>.git
git remote -v

3 推送所有分支/tag到远程

# 推送所有分支到名为origin的远程目标
git push -u origin --all
# 和 git push --set-upstream origin --all 是一样的
​
# 推送所有tag到名为origin的远程目标
# !! 推送tags仍然失败了,推测是需要切到每一个tag,每一个tag都需要删除大文件的历史;考虑到全量tags的推送并不重要,作为后续的TODO;
git push -u origin --tags
​
# (可选的)你也可以,更改当前的分支名,并单独推送该分支到远程目标的某一分支
# 更改当前分支名为main
git branch -M main
# 把当前分支推送到远程的main分支
git push -u origin main

4 批量改写提交历史

在3节,git push -u origin --all 时,报错;

日志中提示,有提交大于了100MB的限制;

4.1 找到大体积的文件

find . -type f -exec du -h {} + | sort -h | tail -n20

示例输出:

uav@uav-G5-5500:/tmp/**$ find . -type f -exec du -h {} + | sort -h | tail -n20
...
93M ./tests/data/Tunnel.pcap
205M  ./tests/data/highway.pcap
256M  ./.git/objects/pack/pack-c3cfcbe650b543caf1143271c04fa51e377314b5.pack
1019M ./.git/objects/pack/pack-d77ef04279c83d523f00d9b0df8674cae91ae0a2.pack

推测大体积的提交历史大概率是包含了pcap文件;

4.2 删除提交历史中的大体积文件

# 查看本地分支列表;
git branch
# 逐个切换到每个分支,在每个分支都要执行更改提交历史的操作;
# !! 没有找到1次变更所有分支历史的方法,TODO;
git checkout master
git filter-branch -f --index-filter 'git rm --cached --ignore-unmatch *.pcap'
# ... 同样操作其他分支;

控制台的输出,如下:

# ...
Rewrite 431b95ba4b145f70bb13fb4d5dbc11854d4d1283 (799/808) (67 seconds passed, remaining 0 predicted)    rm 'tests/data/16_highway.pcap'
rm 'tests/data/Tunnel.pcap'
rm 'tests/data/64.pcap'
rm 'tests/data/128.pcap'
Rewrite e447e530142024c1048aa3b782e6645238422b76 (799/808) (67 seconds passed, remaining 0 predicted)    rm 'tests/data/16_highway.pcap'
rm 'tests/data/Tunnel.pcap'
rm 'tests/data/64.pcap'
rm 'tests/data/128.pcap'
​
# 提示,历史改写成功;
Ref 'refs/heads/master' was rewritten

需要注意的地方:

# 使用*.pcap进行匹配,如果使用.pcap,会匹配失败,显示分支未修改;
git filter-branch -f --index-filter 'git rm --cached --ignore-unmatch .pcap'
WARNING: git-filter-branch has a glut of gotchas generating mangled history
   rewrites.  Hit Ctrl-C before proceeding to abort, then use an
   alternative filtering tool such as 'git filter-repo'
   (https://github.com/newren/git-filter-repo/) instead.  See the
   filter-branch manual page for more details; to squelch this warning,
   set FILTER_BRANCH_SQUELCH_WARNING=1.
​
Proceeding with filter-branch...
​
Rewrite e447e530142024c1048aa3b782e6645238422b76 (802/808) (67 seconds passed, remaining 0 predicted)     
# 提示分支未修改;
WARNING: Ref 'refs/heads/master' is unchanged

4.3 再次推送

参考3节;

git push -u origin --all

5 使用LFS推送大文件

LFS(Large File Storage)通过把大文件存储放在Git仓库之外,并在Git仓库中保存文件的指针,从而实现对大文件的管理;

如果仍然有大文件的推送需求,可以使用LFS,TODO;

x 参考

一些常用的git命令:

Git命令作用备注
git config -l 列出当前git仓库或全局配置的所有配置项及其值; 仓库级别的配置项存储在仓库的.git/config文件中;全局级别的配置项存储在您用户目录下的.gitconfig文件中;
git pull github main 从名为github的远程仓库的main分支拉取最新的修改,并将其合并到当前所在的本地分支中; 如果存在冲突,需要手动解决冲突后再进行提交;
     

x.1 Git clone 所有分支、tag到本地,然后push到一个新的远程仓库_如何把tag连同主分支一起复制-CSD

x.2 Git 一次性 pull push 所有的分支_git 提交所有的分支-CSDN博客

x.3 Git lfs - “这超出了 GitHub 的文件大小限制 100.00 MB” - 代码日志

x.4 关于 Git 大文件上传这件小事 | 素履独行

x.5 git 撤销修改 - 温故纳新 - 博客园

x.6 彻底解决 git push --set-upstream origin 问题-CSDN博客

x.7 撤销修改 - 廖雪峰的官方网站

x.8 git配置user.name和user.email-CSDN博客

x.9 Free push limit | GitLab

x.10 Account and limit settings | GitLab