Code demo using git, part 2

Posted on Mon 17 October 2011 in Tools

In my first post about using Git for doing a code demo, I mentioned in passing that making local changes during the demo can mess things up. I thought I’d mentioned some more about cleaning up local changes.

The cherry-pick method

Cleaning up local changes when using the cherry-pick method is dead simple. Just run:

$ git reset --hard
$ git clean -fd

The first command effectively discards all unstaged modifications, restores deleted files and clears the staging area. The second command removes all untracked files, including directories thanks to the -d flag. (By the way, I assume you have a good .gitignore file so that no important files get removed by accident!)

The interactive rebase method

Resetting local changes, including newly added files, is done the same way as with the other method. However, if you have made local changes, then the rebase process has probably been aborted, and you are facing a message like the following one:

Aborting (2/3)
error: Your local changes to the following files would be overwritten by merge:
        world.txt
Please, commit your changes or stash them before you can merge.
Could not apply fcf2240... Second part of the demo

The problem here is that git thinks that it is done with the second demo commit already, despite the failure! Therefore, a git rebase --continue at this point (after cleaning up) tries to apply the third demo commit, which is definitively not what you want!

An option is to use edit instead of reword in the interactive rebase. That way, you can reset local changes all you want, and then simply do git rebase --continue to continue the demo. However, you need to do git rebase --continue in any case, so the simplicity of the interactive rebase method as originally envisioned sort of disappears…

Which method is best? - revisited

In the light of the possibly complications arising from local changes using the interactive rebase method, I’d lean towards the cherry-pick method! But perhaps we can automate it with a little script to make things simpler? Here’s one attempt (that mostly relies on git to do error-checking, so you might want to add some of that):

#!/bin/bash

set -o nounset
set -o errexit

if [[ $# -lt 1 ]]; then
    echo "Please specify a demo template branch!"
    exit 1
fi

branch=$1
bhead=$(git show -s --format=format:%H $branch)
mbase=$(git merge-base $bhead HEAD)
if [[ $mbase = $bhead ]]; then
    echo "The demo template head is reachable from this branch. Please switch branch!"
    exit 1
fi

for hash in $(git log --reverse --format=format:%H master..$branch); do
    git show -s --format=format:"Applying %h (%s)..." $hash

    echo "-- cleaning up..."
    git reset --hard
    git clean -fd

    echo "-- cherry-picking..."
    git cherry-pick $hash

    echo
    read -p "Press any key to continue..."
    echo
done

(Note to self: Don’t store a script that removes untracked files in the directory where you test run the script! :-))

How does the script work? Well, first it checks that the head of the specified demo template branch isn’t reachable from the current branch head. If it is, then most likely the current branch is the demo template branch. Next, it iterates over the list of commits in the demo template branch (in order of oldest first, thus --reverse). For each commit, it performs some cleanup before cherry-picking the commit. Then it waits for you to carry out the demo of that particular commit before continuing. Simple, right?

A final note about the script: It assumes that the demo template branch is branched out from master. If that’s not the case, the demo ghost will hunt you. :-)