Source control management

Version Control for Embedded Engineers

Synopsis - Embedded engineers often get in the mindset that they’re developing hardware. Hardware developers even think they’re developing hardware, too - imagine that. However, the processes by which commercial firmware and hardware are developed have a lot more in common with software development than digging out the breadboard and making blue smoke. Even in commercial environments, practices long established in software engineering are often lacking in firmware and hardware development. One of these practices includes good version control. Every asset of embedded product development including schematics, PCB layouts, firmware, test instrument configurations, simulations, test results, parts lists and sources, can and should be under version control. In many cases, there are more types of IP assets to track for a hardware / embedded project than for a pure software project.

This article shows how to deploy one of the best version control systems,
git, for embedded hardware and software developers. The example I’ll use is to version control Eagle PCB CAD designs, but the example is generally applicable to any dimension of embedded development regardless of design tool.

Motivation

Even if you’re a lone-wolf developer, it can be extremely useful to be able to quickly tell when a bug was introduced or regenerate versions of PCBs you made months or years prior. Sure you could make pure directory snapshot backups and try to manage all your assets on the file system, but there are better ways that make collaborating on designs as well as backup, distribution, reversion, and testing processes a lot easier. And even if you’re a lone-wolf, it’s easy enough to set up that you’ll sleep better at night knowing you’ve got your hard work under version management.

If you’re on a hardware or firmware development team, you’ll have all the same problems as any pure software project has plus more. You have an even bigger need for the benefits a version control system like git can offer.

Anecdotally, there’s a local company with which I’m familiar that is involved in a substantial FPGA crypto project for the federal government. Recently, they lost days of time and effort because a developer made a change in the HDL that another developer wasn’t aware of. All this HDL lived on a common file share, so while it’s backed up and accessible by all, there was no notification and no process for change management around what is essentially software - FPGA HDL code. Even though the ultimate product is a hardware product, the real intellectual property is actually software, HDL in this case, and therefore, it should be treated like software.

Because so much hardware product development boils down to software in the form of HDL, firmware, schematics, PCB layouts, test instrument and test fixture scripts, for better or worse the overriding practice that governs hardware processes looks more like a software process. So, it makes sense to apply good software processes to managing the assets of hardware and embedded development.

Better management starts with ‘git’, the same version control system used to manage the 1000+ commits daily from the rollup of 100’s of developers for the Linux kernel. I’m assuming you’re reading this because you don’t have any version control established. If you do, it may not make sense to convert to ‘git’ if you’re already happy with your processes. However, if you’re starting a new project or have no process in place now, do yourself a favor, do a fast-forward - start with ‘git’.

Start with the Star Model

Git is capable of many different models of version management - the most advanced being completely distributed. In git, every repository can be a master - peer level with the original. However, I’m going to suggest the classic “Star” model to start with. The star model is a central source control server with many individual contributors all pulling from and pushing changes to the central system.

Git goes a step further in the Star model than other systems, however. Any developer is able to make local changes, keep those local changes versioned locally and only push changes when he or she’s ready to push to a wider group. No longer do you have to take a snapshot of the central tag, do a huge week-long or month-long binge of changes, then do a big-bang checkin at the end. You can be versioning your work locally, making changes, testing, throwing away things that don’t work, pulling current changes from others, reverting to a working version - all the things that make version management great. You can do these locally, without disrupting the work of others until your solution is fully baked and not lose the power of version control.

This local versioning and testing large number of changes locally before committing to a central server is often called micro-checkins. It simply a model for maintaining the benefits of version control without having to make every commit “official” and public until you’re ready to do so. Git supports the micro-checkin model superbly.

The Central Server

Git’s DNA is Linux - originally developed by Linus Torvalds. Git clients are available for all the popular platforms, but this article is about setting up a git server on Linux, specifically Ubuntu, so git clients of any common platform ilk can pull and push code .

Here’s the scenario:

We have an existing directory of embedded development assets that we want under version control. We want to access these items from any machine that has access to the server from any platform or client type (Windows, OS X, or Linux.) We want to be able to make a change, check it in locally, and when we’re ready, or even perhaps connected to the network again, push any changes to the central server.

In this example, I’ll show you how to put your Eagle PCB design files under management from a Mac OS X client where all version control transactions are safely done using secure shell.


On the Server

0) Install - The first thing you need to do, besides insuring you have an account and sudo access on the Linux server is install git. Fortunately, installing git on an Ubuntu linux server is trivial. Login to your Linux server, then type:

sudo apt-get install git


This gives you everything your Linux machine needs to be either a git client or server. There are ready-made binaries for many other platforms as well - I’ll leave it to you to follow the installation instructions relevant to your central server platform.

Other server assumptions:
0a) You have it on a network and can access it by secure shell.
0b) You have enough disk space with some headroom to store a code repository

1) Find ample space on the server to start the git repository. In this example, I’ve chosen: /var/git and made that directory. You will need to be root to create the directory in /var but you can change the permissions to be whatever you need. You can start with a single user and expand it to a git group later if you wish.

sudo mkdir /var/git


