Git(LFS):什么是锁定支持?我应该启用它吗?

115

"新" Git 评论:

今天我第一次看到了来自Git的以下评论(至少是我第一次看到它):

Mikes-Mac$ git push
Locking support detected on remote "origin". Consider enabling it with:
  $ git config 'lfs.https://github.com/<my_repo>.git/info/lfs.locksverify' true
Everything up-to-date
Mikes-Mac$ 

这个 锁定支持 是什么?是针对LFS(大文件存储)的一种互斥锁吗? 如果是,那么它不是让git工作的绝对必要条件吗?最起码,否则如何确立日志历史的“排序”?更糟糕的情况下,我不能同时写入二进制文件导致文件损坏吗?

我的操作

我最近没有对此存储库进行任何不同的操作,与我建立的其他LFS存储库相比,我也没有进行任何不同的操作。

因此,我认为这是向“世界”提供新功能的新评论。

没有明显的文档

然而,既没有谷歌搜索,也没有快速浏览他们的文档能够解释这一点。因此,我不得不思考:

  • 这个锁是什么?
    • 它是互斥锁吗?如果是,那么我的代码库怎么能没有它而正常工作呢?
    • 这只针对LFS吗?它与普通的git文件锁定有何不同?
  • 添加LFS锁定支持的优缺点是什么?

这个问题是否应该应用互斥标签?虽然问题提到了互斥,但似乎并不太合适。 - huw
2个回答

112

Git LFS的锁定支持在这里https://github.com/git-lfs/git-lfs/wiki/File-Locking有详细说明。

Git LFS v2.0.0包括文件锁定的早期版本。 文件锁定允许开发人员锁定他们正在更新的文件,以防止其他用户同时更新它们。 在Git存储库中进行并发编辑将导致合并冲突,对于大型二进制文件非常难以解决。

一旦.gitattributes中的文件模式可以锁定,Git LFS将自动将它们设置为本地文件系统上的只读。 这可以防止用户在未先锁定文件的情况下意外编辑文件。

在推送时,Git LFS将验证您是否修改了另一个用户锁定的文件。由于文件锁定是早期版本,并且很少有LFS服务器实现该API,因此如果无法验证锁定的文件,则Git LFS不会停止推送。 您会看到这样的消息:

$ git lfs push origin master --all
Remote "origin" does not support the LFS locking API. Consider disabling it with:
  $ git config 'lfs.http://git-server.com/user/test.locksverify' false
Git LFS: (0 of 0 files, 7 skipped) 0 B / 0 B, 879.11 KB skipped
 
$ git lfs push origin master --all
Locking support detected on remote "origin". Consider enabling it with:
  $ git config 'lfs.http://git-server.com/user/repo.locksverify' true
Git LFS: (0 of 0 files, 7 skipped) 0 B / 0 B, 879.11 KB skipped
因此,在某种意义上,您可以将其视为咨询互斥锁,因为:

  • 如果您不“锁定”该文件,则无法编辑它
  • 一旦使用 git lfs lock “锁定”文件,您可以编辑它,并且仓库服务器将识别您正在编辑它
  • 服务器不会接受其他人的提交,这些提交更改了您锁定的文件。

它主要添加是为了帮助团队管理大文件,以防止合并冲突。


谢谢,Kenny!我也觉得应该是这样,但是找不到相关的文档! - Mike Williamson
3
你好,执行完 git config 'lfs.http://git-server.com/user/repo.locksverify' true 后,如何恢复到正常状态?只需要执行 git push -f origin 99157a1b1b27820dfba48c5e9d3c4f075670670c:master 就可以回到正常状态了。请注意,不要改变原有的意思。 - Peter Krauss
2
听起来他们应该在编辑文件之前使用“解锁”术语。 - Gandalf Saxe
10
从程序员的角度来看,这是有道理的,因为当你需要访问由互斥锁保护的变量时,你需要“锁定”(获取)该互斥锁。 - kennytm
@PeterKrauss 我不确定,这是一个好问题,但我认为应该将其作为自己的问题提出,因为它与此问题没有密切关联。 - Mike Williamson
2
@PeterKrauss 我猜你只需执行 git config 'lfs.http://git-server.com/user/repo.locksverify' false,对吗?“正常状态”是什么意思?它只能意味着禁用lockverify,对吧? - Sorin Postelnicu

16
被接受的答案没有回答问题的一个次要方面,具体而言:

如果是这样,那么将任何内容放入git中工作绝对必不可少吗?(至少,否则如何建立日志历史的“排序”?更糟糕的情况是,同时写入的二进制文件可能会损坏吗?)

所以我将仅回答这一部分。

在git中不存在同时写入,并且历史记录的排序是答案的一部分!

当您将提交推送到远程git存储库时,它会验证您正在推送的提交是否是该分支的头部之一。

如果不是,则提交将被拒绝。

如果是,则git将发送一组blob(文件数据)、树对象和提交。

然后更新分支头指向您的新提交。

除非头已更改,否则它将再次拒绝您的新提交。

如果被拒绝,您必须从远程存储库中拉取更新的更改,然后将其与您的更改合并,或者在新更改上重新定义您的更改(例如:git pull -r)。

无论哪种方式,都会创建一个新的本地提交,它是存储库的一个后代。

然后您可以将此新提交推送到存储库。 这种情况下,这个新的提交可能会被拒绝,迫使您重复这个过程。

文件永远不会被覆盖。对于 Git 来说,“mybigfile.mpg” 文件只是一个带有唯一 ID 的 blob,该 ID 基于文件内容的 SHA-256 哈希计算得出。如果更改文件,则会生成一个新的 blob,并分配一个新的 ID。

文件名只是树对象中的一个条目,其 ID 也基于其内容的哈希值。

如果您重命名文件(或添加、删除等),那么它将成为一种新的树对象,并具有自己的 ID。

因为这些是历史记录的一部分(提交包括要提交的顶级树的 ID,以及其父项的 ID),所以这些对象(blobs、trees、commits、signed tags)只会添加到存储库中,而不会修改。

Git 历史记录总是有序的,因为它是一个链表,其中链接指向父项。初始提交没有父项,合并提交至少有两个父项,其他情况下只有一个父项。

它们不需要任何显式锁定,因为 Git 在进行更改之前会检查冲突。

只有包含分支最新提交 ID 的文件需要锁定,而且仅在检查更改并更新它之间的短暂时刻需要锁定它。

Git-lfs 中的锁定解决了一个非常不同的问题。二进制资产通常无法合并,并且通常涉及大量的工作来更改它们。特别是对于大型资产而言。

如果两个开发者开始更改同一个文件,那么其中一组更改将被丢弃,然后以另一个更改为基础重新创建。git-lfs锁定可以防止这种情况意外发生。如果你遇到了锁定,你可以等待到以后再进行更改,或者去找持有该锁的人交谈。他们可以进行所请求的更改,或者释放锁并允许你在他们迄今为止的更改之上进行更改。然后当你完成后,你可以推送你的更改并释放锁,让他们继续进行他们的更改。因此,它允许特定文件的更改(整个开发过程,而不是文件编写)进行序列化,而不是用于文本源文件的并行-合并范例。

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