Active Directory | Apache | Astrology | C | Citrix XenServer | Command line | Conference | Debian | Development | Django | Emacs | Fedora | GLib | Gentoo | Git | Gnome3 | Heartbeat cluster | Kerberos | Linux | Monitoring | OTRS | Oracle | PHP | Red Hat | SELinux | SSH | Symfony | Technology | Testing | Windows | Wordpress | Zabbix |

Using Git bisect to find the first good commit

Few months ago we “implemented” a bug in our software, which was released to the customers. We continued development for two weeks when the first customer ticket arrived about the bug. We successfully reproduced it with the customer’s version, but not with the development sources; it turned out that one of the developers unconsciously fixed the bug. The devs spent some hours finding where the fix lied before coming to me like “There is git-bisect which we can use to find the commit where we messed up things. Is there a way to find where we fixed it?”

For those who don’t know this feature, you have to mark a known “good” and “bad” commit, then git-bisect will go through the commits between this two, present you the corresponding snapshots, and you have to mark each of them as “good” or “bad”. At the end, you will get a commit hash where the bug first occured.

As it turned out, our developers’ problem rooted in the naming convention of git-bisect: they assumed that the “good” commit must be a working one, while a “bad” one must be the buggy. In this case, we did the following:

The commit with the customer’s release tag was marked as good (even though this had the bug), and the latest commit on our development branch was marked as “bad” (even though the bug was fixed by then). Now with every snapshot presented by git-bisect we had to do the opposite what you usually do: mark commits still having the bug as “good”, and commits that don’t as “bad”. At the end, we had the hash of the commit that fixed the bug (among some other things; luckily, the developer who pushed that commit had a workflow that introduced a lot of cherry-picking and squashing before the push, so he could easily find the bit that actually fixed the problem in his local repository with the same technique).

This StackOverflow answer suggests the very same, but with some aliases:

  1. [alias]
  2. bisect-fixed = bisect bad
  3. bisect-unfixed = bisect good

Rounding numbers to N decimals in Emacs

I have recently faced a problem, where I had a bunch of SVG files with a large amount of fraction numbers in the path definitions. These images were displayed in small size, so this amount of precision was irrelevant, and these numbers took almost half of my SVG images’ size. So I created an Elisp defun to round these numbers to 2 decimals:
  1. (defun get-number-at-point ()
  2. (interactive)
  3. (skip-chars-backward "0123456789.-")
  4. (or (looking-at "[0123456789.-]+")
  5. (error "No number at point"))
  6. (string-to-number (match-string 0)))
  7. (defun round-number-at-point-to-decimals (decimal-count)
  8. (interactive "NDecimal count: ")
  9. (let ((mult (expt 10 decimal-count)))
  10. (replace-match (number-to-string
  11. (/
  12. (fround
  13. (*
  14. mult
  15. (get-number-at-point)))
  16. mult)))))
This finds the first digit of the number under point (the cursor), and reduces its digits to the given amount (or the number given with C-u). It has some drawbacks, though, as it cannot handle exponential forms (e.g. 1e-1234), but these were rare in my case, and its hard to iterate through all numbers. I will come over this latter problem soon(ish).

NyanMacs

