Un-commit in Git

I just accidentally made a commit in git that I didn’t want – I’d made several changes at once and wanted to commit them separately. Instead I did one big commit so I wanted to get back to a state where I had the uncommitted changes. The methods of undoing a commit (git reset and git revert) dont cut it here, as they just take you back to the previous commit, and lose the changes you made. Here’s what I came up with:

git show > ~/uncommit.patch # Take the commit I just made and store the differences in a patch
git reset --hard HEAD^ # Reset to the previous commit
patch -p1 < ~/uncommit.patch # Re-apply the changes

If you've got some changes that aren't committed yet that you still want to keep, you'll want to do make a second patch from the output of git diff before resetting.

Boogie Board Rip on Linux

I’m fed up of making notes on scrappy bits of paper that I lose, so with some money I got for Christmas I got myself a Boogie Board Rip. I’m not going to do a full-blown review here, but essentially it’s an etch-a-sketch on top of a portable graphics tablet. The graphics tablet bit is battery powered, and converts what you draw to PDF. The PDFs can be accessed by plugging the board into a PC via a Micro USB cable. Some people complain that it’s not very good for drawing, but I only wanted it for writing and it’s great for that.

After using the board for a couple of days I found this piece of software and this blog post. It turns out that as well as appearing as a USB storage device when plugged in, it also appears as a human interface device and spits out a stream of binary (32 bytes of it to be exact) for each event that occurs on the device (button presses, movement of the stylus, etc). With a bit of help from the aforementioned blog post I’ve managed to decode the binary and write a short Ruby script that reports what’s happened each time you do something.

The script as it stands at time of posting is shown below. The latest version is available on github.

    lsusb = `lsusb`
    if lsusb.split("\n").select{|l| l.include? "2047:ffe7"}.count == 0
        raise "Boogie Board Rip not currently connected"

        dmesg = `dmesg`
        bbdev = dmesg.split("\n").select{|l| l.match "2047:FFE7.*hidraw[0-9]"}.pop.match("(hidraw[0-9]+)").to_s
        raise RuntimeError if bbdev.empty? 
    rescue NoMethodError, RuntimeError
        raise "Boogie Board Rip detected, but device's path could not be determined"

    events = []
    threads = []

    thread = Thread.new do
        board = File.new("/dev/"+bbdev, 'r')
        while true do
            data = board.sysread(32)
            event = Array.new()
            data.bytes { |b| event << b }
            events << event
    threads << thread

    thread = Thread.new do
        previous = Array.new(32, 0)
        current = []
        while true do
            current = events.shift
            next if current.nil?

            if current[10] != previous[10]
                state = current[10]
                pstate = previous[10]
                lock = 32
                erase = 4
                wake = 2
                if (pstate == pstate | lock) && (state != state | lock)
                    puts "Board unlocked"
                elsif (pstate != pstate | lock) && (state == state | lock)
                    puts "Board locked"
                if (pstate == pstate | erase) && (state != state | erase)
                    puts "Erase released"
                elsif (pstate != pstate | erase) && (state == state | erase)
                    puts "Erase Pressed"
                if (pstate == pstate | wake) && (state != state | wake)
                    puts "Wake released"
                elsif (pstate != pstate | wake) && (state == state | wake)
                    puts "Wake Pressed"
            if current[3] != previous[3]
                state = current[3]
                pstate = previous[3]
                detected = 32
                contact = 1
                if (pstate == pstate | detected) && (state != state | detected)
                    puts "Pen Lost"
                elsif (pstate != pstate | detected) && (state == state | detected)
                    puts "Pen Detected"
                if (pstate == pstate | contact) && (state != state | contact)
                    puts "Pen contact lost"
                elsif (pstate != pstate | contact) && (state == state | contact)
                    puts "Pen contact detected"
            cury = current[4]+(current[5]*256)
            curx = current[6]+(current[7]*256)
            prey = previous[4]+(previous[5]*256)
            prex = previous[6]+(previous[7]*256)
            if cury != prey || curx != prex
                puts "Pen moved from ("+prex.to_s+","+prey.to_s+") to ("+curx.to_s+","+cury.to_s+")"
            previous = current
    threads << thread

    threads.each{ |thread| thread.join}
rescue RuntimeError => error
    puts error

It’s very rudimentary at the moment, and needs to be run as root so the device can be accessed, but hopefully with a bit more hacking I’ll be able to get something graphical up and running. It also strikes me that you should be able to use the Boogie Board like a Wacom tablet if someone would be good enough to write a device driver. It’s a bit beyond me but the information’s pretty much all there in the script!