# 转换普通文件为 LFS 托管

工蜂系统默认拦截大于 100M 的文件,这些文件必须使用 LFS 才能提交。如果 push 过大的文件(本图示例的为 1M),会出现如下提示: LFS_ERROR

如何使用 LFS,下面分三种情形详细介绍:

# 1. 本地尚未提交过大文件

如果本地未提交过大文件,直接 git lfs track "*.jar"。(跟踪多种后缀:git lfs track "*.png" "*.jar")注意:一定要先 track 再 add、commit。如果没安装过 LFS,请查看安装指南。
LFS_TRACK

再进行 git add 和 git commit 操作。使用 git lfs ls-files 确认一下,是否已经 track LFS 对象。(如果 ls-files 列表为空,说明没 track 上)

LFS_LIST

这个时候能正常 push 了,push 时可以看到 Uploading LFS objects 字样。(如果 LFS 对象没 push 上,可以尝试 git lfs push)
LFS_PUSH

如果 git lfs ls-files 确认大文件都被跟踪了,push 还是被拦截,请参考下面的情形 2.

# 2. 本地已经提交过一个或多个包含大文件的 commit

如果本地已经提交过包含大文件的 commit,如下图:
LFS_LOG

请使用 git reset --mixed 回退到未包含大文件的前一个 commit 点。示例中“add some jars”这个 commit 包含了大文件,所以要回退到上一个 commit,即 a3e40e655bfa8ea3e61796e3f4d8c987e2fa5dcd。 (只提交了一个 commit,可以直接 git reset --mixed HEAD^;如果不清楚哪个 commit 包含大文件,可以 git reset --mixed origin/master,示例中为 master。)

LFS_RESET

注意:最多回退到 origin/master,再往前,push 就会引起冲突了。

如何确定需要跟踪的文件后缀?(windows 环境请用 git 自带的 Git Bash,示例是查找超过 1M 的文件) LFS_FIND

进行 LFS 跟踪:如果查找的大文件后台是.jar,直接 git lfs track "*.jar"。(跟踪多种后缀:git lfs track "*.png" "*.jar")注意:一定要先 track 再 add、commit。如果没安装过 LFS,请查看安装指南。
LFS_TRACK

再进行 git add 和 git commit 操作。使用 git lfs ls-files 确认一下,是否已经 track LFS 对象。(如果 ls-files 列表为空,说明没 track 上)

LFS_LIST

这个时候能正常 push 了,push 时可以看到 Uploading LFS objects 字样。(如果 LFS 对象没 push 上,可以尝试 git lfs push)
LFS_PUSH

# 3. 本地全部历史都需进行 LFS 转换

如果项目是从外部导入的,建议本地全部历史都进行 LFS 转换,转换过程会保留历史,但也会改写历史。 注意:LFS 对象转换会改写历史记录(即 commit sha1 会发生变化),再更新原(github 或 svn)项目时会产生大量冲突。只适用一次迁移的情形,不适用 github 或 svn 和工蜂并行使用。(以后还有更新 github 或 svn,需要重新 clone 一份,再做一次 git lfs migrate)

完整的步骤比较多,这里先介绍大概的流程,方便有心理预期:

  1. 文件分析: LFS_LOG
    以上图的仓库为例,如何找到 commit 历史中有哪些文件可能非文本文件? (必须使用git-lfs/2.7.1 及以上版本,但不要使用 3.0.2 版本,3.0.2 的 git lfs migrate 命令执行性能很差,详见 issue) 可运行命令对仓库进行分析,比如先找出大于1M的文件
    LFS_MIGRATE_INFO

  2. LFS转换 按照上图的分析结果,超过1M的文件有“jar”和“pdf”文件,这些刚好是非代码文件,接下来对这个项目的全部分支的历史记录进行 LFS 对象转换。 LFS_MIGRATE_IMPORT

  3. 推送代码到远端 确保 lfs 对象已跟踪后,推送到远端。

LFS_PUSH_KEEP

以下是详细的、正式的 lfs 转换步骤:

  1. 正式操作时,需要先禁止旧项目提交
  2. 克隆仓库到本地(或者更新代码到最新)
