Introduction: Version Control for Open Source Hardware

About: Brainbow is a multi-disciplinary creative engineering studio. We've built a wide range of projects for clients, from web apps to specialty electronics hardware.

The team at Brainbow have a number of electronics projects under our belts, and we wanted to share our process for using version control to manage our electronics design workflow. This workflow has been used for projects large and small, from simple 2 layer boards to complex 10 layer behemoths, and is based on open-source tools. Hopefully, others can adopt our workflow for themselves, and gain the benefits of version control for their own projects. But what benefits can version control offer an electronics project?

Step 1: Why Version Control Your Electronics?

Version Control (aka source control or revision control) is a well-understood and widely adopted concept in software engineering. The idea behind source control is systematically tracking changes made to the source code of a program or application. If changes break the application, you can revert the source code files to a known working state from the past. In practice, source control systems allow you to track the history of a collection of files (usually the source code files for a computer program, website, etc), and visualize and manage changes to those files.

Tracking the history of changes to a project seems useful for electronics projects; if you make a mistake in the circuit schematic, or use the wrong component footprint in the PCB layout, it would be nice to keep track of what mistakes were made and what fixes were implemented in various revisions of a project. It would also be useful for other makers to see that history, and understand the context and motivations of various changes.

Step 2: The Tools: KiCad and Git

We use two main tools in this project: the version control system (VCS) and the electronics design automation program (EDA or ECAD).

There are MANY version control systems out there, but we use the distributed VCS Git. We use it for a number of reasons, but key are that it's open-source (check!), easy to use (check!), and the de-facto standard VCS for open-source software (check!). We will be using Git as the VCS to track the changes to the files that our ECAD program uses. This Instructable doesn't require familiarity with Git, but general comfort using the command line is assumed. I will try to link to helpful resources for both Git and command line use as necessary.

Most source control systems work particularly well for text-based files, so an ECAD program that uses text files would be great. Enter KiCad, the open-source "Cross Platform and Open Source Electronics Design Automation Suite" backed by researchers at CERN. KiCad is also open-source (check!), easy-to-use (although some would disagree with me on that), and highly capable for advanced electronics design work.

Step 3: Installation

