Worked example - Rearranging projects in large solution

Worked example - Rearranging projects in large solution

Photo by Kaleidico on Unsplash

I've recently been working with a solution which contains 34 projects. In the file system, the root of the repository had a flat list of all 34 project folders. In the solution were some solution folders giving some structure to the projects, but it wasn't the most helpful structure. I was tasked with moving the projects into folders, and updating both file system and solution folders to match each other. This is how I approached the task.

I did the bulk of the work using the windows command line, to avoid my IDE needing to update its indexes repeatedly. From the root of my repository, I first created the directory structure which I wanted using mkdir:

mkdir path\to\new\folder

I could then use git mv to move an existing folder into a different folder. Git requires that the destination folder already exists, which is why I created them with mkdir first.

git mv path\to\old\folder path\to\new\folder

Once I'd done this for each project, the bulk of the task was done. Around 100,000 files had moved to a new structure, with minimal effort. However, at this point the solution was not in a fit state to use.

The most important update I still needed was to update package references in the csproj files. When Project A references Project B within the same solution, ProjectA.csproj will contain a reference which looks like this:

<ItemGroup>
   <ProjectReference Include="..\ProjectB\ProjectB.csproj" />
</ItemGroup>

This assumes that the directory structure looks like this:

src/
├─ ProjectA/
│  ├─ ProjectA.csproj
├─ ProjectB/
│  ├─ ProjectB.csproj

The Include path in the ProjectReference element is a path from ProjectA.csproj to ProjectB.csproj. (The ..\ means to go up a directory.) This path needs updating now that the directory structure has changed. It's now something more like this:

<ItemGroup>
   <ProjectReference Include="..\..\..\path\to\ProjectB\ProjectB.csproj" />
</ItemGroup>

This was within a .NET 6 project. It's possible that this may have been stored in a different format in older versions of .NET. The format of the csproj file has changed over time.

There were also some paths within the .gitignore file which needed updating. Until I updated them, git status was telling me there were untracked files.

At this point, the solution is back in a working state. There was still work to do though. I had some run configurations set up in my IDE which referenced the csproj files, so they needed updating now that the csproj files had moved. Similarly, my deployment pipelines did need some updates.

The final change I made was to update the solution folders. These are independent of the directory structure and are defined within the sln file. I updated them using my IDE, which was a simple case of right clicking on the solution to create new folders, then dragging the projects into the folders where I wanted them. The only change to the source code is the sln file, there are no actual file moves doing this.

Once all this was done I was ready to test everything. After a large change like this, it's important to test absolutely everything that ever happens. If some projects or pipelines don't get used very often it's easy to forget them, but this is the time to do a full test to ensure that all code can be built and run locally, and can be deployed to remote environments.

In the end, this piece of work was quicker and easier than I'd expected, which is a testament to the quality of the tooling which developers have at their disposal nowadays.