我有一个开源Web应用程序,其中多个线程可以使用磁盘上的相同存储库。这包括对新分支执行git checkout
并从存储库中访问文件。
这有一些问题:
Git使用悲观的并发控制来操作,使用存储库中的锁文件。正如预期的那样,当同一个存储库同时在其中调用多个git checkout
命令时,会在JGit中抛出异常。
命令完成后将访问存储库中的文件并删除Git的锁定文件。这意味着另一个签出可能会在此阶段更改文件并导致错误解析它们。
我已经将同步方法和信号量视为解决方案,但在这种情况下我并不知道“最佳”解决方案。
答案 0 :(得分:2)
我建议使用JGit,这是Git的纯Java实现。使用普通的Java库使得不必在服务器上提供合适的Git版本,并且还节省了一些处理周期,因为它不会为每个Git命令生成单独的进程。
在大多数领域,JGit与Git CLI实现相同。因此,除非您需要非常具体的Git功能,否则您将看不到差异。
为了直接访问blob的内容,可以使用ObjectReader / ObjectLoader API。例如:
ObjectReader objectReader = repository.newObjectReader();
ObjectLoader objectLoader = objectReader.open( blobId );
int type = objectLoader.getType(); // Constants.OBJ_BLOB
byte[] contents = objectLoader.getBytes();
有关直接访问Git对象数据库的更多信息,请参阅此文章:http://www.codeaffine.com/2014/10/20/git-internals/
为防止并发写访问,JGit使用与Git CLI相同的锁文件。如果由于锁定失败导致写入访问失败,JGit将返回相应的命令状态,允许应用程序代码稍后重试相同的操作。
如果“乐观锁定”的方法不适合您的用例,您仍然可以使用工作队列或其他同步方法。
答案 1 :(得分:1)
以下是一些选项,它们不会破坏磁盘上的文件,因此对多线程处理更安全:
您可以直接查看文件的内容,而无需检查整个提交:
从命令行,您可以使用:
git show <tree-ish>:path/to/file
或以某种方式找到文件内容的哈希值,并调用:
git cat-file -p <file-hash>
我不熟悉JGit,但你肯定能找到一种方法来使用它的api执行这些命令
如果您有理由真正检查完整提交,可以查看不同的工作树(参见git help worktree
),
或者可能构建一个存档(git help archive
)而不是真正签出提交
奖励点:所有这些命令也适用于裸git仓库。
答案 2 :(得分:0)
试试scm4j-vcs-api。它具有特殊功能 - 锁定工作副本,这是一个线程和进程安全的文件夹
public static final String WORKSPACE_DIR = System.getProperty("java.io.tmpdir") + "scm4j-vcs-workspaces";
public static void main(String[] args) {
IVCSWorkspace workspace = new VCSWorkspace(WORKSPACE_DIR);
String repoUrl = "https://github.com/scm4j/scm4j-vcs-api";
IVCSRepositoryWorkspace repoWorkspace = workspace.getVCSRepositoryWorkspace(repoUrl);
try (IVCSLockedWorkingCopy wc = repoWorkspace.getVCSLockedWorkingCopy()) {
// execute git-related operations within wc.getFolder()
}
}
另请参阅scm4j-vcs-git作为在分离的工作副本中执行Git操作的示例库