Pandorica

Git workflow for contributing to libvirt

May 07, 2016

This is my first post where I’ll describe the workflow to contribute a patch to libvirt’s core C library.

Libvirt uses git for version control and source code management. This post assumes that you are working on a linux machine, have git installed and have the basics(user.name, user.email etc.) setup.

The Patch Workflow

Patches are the medium of contribution when it comes to libvirt. Patches can be regarding anything like a simple one liner bug fix, changing docs or a large feature addition. The gist of the workflow is that you send in only the parts where you have made changes(usually via email) and reviewers apply(pull in) the patches instead of merging in whole branches like we do in Github’s pull request based workflow. Once you have sent the patches, the maintainers or reviewers will give some feedback or suggest some changes, or if they are comfortable with the changes you have made, they will apply the patches. Sometimes, it might so occur that you have sent more than one patch and the reviewer might apply only some of your patches and might give feedback or might even entirely reject the other patches.

Below I will outline the steps involved in sending a patch to libvirt in the context of a bugfix.

Let us assume that you have found a fix to a bug numbered xyz in the bugzilla tracker and you are interested in sending in the fix. Firstly, you open up a terminal and clone the git repository obviously.

$ git clone git://libvirt.org/libvirt.git
$ cd libvirt

Now that you have the latest source code, you are good to add in your fix. For fun or just as an exercise, you can try compiling the source yourself. More on compiling libvirt’s source here.

$ git checkout -t origin -b bugfix_xyz # Create a new branch which tracks origin
# Open your favorite text editor, add the relevent changes in your branch, do
# not commit yet. Read on for more about committing your changes. Once you have
# made the changes, make sure that the changes you have written don't break any
# already working stuff. In case of libvirt, the least you have to do is to get
# the tests to pass without any warnings. More on testing your changes against
# libvirt's test suite http://libvirt.org/compiling.html
$ make check # standard test suite of libvirt
$ make syntax-check
$ make -C tests valgrind # checks for memory leaks and uninitialized variables.

Once you get all the tests to pass, you can move on to commit your changes.

Committing your changes

Once you have made the relevant changes and the tests pass after your changes, you are ready to commit your changes. To do so:

$ git add <files that contain your changes>
$ git commit -s
# The above command will open up your favorite text editor (vi by default), and
# you can add in your commit message and details about the commit. The `-s`
# switch is to sign off the commit.

However, in the development of libvirt, patches are only accepted against the current master, and not any release version. So you need to commit on top of the latest changes, which would require rebasing your branch with the origin.

$ git checkout master
$ git pull
$ git checkout bugfix_xyz
$ git pull --rebase
# The above command will sync your branch with the master, which has just been
# synced with origin, and then replay your commits on top of it. This step might
# require you to fix any conflicts that might occur.

The above steps assume that you are adding all your changes in a single commit. Lots of people like to make incremental commits in small steps. What they will have to do in order to send in a patch is to squash multiple commits into a single commit. The reason for the squashing of multiple commits is explained in the next section. To squash the commits, carry out the above rebasing step and:

$ git rebase -i
# This will open up your favorite text editor. Pick the first commit and squash
# the rest of them, i.e., change the first word on every line except the first
# line to squash. This tells git that you want to squash all of commits with the
# word squash into the first commit which has the word pick. Save the file and
# close it, which will open up another file where you get to edit your commit
# message. Edit the message accordingly and save and close it. This completes
# the squashing step.

We are now set to generate patches out of our changes.

Creating and sending patches

Libvirt accepts changes in the form of patches. Once we have committed our changes, generating patches from it is very trivial. Assumming you have rebased your changes on top of upstream(origin), patches are generated by:

$ git format-patch master

The above command will generate patches out of your commits for submission via e-mail. Refer the docs for further details about the format-patch command.

There should be a file 00*.patch. It is a standard text file and you can open it in your editor to have a look. It contains enough information about the commit that it was generated out of like the diff, the commit message etc., along with some metadata.

Coming to the reason about squashing multiple commits into a single commit, if one reads the man page of format-patch, it clearly mentions that one patch file is generated for one commit. Now many open-source organizations, including libvirt require that compilation from source should be clean after each patch, and the test suite must pass as well. Also, in case of more than one patch being submitted, intermediate patches must compile and not cause failures against the test suite.

