How to ignore files in Subversion

commandsvn

How do I ignore files in Subversion?

Also, how do I find files which are not under version control?

Best Answer

(This answer has been updated to match SVN 1.8 and 1.9's behaviour)

You have 2 questions:

Marking files as ignored:

By "ignored file" I mean the file won't appear in lists even as "unversioned": your SVN client will pretend the file doesn't exist at all in the filesystem.

Ignored files are specified by a "file pattern". The syntax and format of file patterns is explained in SVN's online documentation: http://svnbook.red-bean.com/nightly/en/svn.advanced.props.special.ignore.html "File Patterns in Subversion".

Subversion, as of version 1.8 (June 2013) and later, supports 3 different ways of specifying file patterns. Here's a summary with examples:

1 - Runtime Configuration Area - global-ignores option:

  • This is a client-side only setting, so your global-ignores list won't be shared by other users, and it applies to all repos you checkout onto your computer.
  • This setting is defined in your Runtime Configuration Area file:
    • Windows (file-based) - C:\Users\{you}\AppData\Roaming\Subversion\config
    • Windows (registry-based) - Software\Tigris.org\Subversion\Config\Miscellany\global-ignores in both HKLM and HKCU.
    • Linux/Unix - ~/.subversion/config

2 - The svn:ignore property, which is set on directories (not files):

  • This is stored within the repo, so other users will have the same ignore files. Similar to how .gitignore works.
  • svn:ignore is applied to directories and is non-recursive or inherited. Any file or immediate subdirectory of the parent directory that matches the File Pattern will be excluded.
  • While SVN 1.8 adds the concept of "inherited properties", the svn:ignore property itself is ignored in non-immediate descendant directories:

    cd ~/myRepoRoot                             # Open an existing repo.
    echo "foo" > "ignoreThis.txt"                # Create a file called "ignoreThis.txt".
    
    svn status                                  # Check to see if the file is ignored or not.
    > ?    ./ignoreThis.txt
    > 1 unversioned file                        # ...it is NOT currently ignored.
    
    svn propset svn:ignore "ignoreThis.txt" .   # Apply the svn:ignore property to the "myRepoRoot" directory.
    svn status
    > 0 unversioned files                       # ...but now the file is ignored!
    
    cd subdirectory                             # now open a subdirectory.
    echo "foo" > "ignoreThis.txt"                # create another file named "ignoreThis.txt".
    
    svn status
    > ?    ./subdirectory/ignoreThis.txt        # ...and is is NOT ignored!
    > 1 unversioned file
    

    (So the file ./subdirectory/ignoreThis is not ignored, even though "ignoreThis.txt" is applied on the . repo root).

  • Therefore, to apply an ignore list recursively you must use svn propset svn:ignore <filePattern> . --recursive.

    • This will create a copy of the property on every subdirectory.
    • If the <filePattern> value is different in a child directory then the child's value completely overrides the parents, so there is no "additive" effect.
    • So if you change the <filePattern> on the root ., then you must change it with --recursive to overwrite it on the child and descendant directories.
  • I note that the command-line syntax is counter-intuitive.

    • I started-off assuming that you would ignore a file in SVN by typing something like svn ignore pathToFileToIgnore.txt however this is not how SVN's ignore feature works.

3- The svn:global-ignores property. Requires SVN 1.8 (June 2013):

  • This is similar to svn:ignore, except it makes use of SVN 1.8's "inherited properties" feature.
  • Compare to svn:ignore, the file pattern is automatically applied in every descendant directory (not just immediate children).
    • This means that is unnecessary to set svn:global-ignores with the --recursive flag, as inherited ignore file patterns are automatically applied as they're inherited.
  • Running the same set of commands as in the previous example, but using svn:global-ignores instead:

    cd ~/myRepoRoot                                    # Open an existing repo
    echo "foo" > "ignoreThis.txt"                       # Create a file called "ignoreThis.txt"
    svn status                                         # Check to see if the file is ignored or not
    > ?    ./ignoreThis.txt
    > 1 unversioned file                               # ...it is NOT currently ignored
    
    svn propset svn:global-ignores "ignoreThis.txt" .
    svn status
    > 0 unversioned files                              # ...but now the file is ignored!
    
    cd subdirectory                                    # now open a subdirectory
    echo "foo" > "ignoreThis.txt"                       # create another file named "ignoreThis.txt"
    svn status
    > 0 unversioned files                              # the file is ignored here too!
    

For TortoiseSVN users:

This whole arrangement was confusing for me, because TortoiseSVN's terminology (as used in their Windows Explorer menu system) was initially misleading to me - I was unsure what the significance of the Ignore menu's "Add recursively", "Add *" and "Add " options. I hope this post explains how the Ignore feature ties-in to the SVN Properties feature. That said, I suggest using the command-line to set ignored files so you get a feel for how it works instead of using the GUI, and only using the GUI to manipulate properties after you're comfortable with the command-line.

Listing files that are ignored:

The command svn status will hide ignored files (that is, files that match an RGA global-ignores pattern, or match an immediate parent directory's svn:ignore pattern or match any ancesor directory's svn:global-ignores pattern.

Use the --no-ignore option to see those files listed. Ignored files have a status of I, then pipe the output to grep to only show lines starting with "I".

The command is:

svn status --no-ignore | grep "^I"

For example:

svn status
> ? foo                             # An unversioned file
> M modifiedFile.txt                # A versioned file that has been modified

svn status --no-ignore
> ? foo                             # An unversioned file
> I ignoreThis.txt                  # A file matching an svn:ignore pattern
> M modifiedFile.txt                # A versioned file that has been modified

svn status --no-ignore | grep "^I"
> I ignoreThis.txt                  # A file matching an svn:ignore pattern

ta-da!