Git使用:大體積的歷史commit無法推送到遠端倉庫的解決方案

_bob發表於2024-04-10

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 git@github.com:<你的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

相關文章