即使工作目录中有更改,Repository.Commit()也会抛出EmptyCommitException

时间:2015-01-20 02:04:01

标签: c# libgit2sharp

我的代码相当于此

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上下文中运行,而我们正在复制的流是一个请求内容流。

如何调试此问题?

1 个答案:

答案 0 :(得分:1)

当要提交的树与父提交中的树匹配时,将引发

EmptyCommitException。这意味着没有进行任何修改。

由于您的方案演示了一些分段,我的猜测是您在libgit2中遇到已知问题。

repo.Stage()是一个将workdir目录中发生的更改提升为Index的操作。为此,LibGit2Sharp在工作目录和索引之间运行差异。

但是,为了避免过多的oid计算,当前的libgit2启发式"跳过"如果文件在磁盘上的大小与索引所知的大小相同,并且修改的时间没有被更改,则为文件。问题在于,根据原始git设计,时间戳存储在索引中,精度为1秒。

因此,当在同一秒内,您在不改变其大小的情况下将文件分段两次时,第二个文件将被libgit2 diff算法检测不到。

有关详细信息,请参阅http://github.com/libgit2/libgit2sharp/pull/688