My ssh agent admitted failure to sign a key!

This morning I decided to push some commits to a git repository at Assembla.com. Unfortunately I forgot my pass phrase for the specific key I generated and ended up with:

Agent admitted failure to sign using the key.
Permission denied (publickey,keyboard-interactive).
fatal: The remote end hung up unexpectedly

Which is fine, so I just create a new ssh key using the same name and it should work… Sadly it didn’t because some ssh-agent remembered that I don’t remember the pass phrase, so it reported that to the server. Then the assembla server drops the connection. After some searching on the internet I learned that you should use ssh-add [filename] to add the key to my ssh key chain. That worked fine and I can push my commits again.

Git-ting my branches up to date

Once upon a time a developer created a huge number, as far as more than five is considered huge, of feature branches; each of them based on a master branch and there wasn’t any significance to the actual timestamps of commits. “Soon”, he vowed, “… soon, I shall integrate all features! Soon but not today.” So he created a short script to update all branches to the latest and greatest of the master branch, adding some color for his own pleasure and gracefully failing the merges in case of any errors. The following piece of code was the result.

#!/bin/sh

# Lets define some nice colours
txtbld=$(tput bold)
txtrst=$(tput sgr0)
txtred=$(tput setaf 1)
txtwht=$(tput setaf 7)
txtblu=$(tput setaf 4)

# maybe I want a list of all failed updates
fails=""

git for-each-ref 'refs/heads/*' | \
   while read rev type ref; do
      branch=$(expr "$ref" : 'refs/heads/\(.*\)' )
      revs=$(git rev-list $rev..master)
      if [ -n "$revs" ]; then
         # Ok, so this branch isnt up to date, mention it
         echo -e "${txtbld}$branch needs update${txtrst}"
         git rebase master $branch
         if [ -d "`git rev-parse --git-dir`/rebase-apply" ]; then
            git rebase --abort # fail gracefully, so basically abort and mention it
            echo -e "${txtred}rebase aborted for branch ${txtblu}${txtbld}$branch${txtrst}"
            fails="$fails $branch"
         fi
      fi
   done

After months this turned out to be a very useful script. It saved him from tediously updating each feature branch he had and he never forgot to update them all.

Git rebasing to last public commit

As part of my workflow I make lots of small commits which I push to a central vcs once I finished a feature or fixed a bug. Often I find the need to re-base some of my commits interactively in git.

One reason is that I tend to forget to add something in a commit, so a fix-up I made afterwards needs to be squashed or placed closer to another commit. Another one is that changing the order of my commits will offer a better or more rational train of thought. And yet another reason is that at times my attention is so scatter I have two or more branches for features, futures or wip/dev. All those branches are based on a local master branch, which in turn is based on the central vcs’ master.

Before I used to type/copy/bash reverse-i-search the git rebase --interactive HEAD~N command. This could of course be shortened a bit to just git rebase -i HEAD~N, but it still left me with the task of figuring out how many commits I want to revise. Just guessing usually got me either to many or too little. Then I grew into the habit of firing up gitk, which in my case is an alias for gitk --all so I can see all branches, then count by hand how much commits I needed to revise and then use that number.

Although a slight improvement over just guessing it still left an error margin of 3 commits in the worst case. Then I noticed that I usually revise up to a branching point, so using git rebase -i branch/tag-I-started-to-deviate is shorter and saves time. For this to work its of course mandatory to keep feature branches short and regularly re-base all branches, including the local master branch, against its parent.

Stitched, modularized and converted

Yesterday I decided to finally follow through on a promise I made to my programming team of one person, me. The promise was to get some of the repositories for sub-projects into one bigger one. It makes sense to have all of them in the same repository because they are so dependent on each other. All of those projects are on GIT repositories,  so the logical choice is to use git-stitch-repo and stitch it up. What that little tool does is zip up (like in zipper) several repositories. Every source repository gets stuffed in a sub directory, so it looks clean and nice as well.

After the stitch I had to rename the tags, since all tags got an uppercase letter appended – A for the first repository I wanted to stitch, B for the second, etc. Then I saw that the history wasn’t completely clean. Previously there had been some branches and even a tag that pointed to a deleted branch but still persisted. Checking out that tag and suddenly you’re at no branch! Strange… Luckily it was just a throw-away branch, so I threw it away and went through all source repositories, cleaning them up. Stitched them up again, removed all clutter and what was left is a clean history and a neat directory structure. Awesome!

Some people still have to depend on subversion, since there is no easy and safe way to integrate GIT into Eclipse. I tried, but every once in a while stuff gets messed up for strange reason, no joy. So at one point the stitched needs conversion, but first I modularized the Maven projects it contained. Not that hard, so that took only a few Google searches and some trial and error (first time I ever made a modularized Maven project with parent POM). The result, very nice.

Time to convert to subversion. I used a Perl script called git2svn by Love Hörnquist Åstrand. It does the job well, except that it doesn’t do tags. I guess doing tags is harder or maybe the script wasn’t meant for what I used it for. I will ponder about redoing the convert with a modified script that can add tags or just add tags myself, preferring the former.

Why I like git-svn

By now everybody must have heard of GIT, the distributed version control system (dvcs). Having worked with CVS and Subversion (SVN) I must say that I’m now a huge fan of GIT. Well, maybe it’s better to say that I’m a fan of some of the features I tend to use a lot. Or at least the ones that seem more accessible to me in GIT than they do in SVN.

Granted, switching between branches is something possible in SVN too. A dvcs makes this stuff almost as easy as… well basically it is a short flurry of fingers across your keyboard. In case of GIT it’s:

git co -b branch-name

That command creates and checks out the branch. Now how easy is that? So if I want a new feature I can just make a branch and start working. Branches are also used to clean up deprecated methods and other clutter removed in a future version. So it’s kind of like a glimpse into the future. The only disadvantage is that you have to keep them up to date, which is very time consuming.

Sometimes you’re too busy programming and tend to forget to commit your code. Luckily it’s easy to commit only a chunk or line from your code using git-gui. That way you can still create some order in your commits and avoid the occasional tsunami of code. Smaller chunks are easier to swallow than large ones.

But not everybody wants to use GIT. So compromise is necessary. Which at the moment is a central vcs like Subversion so anybody can access it and then let me have my own little version control paradise island by cloning repositories with GIT.

I found out the hard way it’s easier to work on a clone of a SVN repository than on a clone of a GIT repository that clones a SVN repository. Too much places where stuff will go wrong. Other ways to screw up a perfectly organized system include forgetting which local branch you are working on. There are tools to restructure commits on GIT, but they are difficult to use. Once you structurally make mistakes those tools become routine, but structural mistakes turning into routine is bad.

Once I setup the aliases for certain often used commands with git svn life got easier. Before a commit I issue a svn rebase, for which I created an alias called dmerge. After that my code is back on top. Sometimes I have to manually resolve a conflict, but that’s OK.

In short, I like the way git gives me an extra buffer before I actually commit to the central SVN server on shared projects.