I’ll explain the above with an example. Suppose while creating a fix for the bug xyz, you made incremental commits c1, c2 and c3, where c1 and c2 were simple intermediate commites, which along with c3 constitute the whole fix, i.e., source compiles and test suites pass after the commit c3 is made. If you generate patches directly without squashing, three patch files will be generated, say p1, p2, p3 corresponding to c1, c2 and c3. Since this breaks the requirement of intermediate patches not breaking the test suites and compiling cleanly, we have to squash commits c1, c2 and c3 into a single commit and then generate a single patch file out of it, which would meet all the requirements of a patch.

However, if you are working on a big feature or bugfix, that does not make sense to be added in a single commit and would be difficult as well to do so, it is encouraged to break up the changes into a series of logical commits, provided that the source compiles cleanly and the test suites pass after each commit, the reason behind this requirement being that the source should be such that the git bisect can be run to trace a broken commit if any. Once you have a series of commits c1, c2, … which meet the above requirement, you can generate patches out of them the same way as above; rebase the current branch with origin, and then use git format-patch to generate the patches. Multiple patch files will be created this time, each patch corresponding to one commit.

A Note about using git-notes

As I said above, the *.patch files generated are simple text files, and can be viewed in any standard text editor. However, editing the patch files by hand is discouraged, for every part of the file is structured to a particular format. Although there is one place where one could edit the patch files by hand, which would be between the --- and the diffstat(which mentions what files have been changed and by how many insertions and deletions etc.). Generally, this is the place to add more details or notes about the patch that you don’t want to or could not include in the commit message. An example of that would be to simply list down the changes being made in the current version of the patch as compared to the previous versions of the patches, or adding a note regarding something that has to be done in the future etc. Again, one must be careful with editing patch files in the text editor, even for the purpose of adding notes. Instead, what one could do, and what one should do is, to keep in mind the fact that git is awesome and use the built-in tool that git comes along with, git-notes.

From the docs of git-notes, git-notes adds, removes, or reads notes attached to objects, without touching the objects themselves. You can refer to the docs itself for more description and examples, although I will give a brief rundown of how to use git-notes to add notes to your patches. Say you want to generate patches for a series of commits c1, c2, … and want to add notes in the patch files that will be generated. To do so:

$ git notes add <sha of the commit you want to add notes to>
# The above will open up a text editor and you can start writing a note. Once
# you are done, save it and the note will be saved corresponding to that commit.
# If you are generating patch for a single commit, then you can omit the <sha>
# assuming that the HEAD is pointing to the commit you want to add a note to.
# Repeat the above command for all the commits that you want to add a note to.
# Next, generate the patches the same way as above, but pass a --notes option to
# tell git to add the notes from commits to their corresponding patch files.
$ git format-patch master --notes # As taken from the docs
# The above command will generate the patches as done earlier, but also tell git
# to add notes saved for the commit sha's to the corresponding patch files. You
# can open the patch files and observe that the notes have been added after the
# --- and before the diffstat.

Once you have the patch[es] ready, submit them to the libvirt’s mailing list by git send-email. Some linux distros require you to install a separate package git-email to be able to use this command.

# First, we configure the email specifics
$ git config sendemail.smtpuser <email>
$ git config sendemail.smtpserver <your smtp server> # eg., smpt.gmail.com
$ git config sendemail.smtpencryption tls # or ssl
$ git config sendemail.smtpserverport 587 # 465 for ssl
$ git config sendemail.to libvir-list@redhat.com # mailing list to send patches

Having configured that, send the patches simply by:

$ git send-email --cover-letter --annotate --no-chain-reply-to *.patch
# Omit the --cover-letter if you are sending a single patch

Refer the docs for send-email for more info on the options.

And that is it; this will send your patch to the mailing list. If you receive any feedback or comments, modify accordingly and follow the same procedure to generate the patches. In the format-patch step, add --subject-prefix="PATCH v2" to create the second version of the patches.

Please send across a mail if there is any error in this post or a step is described wrongly.