For one of our clients, we noticed their builds started failing at the checkout step. Looking at the logs the error was
error: cannot lock ref 'refs/remotes/origin/<branch>': there is a non-empty directory '.git/refs/remotes/origin/<branch>' blocking reference 'refs/remotes/origin/<branch>'
In this post we will see what was the root cause and how to fix it.
Issue
From the logs it was pretty evident that it is to do with the branches. Looking at the branches it became clear that there are few branches which just differ in the letter case. For example, take a look at users/Sai
and Users/Sai/local
branches - notice letter u
has different case in those branch names.
The build was happening on a Windows on-premises agent. This meant, the agent machine file-system is case-insensitive. However, Git built originally for Linux and is case-sensitive. This means that on Linux machines a repo which contain readme.md
and Readme.md
are both valid and hence co-exist. On Windows and macOS you will not be allowed to create files with such file names.
So, the issue was that, while Git (and Azure DevOps) allowed branch names to be created that only differ in case (treating them as separate refs). However, when agent tried to clone (Git uses file-system to store refs) the branches on a Windows machines, they conflict and hence the failure.
Solution
Solution is to clean (remove or rename) the branches which just differ in case. Fortunately, Azure DevOps makes it super easy to do this by just using the portal.
Head over to the Repos
hub and Branches
page. Navigate to the branch you want to rename and open the context menu on the latest commit of that branch and click New branch
.
In the dialog that opens, enter the name for the new branch. Make sure you correct the casing. Here I am creating the new branch from Users/Sai/local
to users/Sai/local
, so that a new branch with the same commit is available at the new location.
Once done, go ahead and delete the branch causing conflict. In our case it was Users/Sai/local
.
Do the same for other branches if you have any.
Once you clean all the conflicting branches, retrigger the build and it should succeed now.
Prevention
Okay, you solved the problem, but how will you ensure that it does not happen again? Well, Azure DevOps has the setting to the rescue.
Go to your Project settings
[1] and Repositories
page [2]. Select the repository [3] and then Options
[4]. Finally enable the option which says Block pushes from introducing names that differ only in case to avoid case-sensitivity conflicts. Applies to files, folders, branches, and tags.
Optionally, you can also enable this option for all the Git repositories you create. To do that, you will have to select root Git Repositories
node and do the same.