I was a Vi/ViM user for years. For several reasons I had to change to Emacs now and then. And then, I found this. I surrender. Emacs is just better. (And it's working even in plain text mode without graphics)

Registering an enum type in GLib, glib-mkenums magic

In this post I said I will get through the GLib Makefiles to add an enum type to GLib in a more sophisticated way.

In my other project, SWE-GLib I already used this method. The following two rules in Makefile.am create gswe-enumtypes.h and gswe-enumtypes.c.

  1. gswe-enumtypes.h: $(gswe_enum_headers) gswe-enumtypes.h.template
  2. $(GLIB_MKENUMS) --template $(filter %.template,$^) $(filter-out %.template,$^) > \
  3. gswe-enumtypes.h.tmp && mv gswe-enumtypes.h.tmp gswe-enumtypes.h
  4. gswe-enumtypes.c: $(gswe_enum_headers) gswe-enumtypes.h gswe-enumtypes.c.template
  5. $(GLIB_MKENUMS) --template $(filter %.template,$^) $(filter-out %.template,$^) > \
  6. gswe-enumtypes.c.tmp && mv gswe-enumtypes.c.tmp gswe-enumtypes.c

$(GLIB_MKENUMS) is set in configure with AC_PATH_PROG([GLIB_MKENUMS], [glib-mkenums]).

This approach requires the GNU Autotools (you can get rid of it by changing $(GLIB_MKENUMS) to the path to glib-mkenums binary), and two template files, one for the header and one for the code. $(gswe_enum_headers) contains a list of all the header files that have enum types defined throughout the project.

  1. /*** BEGIN file-header ***/
  2. /* gswe-enumtypes.h - Enumeration types for SWE-GLib
  3. *
  4. * Copyright © 2013 Gergely Polonkai
  5. *
  6. * SWE-GLib is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * SWE-GLib is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this library; if not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef __GSWE_ENUM_TYPES_H__
  20. #define __GSWE_ENUM_TYPES_H__
  21. #include <glib-object.h>
  22. /*** END file-header ***/
  23. /*** BEGIN file-production ***/
  24. /* enumerations from "@filename@" */
  25. #include "@filename@"
  26. /*** END file-production ***/
  27. /*** BEGIN value-header ***/
  28. GType @enum_name@_get_type(void);
  29. #define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
  30. /*** END value-header ***/
  31. /*** BEGIN file-tail ***/
  32. #endif /* __GSWE_ENUM_TYPES_H__ */
  33. /*** END file-tail ***/
  1. /*** BEGIN file-header ***/
  2. /* gswe-enumtypes.c - Enumeration types for SWE-GLib
  3. *
  4. * Copyright © 2013 Gergely Polonkai
  5. *
  6. * SWE-GLib is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * SWE-GLib is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this library; if not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "swe-glib.h"
  20. #include "gswe-enumtypes.h"
  21. #include "@filename@"
  22. /*** END file-header ***/
  23. /*** BEGIN file-production ***/
  24. /* enumerations from "@filename@" */
  25. /*** END file-production ***/
  26. /*** BEGIN value-header ***/
  27. GType
  28. @enum_name@_get_type(void)
  29. {
  30. static volatile gsize g_define_type_id__volatile = 0;
  31. gswe_init();
  32. if (g_once_init_enter(&g_define_type_id__volatile)) {
  33. static const G@Type@Value values[] = {
  34. /*** END value-header ***/
  35. /*** BEGIN value-production ***/
  36. {
  37. @VALUENAME@,
  38. "@VALUENAME@",
  39. "@valuenick@"
  40. },
  41. /*** END value-production ***/
  42. /*** BEGIN value-tail ***/
  43. { 0, NULL, NULL }
  44. };
  45. GType g_define_type_id = g_@type@_register_static(
  46. g_intern_static_string("@EnumName@"),
  47. values
  48. );
  49. g_once_init_leave(&g_define_type_id__volatile, g_define_type_id);
  50. }
  51. return g_define_type_id__volatile;
  52. }
  53. /*** END value-tail ***/

List Git branches and their remote tracking branches side by side

I had a hard time following my own branches in a project. They got pretty numerous, and I wasn’t sure if I pushed them to origin at all. git branch -a can list all the branches, including remote ones, but, as my list grew too big, it was impossible to follow it any more.

Thus, I have created a small script called git-branches-with-remotes, which does the work for me. Its only requirements are git (of course), and the column command, which is pretty obviously present on every POSIX compliant systems (even OSX).

  1. #! /bin/sh
  2. COLUMN=`which column 2> /dev/null`
  3. if test -z $COLUMN
  4. then
  5. echo "\`column' is not found in PATH. Cannot continue."
  6. exit 1
  7. fi
  8. current_branch=`git rev-parse --abbrev-ref HEAD`
  9. for branch in $(git for-each-ref --shell --format='%(refname)' refs/heads | sed -e s/^\'refs\\/heads\\/// -e s/\'$//)
  10. do
  11. remote=`git config branch.$branch.remote`
  12. merge=`git config branch.$branch.merge | sed -e 's/^refs\/heads\///'`
  13. [ x"$current_branch" == x"$branch" ] && echo -n '*'
  14. echo -n "$branch"
  15. if ! test -z $merge
  16. then
  17. echo -en "\t"
  18. echo -n $remote
  19. echo -n /
  20. echo -n $merge
  21. fi
  22. echo
  23. done | $COLUMN -t

I just put it in my path, and git branches-with-remotes does the work!

Edit (16 August): I have added some code to mark the current branch (if any) with an asterisk. Also, I have put this script in a gist.

Edit (26 February, 2015): It turns out that git branch -vv shows the same information and some more: it also shows if the branches are diverged, and the first line of the last commit’s message.

:: Creative Commons License Copyright © 2012-2013, Gergely Polonkai :: Disclaimer ::
Fork me on GitHub