visualstudio-wallpaper-05At one point I was coding on a hobby project, using Visual Studio Online for project management and source control. Because of the technologies involved, a large number of temporary files were being generated that I didn’t want checked in. Visual Studio’s TFS integration is pretty good at automatically filtering these kinds of files out and placing them in the Excluded Changes list in the Pending Changes window, but in my case the sheer number made it a pain to scan the Excluded Changes list for valid changes that I actually wanted to commit.

In my case, I didn’t want those temporary files to show up at all – not even in the Excluded Changes list. In order to gain control over which files TFS should ignore completely, I added .tfignore files to my solution. These allow you to specify which files, extensions and directories to ignore (or un-ignore!) from source control. If you’re familiar with the concept of .gitignore files in GIT, you should feel right at home.

Example excluded changes view before adding tfignore rules.
Example excluded changes view before adding tfignore rules.

You can either manually create a .tfignore file in your solution, or you can add one automatically in Visual Studio by clicking the “Detected” link and then right-clicking on the files under the Excluded Changes list and selecting one of the Ignore options:

Creating a tfignore file using the IDE.
Creating a tfignore file using the IDE.

Once you select one of the ignore options, a .tfignore file will automatically be added to the root of our solution as a result:

A tfignore file in an example solution.
A tfignore file in an example solution.

In this case, I chose “ignore by extension”, so this file contains a rule specifying that version control should ignore all files with the .txt extension. This rule will apply to the directory containing the .tfignore file and all subdirectories. The syntax of the rule is simple:

# This rule ignores files with the .txt extension
*.txt

The comment block at the top of the auto-generated .tfignore file provides example syntax for this and other usages such as limiting rules only to the local directory, limiting rules to a specific named directory, excluding an entire directory, and more.

# ################################################################################
# This .tfignore file was automatically created by Microsoft(R) Visual Studio.
#
# Local items matching filespecs in this file will not be added to version
# control. This file can be checked in to share exclusions with others.
#
# Wildcard characters are * and ?. Patterns are matched recursively unless the
# pattern is prefixed by the \ character.
#
# You can prepend a path to a pattern to make it more specific. If you do,
# wildcard characters are not permitted in the path portion.
#
# The # character at the beginning of a line indicates a comment.
#
# The ! prefix negates a pattern. This can be used to re-include an item after
# it was excluded by a .tfignore file higher in the tree, or by the Team
# Project Collection's global exclusions list.
#
# The / character is interpreted as a \ character on Windows platforms.
#
# Examples:
#
#  # Excludes all files ending in .txt in Alpha\Beta and all its subfolders.
#  Alpha\Beta\*.txt
#
#  # Excludes all files ending in .cpp in this folder only.
#  \*.cpp
#
#  # Excludes all files ending in .cpp in this folder and all subfolders.
#  *.cpp
#
#  # If "Contoso" is a folder, then Contoso and all its children are excluded.
#  # If it is a file, then only the "Contoso" in this folder is excluded.
#  \Contoso
#
#  # If Help.exe is excluded by a higher .tfignore file or by the Team Project
#  # Collection global exclusions list, then this pattern re-includes it in
#  # this folder only.
#  !\Help.exe
#
################################################################################

It is important to pay close attention to the scoping of .tfignore rules in order to avoid excluding files unintentionally, as these rules apply recursively to the local directory and all subfolders unless explicitly stated otherwise. In that regard, the final rule in the comment block above is notable in that it allows a .tfignore file in a child directory to override a rule specified by a .tfignore file in a parent directory.

Returning to my earlier example, if I were to add a Documents directory to my solution containing an IncludeMe.txt file, TFS would ignore the text file based on my initial rule. However, I can add a second .tfignore file to the Documents directory with the rule “!*.txt” to override the higher-level .tfignore rule and allow version control to detect IncludeMe.txt:

IncludeMe.txt is detected based on the higher-level override rule.
IncludeMe.txt is detected based on the higher-level override rule.

IncludeMe.txt now appears under the Excluded Changes list in the Detected link, allowing me to promote it and include it in source control.