使用 Git LFS 上传大文件到 GitHub 中

· 2394字 · 5分钟 · 黄国政

前言 #

搭建网页最便捷的一个方式是使用 GitHub 的 Pages 页面进行部署。

一般来说,在本地路径建立一个包含 docs 文件夹的父文件夹,其中,docs 文件夹内必须包含 index.html 文件,之后将该父文件夹推送至对应的 GitHub 远程仓库中,并在 Pages 页面中将 Branch 处调整为 main/docs,GitHub 即可部署形成网页,默认网址为 https://用户名.github.io/仓库名

这种方式好在便捷,但局限在于没有科学上网则很难打开网页。

最近和老师尝试做一个结合 Copilot 进行数据分析或编程的实战项目,我本打算以 Python 为工具,但发现最新版的 Rstudio 已经接入 Copilot,最后便还是转向相对更熟悉的 R。

折腾了两三天,考虑到和老师交流、获取反馈和检查思路的重要性,我将 R Markdown 文件输出为 Html 格式并部署成网页(https://residualsun1.github.io/Internet-Loneliness/),预备先给老师看过一遍再继续写作。但在上传的文件中,dta 数据文件大小超出了 Git 上传的限制,成为此次部署网页唯一的难题。

由此,本期博文的主题无关网页内容,而是如何使用 Git 将大文件上传到 GitHub

方案 #

第一步:确定文件夹 #

说明

在实际操作中,我在最后才意识到这一步应该放在第一位。
因为在初次操作时,我竟在 `docs` 文件夹上通过 Git 与 GitHub 进行远程关联,这样上传到 GitHub 中 `Internet-Loneliness` 仓库的文件是 `docs` 内的文件,而 Pages 页面无法对此进行部署,必须直接对包含这些文件的 `docs` 文件夹进行部署。
换句话说,问题的根源在于本地文件夹(`Internet-Loneliness`)的根目录设置错误,导致 `docs` 文件夹内的内容被直接推送到了 GitHub 仓库的根目录(`Internet-Loneliness`),而非作为子目录存在。 `docs` 文件夹作为网站源, GitHub Pages 才可以正确识别。

在我的电脑上,项目的本地文件夹路径位于 D:\Tool\project,我在该路径下新建了一个名为 Internet-Loneliness 的文件夹,并在该文件夹中进一步建立一个名为 docs 的文件夹——这个文件夹用于存放所有的相关文件,包括 R Markdown 文件、相关 css 文件、数据集文件等(其中,R Markdown 文件渲染后输出的 html 文件必须命名为 index.html

之后在本地的 Internet-Loneliness 文件夹点击鼠标右键,选择 Git Bash Here,将该文件夹与 GitHub 中建立好的 Internet-Loneliness 仓库进行关联,将整个 docs 文件夹推送到 GitHub 中的 Internet-Loneliness 仓库中。

Internet-Loneliness 文件夹内容:

D:\Tool\project\Internet-Loneliness\

├── .git\

├── docs\

│   ├── index.html

│   ├── index.Rmd

│   ├── index.Rproj

│   ├── .Rproj.user

│   ├── Data\

│   ├── index_cache\

│   ├── index_files\

│   └── Static\

第二步:安装 Git LFS #

在我的项目文件夹中,有一份来自 CFPS2022 的数据文件达 265MB,已经超出了 Git 上传文件大小的限制(如下所示),因此必须使用 Git Large File Storage (Git LFS) 对大文件进行管理。

remote: error: Trace: d7daeac76f24abd94e9737a6c10d1833897b19338bdfb8fa20c9c62faba5eb0e
remote: error: See https://gh.io/lfs for more information.
remote: error: File Data/cfps2022famconf_202410.dta is 110.22 MB; this exceeds GitHub's file size limit of 100.00 MB
remote: error: File Data/cfps2022person_202410.dta is 265.76 MB; this exceeds GitHub's file size limit of 100.00 MB
remote: error: GH001: Large files detected. You may want to try Git Large File Storage - https://git-lfs.github.com.
To https://github.com/residualsun1/Internet-Loneliness.git
 ! [remote rejected] main -> main (pre-receive hook declined)
error: failed to push some refs to 'https://github.com/residualsun1/Internet-Loneliness.git'

首先到官网下载 Git LFS,然后安装。安装过程中,我收到了如下提示:

An executable Git program was found in an unexpected location
outside of Program Files:
"D:\Tool\Git\Git\cmd\git.exe"
If this looks dubious, Git LFS should not be registered using it.

Do you want to register Git LFS using this Git program?

遇事不决,就 Chat 一下,或者 Deep 一下。

这个对话框是在告诉你:Git LFS 的安装程序在你的系统上找到了一个 git.exe,但它并不在默认的 C:\Program Files\Git\... 位置,而是在你自己安装到 D:\Tool\Git\Git\cmd\git.exe。它担心这可能是个「可疑路径」,所以才来让你确认到底要不要把这个 Git 注册给 LFS 用。

如果你确认自己就是在 D:\Tool\Git\Git\ 下安装了 Git,那就直接点击 Yes(或 “是”),让 Git LFS 使用这个 git.exe。这样后续:

git lfs install

就会把钩子(hooks)和配置写到这个 Git 安装里,所有 LFS 操作都会走这套 Git。

我认为,出现提示的原因是默认情况下 Git 会被安装到 C 盘,但用户为保持 C 盘空间充足,往往会将包括 Git LFS 在内的多数软件安装在 D 盘,只要根据提示确认自己的安装情况再进行选择即可。

第三步:使用 Git LFS 上传大文件 #

安装完成后,在本地文件夹 Internet-Loneliness 打开 Git Bash,首先在本地文件夹和 GitHub 之间建立关联。 [1]

[1] 详见《使用Git将本地文件上传至GitHub》。特别注意路径分支,现在一般为 main,更改后在 Git Bash 界面显示为 /d/Project/Internet-Loneliness (main)。 

之后便正式启用 Git LFS 上传大文件。 [2]

[2] 下列代码块内的内容,$ 后的内容为运行代码,没有跟随 $ 的内容为代码运行后反馈的结果。 

安装并启用 Git LFS

$ git lfs install
Updated Git hooks.
Git LFS initialized.

追踪 docs/Data 下所有文件

$ git lfs track "docs/Data/*"
Tracking "docs/Data/*"
$ git add .gitattributes
$ git commit -m "chore: initialize Git LFS tracking"
[main af6cde3] chore: initialize Git LFS tracking
 1 file changed, 1 insertion(+)
$ git remote add origin https://github.com/residualsun1/Internet-Loneliness.git
error: remote origin already exists.
$ git add .
$ git commit -m "feat: add project files with LFS support"
[main 29a5858] feat: add project files with LFS support
 1 file changed, 0 insertions(+), 0 deletions(-)

先单独推送 LFS 大文件。

$ git lfs push --all origin main
Uploading LFS objects: 100% (1/1), 279 MB | 778 KB/s, done.

可以利用下面这段代码检查大文件是否已经收到 LFS 管理。

$ git lfs ls-files

如果成功,应该会显示类似 8607a53a2f * docs/Data/cfps2022person_202410.dta 的信息。

再推送常规文件。

$ git push -u origin main
Uploading LFS objects: 100% (1/1), 279 MB | 0 B/s, done.
Enumerating objects: 132, done.
Counting objects: 100% (132/132), done.
Delta compression using up to 16 threads
Compressing objects: 100% (121/121), done.
Writing objects: 100% (132/132), 23.14 MiB | 7.68 MiB/s, done.
Total 132 (delta 9), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (9/9), done.
remote: error: Trace: 9d19f90ef8d2c127644ce8f8610c00e14b581c75ecaab525335920b240aea674
remote: error: See https://gh.io/lfs for more information.
remote: error: File docs/Data/cfps2022person_202410.dta is 265.76 MB; this exceeds GitHub's file size limit of 100.00 MB
remote: error: GH001: Large files detected. You may want to try Git Large File Storage - https://git-lfs.github.com.
To https://github.com/residualsun1/Internet-Loneliness.git
 ! [remote rejected] main -> main (pre-receive hook declined)
error: failed to push some refs to 'https://github.com/residualsun1/Internet-Loneliness.git'

此时可能会发现,常规推送仍然显示大文件超出上传限制(应当是我早期操作不当所致)。根据 Deepseek 的说法,原因是大文件在 Git 的历史提交中仍存在未被 LFS 管理的版本。GitHub 会扫描所有历史记录,若发现任何提交包含大文件(即使后来被 LFS 管理),也会拒绝推送。

解决方案是彻底重写 Git 历史,将大文件完全迁移到 LFS 管理中,覆盖所有提交记录。

# 指定需迁移的大文件路径(示例为 docs/Data/cfps2022person_202410.dta)
$ git lfs migrate import --include="docs/Data/cfps2022person_202410.dta" --everything
migrate: Sorting commits: ..., done.
migrate: Rewriting commits: 100% (5/5), done.
  main  29a58588b8ade9b1dcddd09dcf532b3f0fbd373e -> 4e8a0f529b13954d8f4455b00a81fd7a3a665cfc
migrate: Updating refs: ..., done.
migrate: checkout: ..., done.

最后再强制推送所有内容到远程仓库。

$ git push --force origin main
Uploading LFS objects: 100% (1/1), 279 MB | 0 B/s, done.
Enumerating objects: 128, done.
Counting objects: 100% (128/128), done.
Delta compression using up to 16 threads
Compressing objects: 100% (117/117), done.
Writing objects: 100% (128/128), 12.65 MiB | 22.10 MiB/s, done.
Total 128 (delta 10), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (10/10), done.
To https://github.com/residualsun1/Internet-Loneliness.git
 * [new branch]      main -> main

最后在 GitHub 仓库中检查文件即可。