# 假设下文为仓库地址
git clone <http://git.tencent.com/{group}/{repo}.git> test_lfs &&  cd test_lfs
# 或者
cd test_lfs && git fetch origin --all
  1. checkout 全部分支
git branch -r | grep -v '\\->' | while read remote; do git branch --track "${remote#origin/}" "$remote"; done 
  1. 拉取所有lfs文件
git lfs fetch --all
  1. 分析历史文件(以下查找历史记录中大于 2M 的文件文件为例,主要为了找出需要转换的文件类型,如果已经找出,就可以跳过这一步)
git lfs migrate info --above="2 MB" --everything --top 100
  1. 转换历史,约需半小时至 1 小时 假设查找出来的是:*.jar,*.exe,hipcc,ocpa_embedding_writer LFS 是根据文件路径匹配的,hipcc 表示这个目录及子目录都会 track。如果只想 track hipcc,请给完整路径。非二进制的.txt 可以不用 track。
git lfs migrate import --include="*.jar,*.exe,hipcc,ocpa_embedding_writer" --everything
  1. 在本地设置新仓库地址为lfs2
git remote add lfs2 <http://git.tencent.com/{group}/{new_repo}.git>
# 或者
git remote add lfs2 <http://{username}:{password}@git.tencent.com/{group}/{new_repo}.git>
  1. 提前将仓库的文件大小限制设置到合适的值,放开推送限制、保护分支等限制
  • 项目大小设置:https://git.tencent.com/{group}/{new_repo}/-/advanced_settings/repository

  • 项目推送设置:https://git.tencent.com/{group}/{new_repo}/-/advanced_settings/push 文档参考:推送设置

  • 保护分支设置(强推到旧仓库前需将分支去除保护):http://git.tencent.com/{group}/{new_repo}/protected_branches

  1. 分别推送所有分支的lfs文件和裸库到服务端(约需 10 分钟,如果分支太多,可使用脚本逐个推送分支)
# 推送lfs对象
git lfs push lfs2 --all 

# 推送裸库对象:--push-option=skip.verify是仓库管理员权限才可用,此参数会跳过检查
git push lfs2 --all --no-verify --push-option=skip.verify --force
  1. 分别推送所有tag的文件到服务端 (约需 3 分钟)
# 推送lfs对象
git lfs push lfs2 --tags

# 推送裸库对象:--push-option=skip.verify是仓库管理员权限才可用,此参数会跳过检查
git push lfs2 --tags --no-verify --push-option=skip.verify --force
  1. 恢复8. 中临时放开的限制

# 4. 拆分推送仓库与 LFS 对象

当仓库历史太大、文件太多,发生 LFS 无法在指定时间内一次性推完,则需要使用拆分仓库与 LFS 的推送模式。

  1. 前期条件是你本地已经有一个完整的仓库了,并且你的目标remote假设是 lfs2(如没有,可参考上文“历史转换”中的 1~4 步 clone 完整仓库)
  2. 拉取所有lfs文件
git lfs fetch --all
  1. 推送所有分支
git push lfs2 --no-verify --all
  1. 推送所有tag
git push lfs2 --no-verify --tags

到这一步,已经完成 Git 裸库的 push,但是 LFS 对象是没上传的

  1. 确认本地已下载的 lfs 对象数量
find .git/lfs/objects -type f | wc -l 
  1. 并发上传脚本(大量数据上传推荐)

    chmod +x upload_objects.sh
    ./upload_objects.sh
    
    • 默认 concurrency 5 个并发,可以自行修改脚本,由于 git 命令输出的特殊性,并发 push 时 git 命令输出日志可能有缺失
    • 脚本可重复执行,但是会从头开始上传,重复内容实际上不会上传但仍会在效验上耗时
  2. 逐个上传命令(传统按顺序上传)

    find .git/lfs/objects -type f | awk -F '/' '{print $NF}' | while read obj; do git lfs push lfs2 --object-id $obj; done
    
    • 命令会把当前本地所有的 lfs 对象查找出来,并逐个上传,如果希望并发上传,可以使用并发上传脚本
    • 命令可重复执行,但是会从头开始上传,重复内容实际上不会上传但仍会在效验上耗时
lastUpdate: 11/6/2025, 7:20:26 PM