2) Copy the existing directory you want to manage to the server. This directory either already exists on the central Linux server or on your local machine. In either case, you need to start with your existing assets on the Linux server. You can put this directory anywhere you have permissions on the central server.

I have a directory called ‘eagle’ in which I keep all my Eagle CAD designs. Use scp to recursively copy the directory to the central server. As an example, if your remote server is called mybogusdomain.com and your user name is ‘joebob’ and your existing assets exist on a local machine, cd to the directory above the directory you want to copy to the central server and then secure copy it to the central server.

Wow that sounds like a sentence out of Dr. Suess, but it’s really this easy. On the Client machine where you have your original tree (ie: ~/Documents/eagle):

cd ~/Documents
scp -r eagle  joebob@mybogusdomain.com:/home/joebob/


This will recursively copy the eagle sub-directory under the local ~/Documents directory, to your account on mybogusdomain.com.

At this point, that’s all you have: a copy of the directory you plan to put under management. You don’t have any version control going yet.

3) Back over on the server, you need to create a git repository and populate it with the initial directory structure. This is where it first got tricky for me when I was first getting to know git. It would be nice to just add all the files in the directory you uploaded into a git repo on the central server and just use that, but if you do this, you’ll only be able to clone the repository and a developer will not be able to push changes back to the central server.

You have to create what’s known as a Bare repository in order to allow remote developers to push changes to the central system.

In order to do that, follow these steps:

3a) Add all your files to a local git repository on the central server, then clone it as a bare repo.

After logging into the central server as your username, go to where you uploaded your asset directory in step 2), then create a git repo and add your files. Carrying the example through, login to the server as username: joebob and go to the directory: ~/eagle:

      cd ~/eagle
      git init
      git add .
      git commit -m"initial checkin"


At this point you have a little localized git repo in your ~/eagle directory, but you still do not have a git repo you can both pull from and push changes to.

3b) Next, clone that local repository with the --bare option to create a centrally accessible git repository that you can pull from and push to. You do this from the space where you will permanently store the master tree: /var/git in this example:

cd /var/git
git clone --bare ~/eagle eagle


This creates a bare repository in the /var/git directory called
eagle.

The last parameter is optional but if you leave it off, it will create a directory named ‘eagle.git’ which I always find to be redundant and is something that will forever be required when you specify the URL to access the repo. So, I like to explicitly name the actual directory, usually after the project directory itself, in this case, just ‘eagle.’

Now you have a centrally accessible repository that you can both push and pull. This is considered the “Remote” repository. I’ve been calling it the central repository, but in git jargon, it’s the remote.

4) Add the remote repository location information to the git repo you made for yourself and from which the actual remote was cloned. This lets you try out some git using the tree you uploaded and effectively turns your uploaded tree into a full-fledged development workspace if you would like.

4a) Add the remote to the local development workspace git repo:

cd ~/eagle
git remote add origin /var/git/eagle

this tells your localized git repository that it can pull from a remote or push to a remote and where that remote is.

4b) Edit .git/config

Add these lines to your ~/eagle/.git/config file:

[branch "master"]
     remote = origin
     merge = refs/heads/master


This tells git how the initial branches are set up both locally and remotely.

You’re done. Now you can both push and pull a centrally accessible git remote repository and you have a full-fledged push/pull workspace from which you can update or make changes.

5) Next: HOWOTO Pull a remote git repo to a local machine.

Install the appropriate git client for the client platform you’re planning to use. For Windows users, use the msysGit installer - You can download msysGit from here: http://code.google.com/p/msysgit/downloads/list

For Mac OS X users, pull git from: http://code.google.com/p/git-osx-installer/downloads/list?can=3 The full msysGit installer for Windows includes all the environmental things you need include a subset of cygwin and openssl.

Warning: if you use the msysGit client in GUI mode, make sure any SSH URLs, as in cli the examples below, you specify use the login name of the Linux server.

5a) Assume you have already installed a git client on your local machine, even for Windows, there’s a git client that uses a cli, so I’ll stick with the CLI since it covers all the client platforms:

5b) Clone a remote repository so you have a local version of it you can modify and push back if you want. Find a directory on your local machine where you want to populate the tree...lets say $HOME/git - from a bash shell (cygwin on Windows):

mkdir ~/git
cd ~/git
git clone ssh://joebob@mybogusdomain.com/var/git/eagle


After a little bit of time where you can see some progress, git will bundle up the remote tree, securely transfer it, and make you one like it locally. Your new local repository is in ~/git/eagle.

From this point on, you can run Eagle CAD for PCB design locally, make changes in your designs, save them, commit them, and have them under version control. There’s one more step to go end-to-end with your designs so that others can see your changes - namely, you need to push your changes back to the central server.

6) Committing and Pushing

Lets say you modified your Eagle schematic and saved the file. Then you regenerated your PCB board layout and finally, regenerated all the Gerber files for your CAM jobs, possibly even using
gerbmerge to create an entire panelized design you’ll submit to the board fab house. You’ve changed quite a bit of stuff that you want versioned so you can go back if you need.

