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

返回文章页面“新”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$

这是什么 Locking support?这是某种用于 LFS (大文件存储)的 互斥锁互斥锁吗?如果是这样,是不是绝对有必要让任何东西在 Git 上工作?(至少,如何建立日志历史的“顺序”?更糟糕的情况是,二进制文件不能被同步写操作破坏吗?)

我的行动

我最近没有对这个存储库做什么不同的事情,也没有对这个存储库做什么与我用 LFS 建立的其他存储库不同的事情。

因此,我假设这是一个新的评论被提供给“世界”,让我们知道新的功能。

没有明显的文档

然而,无论是谷歌搜索还是 快点搜索都没有通过他们的文档让我解释这一点。所以我在想:

  • 这是什么锁?
    • 它是互斥的吗? 如果是这样,我的回购甚至没有它的功能?
    • 这仅限于 LFS 吗? 它与普通的 git 文件锁有什么不同?
  • 为 LFS 添加锁定支持的利弊是什么?
70953 次浏览

Locking support of Git LFS is documented here https://github.com/git-lfs/git-lfs/wiki/File-Locking.

Git LFS v2.0.0 includes an early release of File Locking. File Locking lets developers lock files they are updating to prevent other users from updating them at the same time. Concurrent edits in Git repositories will lead to merge conflicts, which are very difficult to resolve in large binary files.

Once file patterns in .gitattributes are lockable, Git LFS will make them readonly on the local file system automatically. This prevents users from accidentally editing a file without locking it first.

Git LFS will verify that you're not modifying a file locked by another user when pushing. Since File Locking is an early release, and few LFS servers implement the API, Git LFS won't halt your push if it cannot verify locked files. You'll see a message like this:

$ 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

So in some sense you may consider it an advisory mutex, because:

  • If you don't "lock" the file, you can't edit it
  • Once you "lock" the file with git lfs lock, you can edit it, and the repository server will recognize that you are editing it
  • The server will not accept commits from other people that change the files you have locked.

It is mainly added to help team managing large files to prevent merge conflicts.

The accepted answer fails to answer a secondary aspect of the question, specifically:

If so, isn't it absolutely essential to get anything on git to work? (Minimally, how else could the "ordering" of the log history be established? Worse case, couldn't I have a binary file corrupted by simultaneous writes?)

So I'll address myself to just that portions.

There are no simultaneous writes in git, and the ordering of history is part of the answer why!

When you push a commit to a remote git repository it verifies that the commit that you are pushing is a descendant of what the repository already has as the head of that branch.

If not, the commit is rejected.

If it is, then git will send over a set of blobs (file data), tree objects, and commits.

It then updates the branch head to point to your new commit.

Except if the head changed, it will once again, reject your new commit.

If rejected, you have to pull in the newer changes from the remote repository, and either merge them with your changes, or rebase your changes on top of the new ones (e.g. git pull -r).

Either way, you create a new local commit that is a descendant of what the repository has.

You can then push this new commit to the repository. It is possible for this new commit then to be rejected, forcing you to repeat the process.

Files are never overwritten. The file "mybigfile.mpg" to git is just a blob with a unique ID based on a SHA-256 hash of the file contents. If you change the file, that's a new blob with a new ID.

The filename, that is just an entry in a tree object. These also have IDs based on a hash of their contents.

If you rename a file (or add, remove, etc.) that's a new tree object, with it's own ID.

Because these are part of the history (a commit includes the id of the top tree being committed, as well as IDs of its parents), these objects (blobs, trees, commits, signed tags) are only ever added to the repository, and never modified.

Git history is always ordered, because it is a linked list, with links pointing to the parents. Zero commits for the initial commit, two or more for merge commits, and one otherwise.

And they don't require any explicit locking, because git checks for conflicts before making a change.

Only the file that contains the ID of the head commit on a branch needs to be locked, and then only for a brief moment between checking for changes and updating it.

Locks in git-lfs address a very different problem. Binary assets usually cannot be merged, and often involve large amounts of work in changing them.

This is especially true of large assets.

If two developers start making changes to the same file, one set of changes will have to be discarded, and then recreated starting with the other change as a base.

git-lfs locking prevents this from happening by accident. If you encounter a lock, you either wait until later to make your changes, or you go talk to the person who has that lock.

Either they can make the requested change, or they can release the lock and allow you to make your change on top of their changes so far. Then when you're done, you can push your change and release the lock, allowing them to continue with your change.

Thus, it allows changes (the entire developer process, not file-writing) for specific files to be serialized, rather than the parallel-then-merge paradigm used for textual source files.