{ Hi! I'm Mike }
I'm a core developer with The Horde Project and a founding parter of Horde LLC - the company behind the world's most flexible groupware platform. This is my personal blog full of random thoughts about development and life in general.
August 14, 2011

git case sensitivity madness

I do most of my development work on my MacBook. The Mac, by default, uses a case preserving, but insensitive filesystem. This is, by far, by biggest gripe about the OS. Combine this with Git, this leads to a lot of havoc, since git is case sensitive. Since Horde uses Git, this can bite anyone who develops on a similar filesystem. It was a huge issue back when we were refactoring like mad for Horde 4 since there was a lot of file renaming going on.

Nowadays, I rarely run into this issue, but it does still creep up from time to time (like today!), usually during a merge. I used to jump through all kinds of hoops involving setting/unsetting the ignore-case switch in git's config (very bad idea). Now, I've found the following to be a much better way of dealing with it.

$ git pull --rebase

remote: Counting objects: 203, done.
remote: Compressing objects: 100% (93/93), done.
remote: Total 143 (delta 81), reused 81 (delta 39)
Receiving objects: 100% (143/143), 49.49 KiB, done.
Resolving deltas: 100% (81/81), completed with 21 local objects.
First, rewinding head to replay your work on top of it...
error: The following untracked working tree files would be overwritten by checkout:
	passwd/lib/Driver/Adsi.php

Please move or remove them before you can switch branches.
Aborting

# As you can see, the file is present, but as the wrong case.
$ ls passwd/lib/Driver/
adsi.php

# To fix, we have to git mv the file to a different name,
# then git mv it back to the correct name
$ git mv adsi.php adsi.phpX
$ git mv adsi.phpX Adsi.php
$ git commit

# once all are taken care of, pull and rebase
# at this point there might be conflicts,
# but you can --ignore them during the rebase process.
$ git pull --rebase

CONFLICT (rename/delete): Rename passwd/lib/Driver/ldap.php->passwd/lib/Driver/Ldap.php in Fix case sensitivity issues on mac during merge and deleted in HEAD
CONFLICT (rename/delete): Rename whups/lib/Driver/sql.php->whups/lib/Driver/Sql.php in Fix case sensitivity issues on mac during merge and deleted in HEAD
Failed to merge in the changes.
Patch failed at 0001 Fix case sensitivity issues on mac during merge

When you have resolved this problem run "git rebase --continue".
If you would prefer to skip this patch, instead run "git rebase --skip".
To restore the original branch and stop rebasing run "git rebase --abort".

$ git rebase --skip

Hope this helps!

January 16, 2010

Git cherry goodness

With the recent flurry of development activity over at the Horde Project, there came an increase in the number of topic branches in our git repository.  One of the problems dealing with longer living topic branches is the question of how to keep the topic branch in sync with changes going on in the master branch. 

The best way to do this is to rebase the topic branch from master and then rebase your tracking branch against the remote topic branch.  The problem with doing this is that if you are using a post-receive hook to send out commit announcement emails, pushing your changes back to the server will result in duplicate commit messages being sent for the changes that were rebased from origin.  This makes it difficult to zero in on what the actual relevant change in the topic branch is.

After some digging around in the git documentation and some hacking on the script we use for commit messages, we have come up with a good-enough solution. The git cherry can examine the change sets between the two branches and detect if a specific commit on one branch is present on the other branch or not. What makes this so useful is that it doesn't compare commit ids, since these will be different, it actually looks at the diff of each changeset to see if they are the same change.

You can look at the full post-receive-email script we use by looking at our horde-support repository, but the basic idea is to call git cherry like so:

git cherry master [topic branch] 

and then iterate over the results, ignoring any commit ids that are prefixed with a '-'.

So now, my typical development session might go something like this (some commands added for clarity):

# Switch to master branch git checkout master
git pull --rebase

# Resolve, code, hack... 
git add
git commit
git push

 # Pull any new changes
git pull --rebase 

# Switch to my ActiveSync topic branch 
git checkout ActiveSync 

# Rebase it to keep it in sync with master 
git rebase origin/master 
git add
git commit

# rebase it against remote
git pull --rebase git push