我的代码相当于此
public static async Task CopyAndRestAndCommitFile(Stream content,
string branchName,
string sha)
{
CreateOrResetBranch(branchName, sha);
await Copy(content);
Commit("changed");
}
private static async Task Copy(Stream content)
{
var filePath = @"C:\temp\libgit2sharpTestRepo\fileToChange.txt";
using (var fileStream = new FileStream(filePath,
FileMode.Create,
FileAccess.Write,
FileShare.None,
32 * 1024,
useAsync: true))
{
await content.CopyToAsync(fileStream);
}
}
private static void CreateOrResetBranch(string branchName, string startPoint)
{
//This Replaces git -B \{branchName} \{startPoint}
using (var repo = new LibGit2Sharp.Repository(RepositoryPath))
{
var branch = repo.Branches[branchName];
if (branch == null)
{
branch = repo.CreateBranch(branchName, startPoint);
repo.Checkout(branch);
}
else if (string.IsNullOrEmpty(startPoint))
{
repo.Checkout(branch);
}
else
{
var commit = repo.Commits.Single(c => c.Sha == startPoint);
if (commit != null)
{
repo.Checkout(branch);
repo.Reset(ResetMode.Hard, commit);
}
}
}
}
private static void Commit(string message)
{
// this replaces git add -A
// git -m \{message}
using (var repo = new Repository(RepositoryPath))
{
repo.Stage("*");
repo.Commit(message);
}
}
以CopyAndRestAndCommitFile()
作为切入点。出于某种原因repo.Commit(message)
始终抛出LibGit2Sharp.EmptyCommitException
,即使磁盘上的文件已更改。如果我在调用commit函数之前从命令行运行git status
,则提交成功。
这不是一个时间问题,因为我在Copy()
和Commit()
函数之间延迟了多长时间,问题就出现了。重复Commit()
函数的次数也无关紧要,它总是抛出异常,直到我从repo上的命令行运行git status
。
奇怪的是,上面的代码并没有完全重现这个问题,但是它与实际代码之间的唯一区别是实际代码在ASP.NET上下文中运行,而我们正在复制的流是一个请求内容流。
如何调试此问题?
答案 0 :(得分:1)
EmptyCommitException
。这意味着没有进行任何修改。
由于您的方案演示了一些分段,我的猜测是您在libgit2中遇到已知问题。
repo.Stage()
是一个将workdir目录中发生的更改提升为Index
的操作。为此,LibGit2Sharp在工作目录和索引之间运行差异。
但是,为了避免过多的oid计算,当前的libgit2启发式"跳过"如果文件在磁盘上的大小与索引所知的大小相同,并且修改的时间没有被更改,则为文件。问题在于,根据原始git设计,时间戳存储在索引中,精度为1秒。
因此,当在同一秒内,您在不改变其大小的情况下将文件分段两次时,第二个文件将被libgit2 diff算法检测不到。