In this post we will create a gitignore file that matches our recommended file and directory structure for using revision control with Vivado projects.
In the previous post we went through several guidelines on how to use revision control with Vivado projects. There we defined a directory structure and listed all the files that needed to be versioned. However, any files that are created in a directory that is being tracked may be identified by the revision control system as something we would like to add to our repository. This might include any intermediate results, reports, logs, and output products that are generated by Vivado and that we would not like to keep.
Modern revision control systems support creating a list of directories and files that shall be ignored, thus facilitating the tracking process. In Git this is done by describing in the ‘.gitignore’ file which files and directories must (or must not) be versioned.
Although the gitignore file contains a list of directories and files that Git shall ignore, the syntax for describing those rules allows us to use a different strategy: we will first tell Git to ignore everything, and then we will create exceptions for all the elements that we do want to track. This is known as ‘whitelisting’.
The code below shows a gitignore file that whitelists all the files and directories we would like to keep, as defined in our revision control guidelines. All text in a gitignore file starting with a ‘#’ are comments.
# Ignore everything
*
# Allow whitelisting subdirectories
!*/
# Don\'t ignore the block design and block design hdl wrapper files
!/bd/*/*.bd
!/bd/*/hdl/*.sv
!/bd/*/hdl/*.v
!/bd/*/hdl/*.vhd
!/bd/*/hdl/*.vhdl
# Don\'t ignore the constraint files
!/constraints/**/*.xdc
# Don\'t ignore the synthesis files
!/hdl/**/*.sv
!/hdl/**/*.v
!/hdl/**/*.vh
!/hdl/**/*.vhd
!/hdl/**/*.vhdl
# Don\'t ignore the HLS source and testbench files
!/hsl/*/sources/*.cpp
!/hsl/*/sources/*.hpp
!/hsl/*/testbench/*.cpp
# Don\'t ignore the IP defintion files
!/ip/*/*.xci
# Don\'t ignore the HLS IP defintion files
!/ip/hls_ip/**
# Don\'t ignore the output files
!/output/**/*.bit
!/output/**/*.xsa
!/output/**/*.dcp
# Don\'t ignore the project files
!/project/*.xpr
# Don\'t ignore the simulation files
!/sim/**/*.sv
!/sim/**/*.v
!/sim/**/*.vh
!/sim/**/*.vhd
!/sim/**/*.vhdl
!/sim/**/*.wav
# Don\'t ignore this file
!.gitignore
The fist command, ‘*’, ignores all contents of the directory tree. So, our first action is to exclude all files and directories from revision control.
In the .gitignore syntax, a ‘!’ negates the command to ignore the objects that come afterwards, so we will use it to whitelist all the files and directories we want to keep.
The second command, ‘!*/’ recursively whitelists all subdirectories. This might sound a bit counter-intuitive, as Git does not allow tracking of empty folders, but this command allows us to access subdirectories to whitelist their content. We can think of it as an ‘AND’ condition: after we blacklist everything, we need to whitelist the files that we do want to track and the (sub)directories in which they are stored. If we whitelist only one of those (the directories or the files) Git will still ignore the files.
Now we get to the fun part. Whitelisting files is done by ‘unignoring’ them with the ‘!’ operator. The path to the file is relative to the location of the gitignore file, which should be in the project root directory. Since we don’t know how the files will be named, we use the wildcard ‘*’ followed by the file extension. For instance, the ‘!/project/*.xpr’ pattern will whitelist all files with the ‘.xpr’ extension in the ‘project’ folder. Of course, it is up to the developer to make sure that only one project file is stored in the project folder.
The ‘*’ wildcard also allows us to navigate the directory hierarchy to apply some more powerful whitelisting patterns, especially when it comes to files below the first layer of the folder hierarchy. For instance, when working with block designs, we have three layers in the folder hierarchy:
- the bd folder, where all block designs are stored,
- an intermediate folder with the name of the block design, and
- the hdl folder stored in the intermediate folder, next to the block definition file.
The ‘!/bd/*/*.bd’ and ‘!/bd/*/hdl/*.vhd’ commands allow us to whitelist the block design and VHDL wrapper files for all block designs, even though the names of each block design (and therefore the name of the second layer of the folder hierarchy) are unknown. The same strategy is used for whitelisting the IP definition files.
The ‘*’ wildcard is useful when the number of levels in the folder hierarchy is known, however, this is not always the case. It is common to create subfolders for the synthesizable code and the testbench, so that their logical hierarchy is reflected in the file system. In this case, the ‘**’ wildcard will represent all subdirectories that exist below the last folder in the path. Thus, the command ‘!/hdl/**/*.sv’ will whitelist all SystemVerilog sources in the hdl directory and any of its subfolders.
Finally, the ‘!.gitignore’ command whitelists the gitignore file itself, so that these rules are enforced by Git. After all, we don’t want our hard work to go to waste, do we?
Cheers
Isaac