文章

如何清理 .git 文件夹来减小 github 仓库大小

本文介绍了如何清理github本地缓存文件夹来减小 github 仓库大小。


1. github

1.1. git 命令

1.2. github 桌面

1.3. .git 文件夹

git 是增量更新模式,所有改动都会保存在 .git 隐藏文件夹内。

.git 文件夹清理不会把仓库中已有的文件夹和里面的内容删除,会保留最新的一次提交,并且默认最近的一次提交是干净无误的提交。

2. .git 文件夹清理

2.1. Linux 环境命令行清理

需要 Linux 环境。

  • 检查仓库是否存在未提交的更改

    如果仓库存在未提交的更改,会在后续操作中提示提示 Cannot rewrite branches: You have unstaged changes. 表明尝试重写分支时,有一些未暂存的更改。这意味着你在Git版本控制中,工作目录或者暂存区有一些更改还没有被添加到暂存区。因此,Git不能进行重写操作,因为这可能会导致你丢失这些未提交的更改。

    可以通过以下命令检查本地仓库与云端仓库的差异,定位未提交的更改

    1
    
      git diff
    

    执行命令后按 q 退出。

    可以通过以下命令提交更改

    1
    2
    
      git add . # 将所有文件添加到暂存区
      git commit -m "Your commit message" # 提交你的更改
    

    或丢弃更改

    1
    
      git checkout -- . # 丢弃工作目录中的所有更改
    
  • 查看占用仓库大小最大的文件

    bash 下执行以下命令

    1
    
      git rev-list --objects --all | grep -f <(git verify-pack -v .git/objects/pack/*.idx| sort -k 3 -n | cut -f 1 -d " " | tail -N)
    

    举例

    1
    
      git rev-list --objects --all | grep -f <(git verify-pack -v .git/objects/pack/pack-3a121311b111a111c11111x1111f111111111111.idx| sort -k 3 -n | cut -f 1 -d " " | tail -10)
    

    将在控制台输出类似如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
      344ee5dcae1xxxxx3d80daa8714ed7d16b21dxxx src/vehicles/cls_Spacecraft.cpp
      98eecfdf58a0c0dc33bbfae46bxxxe5d837d5xxx src/vehicles/cls_Spacecraft_Docker.cpp
      a8a5bca95b08084xxxx7160c4c5d98631f1cdxxx config/usrSpacecraft.json
      e1cf4bf431f82d788fcaaaaac4ecca05503248xx winDSSimulator.exe
      8932ce1bca5ba3c1ae39cxxxx054d14f15ad8xxx winDSSimulator.exe
      17965fde8b22564a73addxxx10e77a815ef89xxx src/SimDynamics.cpp
      33e7714xxxxaa033326648609f614837f49d2xxx winDSSimulator.exe
      f3c41a010b75743fbb111161d84ebcc57ae85xxx winDSSimulator.exe
      058da4754e97e910a72xxxxxxxa4d6f6513f5xxx winDSSimulator.exe
      351e85631xxxx609d92523a67ca5d1e3e7f47xxx src/class/clsEarthDynamics.cpp
    
  • 从历史中移除大文件

    使用以下命令检查仓库中的文件个数(在执行 filter-branch 清理命令后个数会减少)

    1
    
      git count-objects -v
    

    对于每次提交操作,filter-branch 命令都会使用给定的过滤器重写仓库的历史。

    以下命令删除历史中存在的图像(例如 *.exe*.json*.jpg*.png*.gif),这些文件类型是常见的无需跟踪和回退修改的文件。

    1
    
      git filter-branch -f --index-filter 'git rm --cached --ignore-unmatch "config/**.json" "**.exe" "**.jpg" "**.png" "**.gif"' --prune-empty --tag-name-filter cat -- --all
    

    需要注意以下几点:

    • git rm --cached:这个命令会从Git的索引中移除指定的文件,而不是从工作目录中移除。这意味着你的工作目录中仍然会保留这些文件的副本。如果你希望从工作目录和索引中都删除这些文件,你应该使用git rm –cached -r –ignore-unmatch…这样的命令。
    • 文件模式:你使用的文件模式,例如 "config/**.jpg""**.png" 等,是用双引号包围的。这通常是可以正常工作的,但是如果你在文件名中有一些特殊字符或者空格,可能会导致问题。你需要确定这些模式正确匹配了你想要删除的文件。
    • --prune-empty:这个选项会导致Git丢弃那些没有任何修改的提交。因为你的操作可能导致一些提交没有任何修改,所以这个选项可能会被用到。
    • --tag-name-filter cat:这个选项会重命名所有的标签。cat命令会直接输出标签名,这意味着你的标签名字可能会改变。你需要考虑这是否是你想要的行为。
    • --all:这个选项会让Git处理所有的引用,包括所有分支和标签。如果你只想处理特定的分支或标签,你可以去掉这个选项。
  • 清理仓库

    清楚旧提交中不需要的日志和文件。

    1
    2
    3
    
      rm -Rf .git/refs/original
      rm -Rf .git/logs/
      git gc --aggressive --prune=now
    

    将清理后的本地仓库更新到云端。

    1
    2
    
      git push origin --force --all
      git push origin --force --tags
    

2.2. 跨平台 BFG 工具清理

https://rtyley.github.io/bfg-repo-cleaner/ BFG Repo-Cleaner 是一个原生 git-filter-branch 的更加简单快速的替代,基于 JDK 8+

首先前往官网安装 JDK(https://www.oracle.com/java/technologies/downloads/)。

然后下载 BFG(https://rtyley.github.io/bfg-repo-cleaner/)。

一切准备就绪后,进入清理环节

  • 克隆一个全新的 repo 裸仓库到本地(通过 --mirror 参数)

    1
    
      git clone --mirror https://github.com/[user_name]/[repo_name].git
    

    【注意】,基于https的命令行克隆需要授权,若安装 Git 时候没有选择附带 Git Credential Manager,需要手动独立安装(https://github.com/git-ecosystem/git-credential-manager/releases),否则会失败,因为 Github 在 2021 年移除了通过账户名和密码授权的方式。 裸仓库:https://git-scm.com/docs/gitglossary.html#def_bare_repository, 裸存储库通常是一个适当命名的目录,后缀为.git,没有任何受修订控制的文件的本地签出副本。也就是说,所有通常会出现在隐藏的.Git子目录中的Git管理和控制文件都直接出现在repository.Git目录中,而不包含其他文件。

  • 将下载好的 bfg-1.14.0.jar 放置在克隆裸仓库 [repo_name].git 相同的路径,如:
    1
    2
    
    ./mirror/[repo_name].git
    ./mirror/bfg-1.14.0.jar
    
  • 根据文件大小批量清除历史记录

    例:清理大小超过 1M 的二进制文件

    1
    
      java -jar bfg-1.14.0.jar --strip-blobs-bigger-than 1M [repo_name].git
    
  • 根据指定文件名清除历史记录

    例:清理所有后缀为 .zip 的文件

    1
    
      java -jar bfg-1.14.0.jar --delete-files *.zip [repo_name].git
    
  • 根据文件夹清除历史记录

    例:清理文件夹 build

    1
    
      java -jar bfg-1.14.0.jar --delete-folders build [repo_name].git
    
  • 进入 .git 目录,执行垃圾回收

    1
    2
    
      cd [your_repo].git
      git reflog expire --expire=now --all && git gc --prune=now --aggressive
    
  • 最后,执行提交操作

    1
    
    git push
    
  • 【注意】 最后的最后,必须移除所有该仓库的本地同步内容重新同步,包括自己和他人已经同步过的该仓库。因为旧的同步仓库包含未被清理过的所有脏记录,如果某个本地同步仓库在使用 BFG 清理后进行提交,会将重新造成记录污染。因此需要删除本地同步仓库后重新同步抓取,保证清理过程不会因为其它该仓库的历史本地信息因下一次提交而被污染。当然,不要忘记,重新同步到本地后,试试 repo 能否编译通过 0.0。

清理完毕,可以删除 mirror/[your_repo].git 文件夹。

3. 参考文献

[1] Junyong Lee. How to clean up .git folder for reducing repository size

本文由作者按照 CC BY 4.0 进行授权