By: P. Kelley
On 30 January 2013, we released the first preview version of the Visual Studio Tools for Git downloadable plugin for Visual Studio 2012. We recently became aware of two bugs in this initial preview release that we felt warranted public disclosure. The second preview version of the Visual Studio Tools for Git, version 0.8.0.0 is now available for download, and these bugs are fixed in that version.
Both bugs are related to the support in the open-source libgit2 library for the “core.ignorecase” setting. This setting is on by default on Windows, because Windows file systems (like NTFS) are generally case-insensitive but case-preserving. That is, the filenames “file.txt” and “FILE.txt” both map to the same file on disk.
It’s legal for a Git repository to have two directories (also called trees, in Git-speak) with different names according to case-sensitive sorting rules, but identical names under case-insensitive sorting. For example, those directories might be named “Images” and “images”. On Windows, when you create a working copy of this structure, the contents of these separate “Images” and “images” directories end up merged together in one directory on your disk, since the two directory names are equivalent. If you created a working copy on Linux, though, you would end up with two separate subdirectories next to each other, named “Images” and “images”. Their contents wouldn’t be in the same place like on Windows.
We see this scenario most commonly when you have a team using Git to share a repository between UNIX and Windows. However, it’s also possible to get this to occur when you rename a folder on your local disk, edit a file underneath the renamed folder, and then commit.
If you do have a repository with this particular property somewhere in it, then you may run into a couple of problems in our 0.7.x.x series of releases. (Again, these are fixed for 0.8.0.0.)
- Spurious/non-existent changes in the Changes page. Generally, these show up as pending deletes. If you go to use the git.exe command-line tool and run “git status”, you won’t see these spurious changes. This is a bug in libgit2 having to do with support for ‘merging’ equivalent directories into a single one as described above.
- Corrupted tree objects being written out at commit time by libgit2. This is due to a bug in libgit2 where the in-memory copy of the repository index was sorted case-insensitively. However, tree objects committed permanently to the Git repository’s object store always use case-sensitive sorting. If a subset of items from the index repeats a subdirectory name with different cases, as in the sequence (“subfile1.txt”, “SUBfile2.txt”, “subfile3.txt”), then the folder “sub” will be created twice in the tree object, which is not legal.
This means that from the point of this commit forward, your Git repository is corrupted. Most Git hosting providers won’t let you push these corrupted tree objects up. For example, if you try to push to Team Foundation Service, you’ll get an error message that looks something like “The tree object pushed has an invalid structure.” To recover your repository, you’ll have to cut off the portion of your Git object graph that is malformed and repeat those commits either using git.exe or our latest tools.
Finally, I’d like to point out that these bugs don’t just affect the Visual Studio Tools for Git. Other software depending on libgit2 is also potentially affected depending on what functionality from libgit2 is being used. Microsoft has contributed fixes for these issues for the benefit of both our own tools and the entire libgit2 ecosystem.