Azure Pipelines - Git checkout step fails with cannot lock ref error

Jun 6, 2019 | Utkarsh Shigihalli Utkarsh Shigihalli

Azure DevOps Git

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.

branches in the repo

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.

branch context menu

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.

Create new branch

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.

Block commits

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.

About author
Utkarsh Shigihalli
Utkarsh Shigihalli
Utkarsh is passionate about software development and has experience in the areas of Azure, Azure DevOps, C# and TypeScript. Over the years he has worked as an architect, independent consultant and manager in many countries including India, United States, Netherlands and United Kingdom. He is a Microsoft MVP and has developed numerous extensions for Visual Studio and Azure DevOps.
Comments