Question

In my sample code, I do this (on Windows):

var repo = new Repository(command.RepoFolder);
for (int i = 0; i < 100; i++)
{
  string file = command.RepoFolder + "\\text.txt";
  File.WriteAllText(file, string.Format("File number {0}, written at {1}", i, DateTime.Now));

  repo.Index.Stage("text.txt");
  repo.Commit(string.Format("Written version {0}", i), new Signature("me through code", "email@email.com", DateTimeOffset.Now));
}

If I step through this sequence with the debugger, each loop run through the loop creates a new commit with the expected checge in the text.txt file and the appropriate commit message. However, if I run it without blocking it, I get 100 commits, with the expected commit messages, but only some of the commits have a real file change in them. They are typically of this form:

- File number 54, written at 8/30/2013 10:27:38 AM
+ File number 88, written at 8/30/2013 10:27:39 AM

So it seems as if repo.Index.Stage() happens asynchronously and the commit is done before the file system changes have been noticed. Is that as expected? Is this the "racy git" behavior? Is there a way in Libgit2Sharp to explicitly wait until the changes have been picked up by the index?

Addition:

  1. if I do an append on the file instead of a rewrite with a different line, everything works fine
  2. If I do the same thing on the command line using git.exe, I see no such behaviour
Was it helpful?

Solution

LibGit2Sharp repo.Index.Stage() relies on libgit2 diffing functionality to determine which files have been modified in the workdir and which files haven't.

When doing a diff, and before comparing the actual files contents, libgit2 relies on some "tricks" to check if a file has been changed. For example:

  • if the file has the same size in the index and in the workdir
  • and if the file modification date/time is the same (time with seconds precision on windows)
  • and if other attributes (file owner, mode, ...) are the same

then the file is considered as unmodified, and it won't be opened at all to see if the content is the same. This allows for a big optimization for big repos with thousands of files.

In your case, many of your files have the same size and the same date/time of modification, which is why those files are not picked up by repo.Index.Stage().


A possible (dirty) workaround is to add a Thread.Sleep(TimeSpan.FromSeconds(1)); between your modifications.


A bug report dealing with the same issue has recently been opened on the LibGit2Sharp bugtracker. If you have real-world examples, or an opinion to give, on this topic, feel free to weigh in!

OTHER TIPS

I was having the same problem, but the Thread.Sleep trick didn't work for me, no matter how long I made it wait, but this did

File.SetLastWriteTime(filePath, DateTime.UtcNow.AddHours(-1));

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top