问题背景#
我已经有了一个 .gitattributes 文件,我希望将仓库中的大文件全部重写到 lfs 上
.gitattributes 文件样例如下:
1
2
3
4
| assets/geolite2-asn-ipv4.mmdb filter=lfs diff=lfs merge=lfs -text
assets/geolite2-asn-ipv6.mmdb filter=lfs diff=lfs merge=lfs -text
assets/qqwry.dat filter=lfs diff=lfs merge=lfs -text
assets/zxipv6wry.db filter=lfs diff=lfs merge=lfs -text
|
最终解决方案(TLDR)#
1
2
3
4
5
6
7
| # 首先安装 git-filter-repo
uv tool install git-filter-repo
# 然后将 .gitattributes 添加到每个提交
HASH=$(git hash-object -w "$(pwd)/.gitattributes")
git filter-repo --force --commit-callback "commit.file_changes.append(FileChange(b'M', b'.gitattributes', b'${HASH}', b'100644'))"
# 然后使用 --fixup 根据 .gitattributes 文件转换为 lfs 格式
git lfs migrate import --everything --fixup
|
注意:该方案仅适用于 gitattributes 文件中不包含 exclude 规则的情况
解决过程#
git lfs migrate import 有一个 --fixup 参数
根据官方的解释:
1
2
3
4
| --fixup Infer --include and --exclude filters on a per-commit basis based on the .gitattributes files
in a repository. In practice, this option imports any filepaths which should be tracked by Git LFS
according to the repository´s .gitattributes file(s), but aren´t already pointers. This option is
incompatible with explicitly given --include, --exclude filters.
|
似乎看起来是我们想要的作用,但是我使用后发现并没有重写,原因在这:是否可以使用 lfs migrate import --fixup 将整个仓库追溯性地转换为 LFS? · 问题 #3543 · git-lfs/git-lfs — Is it possible to use lfs migrate import –fixup to retroactively convert an entire repository to LFS? · Issue #3543 · git-lfs/git-lfs
–fixup 工作原理是使仓库在每个历史节点上都与其 .gitattributes 文件保持一致。由于你是在历史节点上的最新节点添加 .gitattributes 文件,因此 git lfs migrate –fixup 大部分时间都不起作用。
我认为你可以做两件事来代替:
- 你可以不使用
--fixup ,而是明确指定 --include 和 --exclude 参数,让 Git LFS 为你创建 ` .gitattributes 文件。你提到你不想使用这个选项,但实际上应该没问题:Git LFS 会修改你的 `.gitattributes` 文件,但不会进行冗余修改(例如,如果我们想要添加的条目已经存在,那么 Git LFS 将不会执行任何操作)。 - 或者,您可以使用 git rebase 将引入 .gitattributes 的提交提前到历史记录中, 然后运行 git lfs migrate –import –everything 。由于您引入的 .gitattributes 更改会更早出现,因此 –fixup 将转换您想要的文件。
既然上面的不起作用,那就只能使用 awk + xargs 来实现了
1
| cat .gitattributes | grep 'filter=lfs diff=lfs merge=lfs' | awk '{print($1)}' | xargs -I{} git lfs migrate import --include="{}" --everything
|
但是他有个问题,不会迁移 tag
所以参考如下链接,给出一个最终方案
1
2
3
4
5
6
7
| # 首先安装 git-filter-repo
uv tool install git-filter-repo
# 然后将 .gitattributes 添加到每个提交
HASH=$(git hash-object -w "$(pwd)/.gitattributes")
git filter-repo --force --commit-callback "commit.file_changes.append(FileChange(b'M', b'.gitattributes', b'${HASH}', b'100644'))"
# 然后使用 --fixup 根据 .gitattributes 文件转换为 lfs 格式
git lfs migrate import --everything --fixup
|