Generate Git Ignore file from the csproj file

Let’s say that you have a specific project that has a tonne of extra files that are automatically copied into it due to front end build tasks or similar. However, you don’t want any of these copied files to make their way into the GIT repo; nor do you want to create a blanket git ignore rule on the entire folder, because then other developers may forget to manually override them if they add new files to the project itself.

So what can you do!?

Well, I bet there’s a better way, but in the meantime, I’ve created a little MSBUILD task to generate a .gitignore file based so that only the files included in my Visual Studio project are included in GIT. It’ll do this after every build or rebuild.

Here’s my .targets file that can then just be dumped into a my “tools” solution folder and then included in the proj file:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <AvailableItemName Include="GenerateGitIgnore" />
  </ItemGroup>
  <Target Name="AfterBuild">
    <CallTarget Targets="GenerateGitIgnore" />
  </Target>
  <Target Name="GenerateGitIgnore">
 
    <ItemGroup>
      <LocalGitIgnoreFile Include=".gitignore" />
      <ProjectFiles Include="@(Content); @(None); @(Compile)" />
      <LocalProjectFiles Include="%(ProjectFiles.Identity)" Condition="'@(ProjectFiles->Contains(':\'))'=='False' And '@(ProjectFiles->Contains('..\'))'=='False' And '@(ProjectFiles->Contains('obj\'))'=='False'" Exclude="@(LocalGitIgnoreFile)" />
    </ItemGroup>
 
    <ReadLinesFromFile File="@(LocalGitIgnoreFile)" Condition="'@(LocalGitIgnoreFile -> Exists(%(Identity))' == 'True'">
      <Output
          TaskParameter="Lines"
          ItemName="CurrentGitIgnores"
          />
    </ReadLinesFromFile>
 
    <ItemGroup>
      <SourceGitIgnores Include="%(CurrentGitIgnores.Identity)" Condition="'@(CurrentGitIgnores->Contains('#'))'=='True'" />
      <!-- Note: %2A is the escape char for an '*' -->
      <ProjectGitIgnores Include="%2A;@(SourceGitIgnores);@(LocalGitIgnoreFile -> '!%(Identity)');!$(MSBuildProjectFile);@(LocalProjectFiles -> '!%(Identity)')" />
      <ProjectGitIgnoresFlattened Include="%(ProjectGitIgnores.Identity)" />
    </ItemGroup>
 
    <WriteLinesToFile
            File="@(LocalGitIgnoreFile)"
            Lines="@(ProjectGitIgnoresFlattened)"
            Overwrite="true"
            Encoding="Unicode" />
 
  </Target>
</Project>

Note: If you want to add a manual entry to the ignore file, you should include a ‘#’ at the back to make the build target automatically keep it.

The piece I couldn’t work out how to do well was the exclusion of any linked files outside of the project root. For now, that’s just as a series of manual conditions on the ‘LocalProjectFiles’ item group declaration. Let me know if you know a better way!

To add the targets file to the bottom of your csproj file:

  <Import Project="..\..\tools\MsBuild\GenerateGitIgnore.targets" Condition="Exists('..\..\tools\MsBuild\GenerateGitIgnore.targets')" />

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s