如何禁用Git LFS?

60

我在bitbucket上有一个使用LFS的仓库。使用一段时间后,我决定将仓库移动回我控制的空间。我最初使用LFS的唯一原因是为了有效地将我的仓库大小限制加倍(因为LFS中的文件进入单独的存储桶),但现在我正在移动它,我不再需要这样做。

我需要一种方法来遍历整个git历史记录,删除所有git LFS的工作痕迹(以便所有文件都以正常方式提交)。完成后,我打算强制推送到新仓库。

我已经做了相当多的搜索,并找到了建议的解决方案,但我不知道如何实现或运行它们,因为它们是高级别的。

如何告别git LFS?


这就像 https://github.com/git-lfs/git-lfs/issues/326#issuecomment-104881826 那样的东西,我想是吧? - VonC
让我们在聊天中继续这个讨论 - Shadow
相关链接:https://stackoverflow.com/questions/35011366/move-git-lfs-tracked-files-under-regular-git - undefined
5个回答

57

仅更新当前提交

如果您想离开Git LFS,但不太担心修复整个Git历史记录,可以执行以下操作:

git lfs uninstall
touch **/*
git commit -a

这将卸载LFS支持,触及每个单独的文件(以便git认为它们已更改),然后提交所有更改。如果你想要更具体的选择(例如,**/*.png),请注意使用 ** 需要启用扩展通配符支持(在bash上使用 shopt-s globstar )。

更新整个历史记录

对我来说这行得通 - 但它会抛出大量错误(我认为每次提交时文件未添加到LFS中都会出现错误),并且需要很长时间(大约每个提交需要2-3秒)。

git lfs uninstall
git filter-branch -f --prune-empty --tree-filter '
  git lfs checkout
  git lfs ls-files | cut -d " " -f 3 | xargs touch
  git rm -f .gitattributes
  git lfs ls-files | cut -d " " -f 3 | git add
' --tag-name-filter cat -- --all

它卸载git LFS支持(理论上防止LFS干扰索引),然后对于每个提交,确保正确检出LFS文件,然后触摸所有这些文件(以便git意识到它们已更改),删除在.gitattributes中找到的LFS设置,以便在克隆时不再尝试使用LFS,然后将真实文件添加到索引中。

完成以上操作后,您需要进行强制推送。自然地,这会将在您的repo上工作的任何其他人都置于分离头状态 - 因此,在代码冻结期间执行此操作是明智的。之后,最简单的方法可能是让每个人进行全新的克隆。


我在Windows上使用git for windows时遇到了以下错误: 'cut' 不是内部或外部命令,也不是可运行的程序或批处理文件。 - BikerDude
1
@BikerDude 是的,cut是一个Linux命令。你可以使用类似cygwin的东西。 - Shadow

47

git lfs migrate export

根据 git lfs migrate help 的说明:

导出(Export)

导出 模式将 Git LFS 历史记录中存在的指针文件移出 Git LFS,并将它们转换为相应的对象文件。

工作流程示例

  1. 使用 git lfs ls-files 确认您实际上有 LFS 文件。
  2. 从存储库中的所有 .gitattributes 文件中删除所有 filter=lfs 行。请注意,.gitattributes 可以存在于任何位置,因此请确保找到所有文件,否则可能会在以后的迁移过程中引起问题。
  3. 提交您对 .gitattributes 所做的任何更改。
  4. 确保使用 git status 没有未提交的更改。
  5. 运行迁移命令:git lfs migrate export --everything --include .
  6. 运行 git status 确保没有未提交的更改。如果您遗留了带有 filter=lfs.gitattributes,现在可能会错误地显示更改。
  7. 使用 git lfs ls-files 确认所有先前列出的 LFS 文件现在已不再存在。
  8. 检查文件(例如,打开以前的 LFS 文件以确保它们不会损坏),并运行构建以确保一切正常。