Each time I get ready to submit a board design to
BatchPCB or another board fab house, I commit and push my changes in order to make sure that if I need to resurrect the design later for debug or further production, I can go right to it. (Actually, there are ways to make an easy to remember tag or label for a specific version of all the files at a given point in time, but for git, it’s easy to pull designs based on dates if you want, too.)

I can put a date, version string, or even tag name on the silkscreen of my PCB and use that same date or tag name to retrieve the design later - but only if I commit and push first.

Here’s how to commit and push after your design changes and CAM file generations. On the client side:

cd ~/git/eagle
git add .
git commit -m"Made massive changes"


The “git add .” (the dot is important) tells git to add any new files created to the repo and note any modifications made to existing files. You always have to
add before you can commit any changes.

As you surmised in the example above, the -m option lets you supply a note about what changed to remind you later what you did. I’ll often write things like “moved the RJ45 and rotated the resistor net, regenerated board layout.” If you need to write a tome, don’t use the -m option and let git launch your default text editor instead. (set GIT_EDITOR environment variable in your shell to point to vim, emacs, or whatever programmer editor you like.)

At this point you have versioned your Eagle files locally and could revert to any date or time if you needed to. Every time you commit, you have the ability to exactly reconstruct your tree at that point in time any time in the future.

Now, when you’re ready to make sure the rest of the world also has your changes (other developers on your team) you still need to push them to the central server:

git push


Push will conveniently wrap up all your changes, compress them and safely transfer them to the remote repository over ssh.

After this push has completed, your Eagle board changes are not only committed to your local repository (previous to the push) but they are also on the remote repository as well. Anyone else with access to that repository will be able to pull your changes assuming they’ve cloned the same repository and have credentials to access that server.

If someone else was working on the same Eagle project at the same time you were, you’ll have some conflicts, unfortunately. Git doesn’t use a locking mechanism like some SCM’s so there’s no way for it to know if two people have modified a binary file, for example, until both try to commit to the remote repository. If that happens, just like if two developers had tried to modify any binary, whether it’s a PNG file or a HEX firmware file, the two developers need to come to a conclusion about how to resolve it. Usually this involves lots of blood and large quantities of beer and other vices before everyone’s feeling right about the world again. It’s not really something the version control system can do to help merge a binary.

7) Pulling

If you’re working on a joint project and other developers are also making changes to other parts of the project - say someone’s working on a daughter card PCB and you’re working on the base board and the firmware, you may occasionally need to get their changes to review or at least keep current. Pin assignments can change, dimensions can change, power requirements might change - you need to stay up to date with what else is going on in the project. You need to pull the latest changes from the remote repository:

cd ~/git/eagle
git pull


I will often need this even as a lone developer because I have multiple machines on which I develop - my desktop, my laptop, and the central server itself. I spend most of my time on my desktop, but if I’m going to go off-road, I’ll pull the latest onto my laptop so I can develop, even without a network connection. I can work, do my micro-checkins on my local laptop, and when I get back to a network connection, do a push to synchronize my changes to the central server.

I also want to share a design with my business partner, so to do that, after he’s cloned the Eagle repository, he can stay up with my changes on a daily or hourly basis if he wants by doing a ‘git pull’. Vica-versa, I can also get any of his progress and changes.

8) Backup

On the central server, if the /var directory isn’t already being backed up in its entirety, it would be a very good practice to put an rsync backup process on a cron job. I have a cron
rsync of /var/git going every hour to copy changes in /var/git to an external backup drive so that the worst that can happen if I lose the disk for the remote repository is about an hour’s worth of work. Theoretically, I could have another cron job that does a git pull every hour to get the latest repo - that repo could then become a master in the event of a catastrophic failure of the original server (assuming the git pull was going to an external drive or other machine.) Finally, one could rsync the /var/git directory to another linux box entirely across the network or have it doing periodic git pulls also. It’s a very redundant architecture for backup purposes.

Summary

This has been a very quick introduction to using ‘git’ for embedded development. It’s very similar to using git for any type of software development and that’s pretty much the point of the article - hardware and firmware asset management can be easily accomplished with the same powerful tools and best practices used by software engineers.

I hope this has inspired you to build good software practices into your hardware development methodology. In future articles, I’ll try to cover what types of embedded development assets are appropriate for version control (not all are), how to tag, branch, and revert as needed.

Additional Resources

Here are some very good additional resources that will help you as you become accustomed to ‘git’:

http://www-cs-students.stanford.edu/~blynn/gitmagic/index.html

A fairly lengthy, but quite high quality video tutorial on git can be found here:
 http://bit.ly/SABw7  

One of the best books on git is Version Control with Git http://bit.ly/oriellygit

The latter book has one of the best explanations I’ve seen of why you need a --bare repository to implement a central server model and was the critical piece of info I was missing when I first tried to implement ‘git’.

Comments and Corrections

If you have ideas for future articles around the topic of git and version control for embedded developers feel free to tweet me at @
esawdust. Same if you have any comments or corrections you see to make on this article - tweet me @esawdust.

Alternatively, you can
contact me directly.
asdfasdf