Skip to content

Things your mum didn’t tell you about git

The other week we had a rather painful experience with git. My team is currently in the unfortunate position of having to maintain two long running branches. This is not a great idea in general but in our case we don’t have a lot of choice. Our merges have generally been somewhat painful so we resolved to perform them more often. The idea being we break the pain down into smaller more manageable hurts. Last week it was my turn, so I set about merging the code from the branch into master. After running the merge I noticed a lot of conflicts. At the time I thought this was strange considering it wasn’t that long ago that we’d run the previous commit. I fired up merge tool anyway and set about resolving the conflicts then started noticing in conflicts in stuff that should definitely not have been conflicting. At that point I stopped and looked back at the git log to try and see if I could figure out what was going on.

What I found was somewhat disturbing. The last two merges didn’t look like merges at all. A normal merge will have two (or more!) parents (unless git fast forwarded it – a feature which you can turn off on the command line). The last two merges only had a single parent and it looked more like they’d been rebased. I couldn’t understand this because I knew for a fact that the last people to merge into the tree had definitely performed a merge and not a rebase. I did a lot of hunting around at this point to try and figure a way out of this mess and to understand why this had occurred when seemingly we’d done the right things.

Since I had an upcoming release to prepare I didn’t have much time to look into this further so Lee took over and started investigating. After a lot of hunting around he came across a blog post which exactly describes the situation we found ourselves in. What happened was this:

  • Person A starts a merge.
  • Person B commits into the branch you’re merging into.
  • Person A finishes the merge then tries to push it. This fails because the merge is now out-of-date.
  • Person A runs ‘git pull –rebase’ so that he/she can commit the merge.

What Person A has not realised at this point is that the rebase has just trashed the merge commit. In our case we’d done this twice without realising the complete mess we’d just made to our history.

Turns out that if this happens you have to start your merge over from scratch or use an option on the git rebase command called –preserve-merges. This option doesn’t exist in the git pull command so you’ll need issue separate fetch and rebase commands. See the original article for more detail about this.

In the end to clean up we had to abandon the current merge, revert the previous merge mess then rerun the merge. Finally we’re back to a sane(ish) commit history.

I screwed up

My old domain is gone I’m afraid. The email on my domain name provider was set to an old email address and when my domain came up for renewal I never saw the email. As a result my domain lapsed and was picked up my Melbourne IT who were asking for $75/year to get it back. Since there was no way I was about to pay that I decided to just get myself a new domain. Sadly this does mean all my old links are now broken and I’ll be restarting with zero traffic.

It’s been a long time since I’ve really written much on this blog so I may take this as an opportunity to reboot and start writing again. In the near future I’ll probably rename the site to match the domain as well but for the short term I’ll be leaving it as it in case anyone ends up searching for stuff under the old name.

Clojure Web Infrastructure

All the various libraries involved in Clojure web development can be confusing so I created a page to clarify this.  I’m sure there is stuff I’ve missed.  If there’s something you’d like to see added let me know in the comments and I’ll update it.

Are We There Yet?

I just watched Rich Hickey’s talk – “Are we there yet?” for the second time. Awesome presentation that I highly recommend you put on your list to watch.

Clojure for Beginners

At the moment on the Clojure mailing list there is a large rambling discussion about Clojure needing to be easier for beginners. There is some merit to this idea but I find this type of discussion doesn’t actually produce anything worthwhile.  Despite the large amount of hot air a couple of people have stepped forward with some useful videos for setting up Clojure in Eclipse and IntelliJ Idea.

Laurent Petit posted the following video on the Eclipse plugin:

and Greg Slepak posted the following video (via his blog):

If you’re considering starting with Clojure these are reasonable alternatives despite being somewhat immature. Personally I made life difficult on myself deciding to use Emacs. Emacs is great but the learning curve is horrible. Learning a new language and learning a new (difficult) editor at the same time is tough (although ultimately I’m glad I did it).

Gradle

I’ve been an Ant user for a long time. Ant has many flaws as a build tool but it does have the advantage of being simple, predictable and reasonably well documented. Maven has been around for a long time however while I liked the fact that it gives you lots of functionality out of the box I dislike how rigid and opaque it is.

Recently I’ve started to use Gradle. Gradle is an extremely impressive project. Even though it has yet to reach the 1.0 milestone, it has extensive documentation and is obviously well thought out.

Like Maven it supports impressive out of the box support functionality with very little work. However it makes setting up custom configurations much easier – at least in my opinion. Ant tasks are also available within Gradle should you have a requirement to use them.

Although I’ve only used it on smaller single project builds from what I’ve read about multi project builds it looks simple and easy to deal with.

The underlying dependency technology uses Ivy which means it automatically gets full compatibility with Maven repositories while keeping the flexibility of ivy configurations.

One of the plugins which I particularly like is the Idea plugin. It makes it easy to create a full IntelliJ Idea project with all the dependencies setup to point straight into the local ivy cache. Unfortunately I didn’t manage to get it working correctly for a multiproject build but otherwise it is still great for creating a new project from scratch.

Gradle is definitely something to look into if you’re looking around for a build tool. Some basic Groovy knowledge would be an advantage however.

Simple Macro Followup

Nguyen (sorry wordpress stuffed up your name) offered up a simplified version of the cond macro. Behold:

(defmacro condd [pred & clauses]
  `(letfn [(predd# [test-expr# expr#]
                   (->> test-expr# ~pred))]
          (condp predd# nil
                 ~@clauses)))

If we macro expand it:

(macroexpand-1 '(condd is-two?
                       1 (print "was one")
                       2 (print "was two")))

We get (after cleaning it up):

(letfn [(predd [test-expr expr]
               (->> test-expr is-two?))]
       (condp predd nil
              1 (print "was one")
              2 (print "was two")))

Which is pretty much the same like writing the following:

(condp (fn [expr _] (->> expr is-two?)) nil
       1 (print "was one")
       2 (print "was two"))

So it seems than condp can be bent to our will by passing nil as the expression then ignoring it in the predicate function. Thanks Nguyen.