提示

  • 在区分大小写的文件系统上运行,以防止文件系统冲突(例如 ./LICENSE 和 ./License)。
  • 从所有的.gitattributes文件中移除filter=lfs
  • 您还可以删除.git/hooks目录中的LFS残留物:pre-commit、post-commit、post-checkout、post-merge。
  • 使用$GIT_TRACE=1,不应该出现任何...trace git-lfs: filepathfilter: accepting...的迹象。

3
您可能还想删除.git/hooks目录中的LFS遗留物:pre-commitpost-commitpost-checkoutpost-merge。使用$GIT_TRACE=1,不应该出现...trace git-lfs: filepathfilter: accepting...的迹象。 - pizycki
@pizycki 谢谢。我已将您的评论添加到答案中。 - Doug Richardson
2
这太棒了。它运行得非常好,而实际的git lfs文档中提供的简单指令......则不是那么好。你能解释一下为什么在--include后面要加一个点吗?我一直以为这必须是某个表达式,但当我使用基本上与我的.gitattributes文件中相同的内容时,它根本无法工作。 - jkratz
2
如果(例如在Github桌面版上)它说您的本地与远程不同,所有提交都是如此,那么您应该怎么办?我应该将导出的存储库视为全新的吗? - Tom Charles Zhang
1
完成操作并推送后,我收到了以下提示:提示:更新被拒绝,因为您当前分支的尖端落后于远程分支。在再次推送之前,请合并远程更改(例如'git pull...')。有关详细信息,请参见“ git push --help”中的“快速向前”提示。当我尝试拉取时,我得到了致命错误:拒绝合并不相关的历史记录。不确定我哪里做错了。 - Pro Q
显示剩余4条评论

3

针对特定文件

  1. .gitattributes中删除文件/模式
  2. 进入文件目录并运行touch myfile.bin
  3. 提交和推送更改
注:Original Answer翻译成"最初的回答"

1

我写了一个 脚本,可以完全从 Git 存储库中删除 LFS。警告- 它会重写你的历史记录。

#!/bin/zsh

git lfs install
git lfs fetch --all
git lfs checkout

lfs_dirs=()

echo "finding lfs files"
for lfs_file in $(git lfs ls-files | sed -r 's/^.{13}//'); do lfs_dirs+=($(dirname "$lfs_file")); done;

echo "found all lfs files"

unique_dirs=()
for unique_dir in ${(u)lfs_dirs}; do unique_dirs+=("$unique_dir/*"); done;

count=${#unique_dirs[@]}

if (($count == 0))
then
echo "No lfs dirs"
exit 0
fi

echo "There are $count unique lfs dirs"

printf -v migrate_paths ',%s' "${unique_dirs[@]}"
migrate_paths=${migrate_paths:1}

echo "performing: git lfs migrate export --include='$migrate_paths' --yes --verbose --everything"
git lfs migrate export --include="$migrate_paths" --yes --verbose --everything
git lfs uninstall

感谢您的回复。根据stackoverflow的指南,仅提供链接的答案是不被鼓励的,因为链接可能会失效。您是否考虑将您的脚本复制到您的答案中? - Shadow

1
根据Shadow的回答,我稍微修改了整个历史更新。 对于那些不想保留LFS文件的人(在我的情况下,我不想保留它们,因为它们会很大)。
使用:
GIT_LFS_SKIP_SMUDGE=1 git filter-branch -f --prune-empty --tree-filter '
  git lfs checkout
  git lfs ls-files | cut -d " " -f 3 | xargs rm -f
  git rm -f --ignore-unmatch .gitattributes
' --tag-name-filter cat -- --all

此外,当提交中没有.gitattributes时,它也不会失败,在我的情况下,并非所有提交都是如此。此外,该仓库没有存储原始的LFS文件,因此使用GIT_LFS_SKIP_SMUDGE=1。这样,仓库就不包括任何LFS引用和文件,这使得克隆仓库更快、更轻便——这是我的目标。虽然测试使用了大文件,但由于代码已经大大改进,运行那些旧测试是无关紧要的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接