To install these programs, follow the instructions from their various download sites linked below.

  • KiCad is cross-platform (and dizzying-ly so; their download page lists 13 supported OS's, and offers a source code download if none of those suit you). Use the kicad-unified default install, not the nightly development build. See Step 4 for advanced optional details on library installation.
  • Git is also cross-platform. If using Windows, I would recommend the impressive Git for Windows project for a more useful, fully-featured experience.

The install documentation available at both these sites will be more complete than any description I can offer here. Once both programs are downloaded and installed, you can clone Brainbow's project template from our Github repository. The git clone command takes the structure `git clone {src directory} {target directory}`; for our project, use `git clone https://github.com/builtbybrainbow/kicad-starter.git {target directory}`.

Cloning a git repo is a special form of copying; when you clone a project, you get a copy of all the files included in the repo as well as the entire Git-tracked history of the project. By cloning our repo, you get a project directory already structured with our recommendations for using Git with KiCad. We'll cover more about the project structure in Step 6, or you can skip to Step 7 if you're itching to get working.

A few quick housekeeping tasks - run `git remote rm origin` to remove the link to the Github project you cloned from. Also, run `git commit --amend --author="John Doe <email@domain.com>"`, replacing the author parameter with your name and email. This amends the last commit (which in this case is also the first commit) and changes the author to you, rather than Brainbow.


Step 4: Installation Note: KiCad Libraries

One quick note about KiCad's library structure. KiCad provides a set of libraries maintained by the developer team for a wide range of electrical components. There are three main libraries:

  • Schematic Symbols: Symbols used for representing electronic components in a circuit schematic drawing.
  • PCB Footprints: 2D drawings representing the actual footprint (copper pads, silkscreen text, etc) to be used when laying out the circuit on a PCB.
  • 3D Models: 3D models of electronic components.

These libraries are downloaded along with the KiCad program suite you just installed. You can use KiCad without any more effort. However, for "power users", the source files for the libraries are stored in a git repository on Github, allowing users who want to stay up to date with the latest changes to clone the library repo's to their own machine. Tracking the libraries with git has a number of advantages - you can choose when you want to update your libraries, and updates only need to incorporate changes to the files, rather than download the entire set of library files again. However, you are responsible for updating the libraries, which can be easy to forget about.

If you'd like to clone the libraries, this site details the various Github repos KiCad offers. Git clone the libraries to your computer (ex: `git clone https://github.com/KiCad/kicad-symbols.git`), then open KiCad, select the menu bar "Preferences" item, and click "Configure Paths...". This lets you tell KiCad the directory path to look for each library in. These environment variables default to the path to the libraries installed with the KiCad installation; I took note of these values so that I could switch back to the default libraries if necessary. The KICAD_SYMBOL_DIR path should point to your cloned kicad-symbols library, KISYSMOD to the cloned kicad-footprints library, and KISYS3DMOD to the cloned kicad-packages3d library.

When you want to update the libraries, you can run a simple `git pull` command in the library repo which will tell Git to check for differences between your local copy of the library repo and the Github "remote" repo, and automatically update your local copy to incorporate changes.

Step 5: Git Fundamentals

Git is a complex and many-faceted program, with whole books devoted to mastering it. However, there are a few simple concepts that will help you understand how we're using Git in our workflow.

Git tracks changes to files using a series of stages. Normal changes take place in the working directory. When you are satisfied with the changes you've made to a series of files, you add the files you've changed to the staging area. Once you've made all the changes you plan to and staged all the files you'd like tracked in Git, you commit those changes to the repository. Commits are essentially snapshots of the state of the files in a repo at a specific time. Since Git tracks changes to files and stores these changes in commits, at any point you can revert a project back to the state it was in at any prior commit.

There are more complex topics, like branching and remotes, but we don't need to use these to gain the benefits of source control. All we need is to track changes to our KiCad design files with a series of commits.

Step 6: KiCad Project Structure

Let's take a closer look at the structure of the KiCad-Starter project you cloned earlier. It's divided into a number of subdirectories for easy organization:

  • Circuit: This folder contains the actual KiCad project files (schematic, PCB, etc). I don't rename this folder, but I do rename all the files inside with the name of the project (Circuit.pro => ArduinoMini.pro).
    • Circuit.pro: the KiCad project file
    • Circuit.sch: the KiCad schematic file.
    • Circuit.kicad_pcb: the KiCad PCB layout file.
  • Documentation: This folder is for storing documentation regarding the project. We have plans for improving this space in the future, but for now it contains a simple README file. Use it to store notes on the project for future you to review.
  • Fabrication: This folder is where you will store the gerber files that most fab houses will use for manufacturing your circuit board. We also use it to store BOM files and other documents that may be needed for manufacturing and assembly.
  • Libraries: This folder is for storing project-specific library files (we'll cover this more in a few steps).

You may have also noticed a few other files (particularly if you `ls -a` the directory). The .git directory is where Git does it's magic, storing the history of the repository. The .gitignore file is used to tell Git which files it should ignore and not store in source control. These are mostly backup files that KiCad generates, or a few different "generated" files, like netlists, which should not be stored in source control because they are generated from the source that is the schematic file.

This project structure is just a starting point. You should adapt it to fit your needs, and add sections as necessary. In some projects we've included a software folder or enclosure folder, where we stored models for 3d printing enclosures for the project.

Step 7: Using Git for KiCad Projects

We're finally ready to see how to use Git for tracking your projects. This Instructable isn't meant to teach you how to use KiCad (although I may do one in the future if there's demand for it), so we'll run through some trivial examples to show you how the workflow runs. It should be easy to understand how to adapt these ideas to a real project.

Open the kicad-starter directory, then run `git log` to display the commit history. There should be one commit here, the initialization of the repo by Brainbow. Running `git status` will tell you the status of files in your repo (untracked, modified, deleted, staged).

At the moment, you should have no changes in your repo. Let's make a change. Open the KiCad project and add a resistor to the schematic, then save. Now running `git status` should show that you've modified the schematic file, but haven't staged those changes for commit yet. If you're curious about what exactly KiCad did when you added the resistor, you can run the diff command on the modified file `git diff Circuit/Circuit.sch`. This will highlight the changes between the current version of the file in the working directory and the state of the file at the last commit.

Now that we've made a change, let's try committing that change to our project history. We need to move the changes from our working directory to the staging area. This doesn't actually move the files in the file system, but is conceptually a way of letting Git know that you've made all your planned changes for a particular file and are ready to commit those changes. Helpfully, Git provides some hints when you run `git status` for the next action. Notice the message `(use "git add ..." to update what will be committed)` under `Changes not staged for commit:`. Git is telling you how to move the changes to the staging area. Run `git add Circuit/Circuit.sch` to stage the changes, then `git status` to see what happened. Now we see the schematic file under changes to be committed. If you don't want to commit these changes yet, Git helpfully offers another tip: `(use "git reset HEAD ..." to unstage)`. We do want to commit these changes, so we run `git commit -m "Added resistor to schematic"`. This commits the changes with the provided message. Running git log will show this commit in the project commit history.

A few more tips about commits.

  1. Don't commit with every save. Commit when you feel that you've reached a point where your changes have somewhat solidified. I commit after I finish a schematic, not after every component addition. You also don't want to commit too infrequently, because remembering the context of why you made the changes you did 3 weeks later can be difficult. Figuring out when to commit is a bit of an art, but you'll grow more comfortable as you use Git more.
  2. Only store source (mostly). This includes the project, schematic, and layout files, as well as project-specific libraries. This can also include documentation files. Be careful when storing derived objects because they can get out of sync with the original source easily, and that causes headaches later on. BOM and gerber files get de-synchronized particularly easily, so are better avoided (although more detailed guidance is covered in Step 9).
  3. Commit messages are very useful, but well-structured commit messages are invaluable. This excellent article provides some guidelines for writing clear, concise, useful commit messages. Doing so may require using a command line text editor, which can me complicated for beginners (`git commit` without the -m message option will open a text editor). For most people, I recommend the Nano editor. StackOverflow has a good explanation of changing your editor


Step 8: Advanced: Semantic Versioning for Electronics

For the adventurous souls, the following tips are advanced ideas, gleaned from many hours of KiCad development. They aren't particularly useful on smaller projects, but they can really save you heartache as your projects grow in complexity.

In software, there is a concept of Semantic Versioning (semver). Semver defines a common naming methodology to identify software releases by "version number", following a pattern of "Major.Minor.Patch". To quote semver's spec, you advance the version number according to the following change categories.

  1. MAJOR version when you make incompatible API changes,
  2. MINOR version when you add functionality in a backwards-compatible manner,
  3. PATCH version when you make backwards-compatible bug fixes.

We at Brainbow use our own version of semver adapted to fit the needs of hardware projects. Our spec follows the same "Major.Minor.Patch" pattern, although our definitions of what changes fall under which category obviously differ.

  1. MAJOR version: used for significant changes to the circuit's core functionality (ex: switching processor from ATmegaa to ESP8266).
  2. MINOR version: used for component swaps that could affect circuit operation (ex: SPI flash swap with pin-compatible part that may have a different command set) or addition of some minor additional feature (ex: added additional temperature sensor).
  3. PATCH version: used for minor bugfixes that won't change the circuit operation (ex: silkscreen adjustment, minor trace layout adjustment, simple component swaps like 0603 capacitor to 0805).

In hardware semver, the version number is only updated on manufacture (just as in software, version numbers only change with releases, not every individual commit to a project). As a result, many projects have low version numbers. We've yet to have a project use more than 4 major versions.

Aside from the benefits in consistency and comprehensibility you get from switching to a well-defined naming system, you also gain benefits in firmware compatibility and customer satisfaction. Firmware can be written while taking into account the version of board it is targeting, and it can be easier to debug why a particular program isn't working on a particular board ("right, the 2.4.1 firmware doesn't run on 1.2 boards because we don't have ...."). Customers have also benefited from our hardware semver because customer service and troubleshooting is much easier with a defined standard.

Step 9: Advanced: Using Hardware Semantic Versioning

To use hardware semver in your own projects, we utilize a Git feature called tagging. When you first manufacture a board, that is the 1.0.0 version of that board. Ensure that you've committed all the changes in your project, then run `git tag -a v1.0.0`. This will open an editor so you can write an annotation message for this tag (very similar to a commit message). I include details about the manufacturing (who made the PCB, who assembled the board), which can be useful information later.

The release tag is added to the commit history and indicates the state of the files at the 1.0.0 manufacture. This can be particularly useful several revisions later when you need to refer back to this point for troubleshooting. Without a specified release tag, it could be difficult to figure out which commit was the most recent at the time of the manufacture. A 1.0.0 (and 1.1, 1.1.1, etc) tag let you specify that these specific source files were the ones used in a particular manufacturing run.

A note on Gerbers. Some fab houses require gerber files to make your board, and you can generate them with KiCad. These are derived objects, generated from the source .kicad_pcb file, and we don't normally version control derived files. We at Brainbow don't store gerbers in version control EXCEPT for when we tag a release. When we are ready to build, we generate the gerber files, store them in the Fabrication folder, and commit and tag. Then we remove the gerbers and commit the deletion. This may seem a little confusing at first, but it ensures that normal commits only store source files, and the tagged releases also store the exact files used to manufacture the boards. This has proven remarkably useful in tracking down manufacturing errors weeks later.

Step 10: Next Steps

Hopefully this introduction has taught you enough to start using version control on your own electronics projects. We didn't get to some of the more advanced topics, like version control for libraries shared between projects or feature branches. Still, version control is like eating your vegetables: you may not get what you think you should, but every bit you do get counts.

Brainbow is working on a more detailed guide to some of the more advanced features of our workflow. We hope to publish it sometime in the next few months. Follow us here on Instructables, and we'll be sure to let you know when you can read it.

Thanks for reading, and we can't wait to see what you make!

Electronics Tips & Tricks Challenge

Participated in the
Electronics Tips & Tricks Challenge