Lately, a post on writing good Git commit messages and the subsequent Reddit discussion caught my attention. I fully agree with each and every point made and in fact alway try to convince colleagues and friends to follow this model. However, what to do if you are happily coding away, churning out commit after commit and then end up with a larger number of commits with summaries such as “Fixes this” or “Forgot to add that”? You use an interactive rebase, a Git feature that is surprisingly unknown among my fellow peers.

As the name suggests, an interactive rebase is a rebase done in a more intuitive way. That does not sound like a lot because most people assume a rebase to be taking commits from one branch and putting them on top of a commit of another branch. However, with the default workflow an interactive rebase happens on the same branch. To initiate such a rebase, simply find a suitable range of commits that you want to remove, edit or combine (e.g. from HEAD down the last ten commits) and type

$ git rebase -i HEAD~10

Your favorite editor will then be opened with the list of commits in chronological order. You can remove commits simply by removing the corresponding line or reordering commits by moving lines up and down. Concerning the Git commit messages, you can edit a message by replacing pick with reword (short r) or edit (short e) which also gives you the opportunity to change the author of a commit. To combine commits, you can either use squash (short s) which creates a single commit out of all the marked commits and the one commit leading to the first squash commit. fixup does the same but will use the commit message of the previous commit. These tools help to consolidate related commits to one logical commit.

Interactive rebase is a pleasant way of reorganizing the private history. In case you are using Vim, this can be an even more pleasing experience with a small plugin that I wrote some time ago.

To fetch a pull requests by its ID, I probably googled “github checkout pull request” a hundred times by now. Here is a simple Git alias which goes into the .gitconfig to make that a bit easier:

  checkout-pr = "!f() { git fetch origin pull/$1/head:pr-$1 && git checkout pr-$1; }; f"

Now it’s just a matter of git checkout-pr 42 to check the changes of pull request #42 on my local system.

Quick reminder how to use the alternatives system to call Neovim:

sudo update-alternatives --install /usr/bin/vi vi /usr/local/bin/nvim
sudo update-alternatives --install /usr/bin/vim vim /usr/local/bin/nvim
sudo update-alternatives --install /usr/bin/editor editor /usr/local/bin/nvim

… and to change it

sudo update-alternatives --config vi

pkg-config is a freedesktop standard and implementation that helps developers finding correct compile and link flags of dependencies. Despite its very low version number, it is the de facto method for determining said flags on the Linux desktop. An oft-forgotten feature of pkg-config is the ability of a package to expose arbitrary key-value meta data. This allows dependent applications to find data paths, plugins to know where to install themselves or determining tool paths.

Although CMake supports pkg-config for quite some time with its FindPkgConfig module, it only queries for the compile and link information. If you want to get a variable value you are out of luck. But fear not! Just stick this into a CMake module

find_package(PkgConfig REQUIRED)

function(pkg_check_variable _pkg _name)
    string(TOUPPER ${_pkg} _pkg_upper)
    string(TOUPPER ${_name} _name_upper)
    string(REPLACE "-" "_" _pkg_upper ${_pkg_upper})
    string(REPLACE "-" "_" _name_upper ${_name_upper})
    set(_output_name "${_pkg_upper}_${_name_upper}")

    execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=${_name} ${_pkg}
                    OUTPUT_VARIABLE _pkg_result

    set("${_output_name}" "${_pkg_result}" CACHE STRING "pkg-config variable ${_name} of ${_pkg}")

and you can easily query information like this

pkg_check_modules(GLIB glib-2.0)
pkg_check_variable(glib-2.0 glib-genmarshal)
message("Path: ${GLIB_2.0_GLIB_GENMARSHAL}")