Subversion: The Magic of Merging

When programming professionally, Subversion is a must-have. Same for system administration: it’s quite a good idea to keep your configuration files (e.g in Linux the whole /etc/ directory) as a Subversion checkout.

So the goal of Subversion (or any other Source Control system) is to allow you to do something Apple will introduce with it’s new Leopard operating system: Time Machine. Go back in time (and restore a version of a file as it was on day x).

Using Subversion on a daily basis is quite easy. Just check in (svn ci) your changes after you have completed a certain task. When you work collaboratively, and someone else has committed some changes, you do a svn up and the changes of the others are applied to your codebase.

That’s all you basically need. But how can you go back in time now?

So you poke around a bit and find that svn up has a parameter -r which let’s you put your checkout to the state in which it was at a certain revision.

Let’s suppose we know that something was ok on monday and is not today. So let’s use the command from above to see what it looks like.

~/project/trunk$ svn up -r {2006-10-09} app.php
U app.php

Voila, there it is. Now we choose to use that code now and throw away all changes that have been committed since. We modify the file a bit and do a check in:

~/project/trunk$ svn ci -m "revert to monday" app.php
Sending app.php
svn: Commit failed (details follow):
svn: Your file or directory 'app.php' is probably out-of-date
svn: The version resource does not correspond to the resource within the transaction. Either the requested version resource is out of date (needs to be updated), or the requested version resource is newer than the transaction root (restart the commit).

Uh.. ok. So you probably you know that error message already. It is also returned when you want to check something in on a file that has been changed by someone else since your last svn up.

When you check something into a subversion repository, one of the basic rules is that the file you want to commit is “up to date”, i.e. the revision number of your local file (updated by svn up) equals the number in the repository (on the server).

Ok, so, let’s update our checkout so we can re-run the check in.

~/project/trunk$ svn up
G app.php

So you discover the changes that happened since have been re-inserted to that file again. Maybe Subversion has alerted you of a conflict, because you changed some lines that have been modified since monday also.

Great! Basically we are back to where we started.

Let’s not resign here, but rather use the appropriate command: svn merge. That command is mostly known for merging changes from one branch of development to another. But it can also help you to go back in time.

The parameters of svn merge are to specify a revision range, which changes to be merged, and a source — what part of the subversion repository should be searched for the changes.

Usually one would find this command used in a way like:

~/project/trunk$ svn merge -r 15:26 ../branches/first_release/
G app.php

So with two revisions specified you define a range of changes which should be merged into the current checkout. Ok so how would us help this here?

You can also specify revisions backwards, to go back in time. So to undo the command form before you can write:

~/project/trunk$ svn merge -r 26:15 ../branches/first_release/
G app.php

To put it simple, Subversion generates a diff file behind the scenes that incorporates the changes between the given revisions. Then the changes are merged with the files in the same way the patch command (Linux, Unix, OS X, …) does it. When going back in time, the parameter -R is used which applies the patch in the reverse direction. Voila.

So as a final solution this leaves us with:

~/project/trunk$ svn merge -r head:{2006-10-09} .
U app.php
~/project/trunk$ svn ci -m "revert to monday" app.php
Sending app.php
Transmitting file data .
Committed revision 27.

For further questions, the Subversion FAQ is a good starting point when you know exactly what you want (i.e. the correct terminology). (For example reverting does not mean to go back to a previous version of the file, but rather to remove the changes you did locally).

There is the subversion book (also published by O’Reilly), of which the Guided Tour is a good starting point.

The process I described above as a trial and error is also described in that book at Undoing changes.

Also OSCON: Subversion Best Practices, a transcript of a talk given by the subversion creators (Ben Collins-Sussman and Brian W. Fitzpatrick) by Brad Choate has some good tips.

Have fun :)

subversion, merge, revert, time machine

JavaScript Tricks And Good Programming Style

Note that this is an updated version. Original version can be found here.

Thanks to the commenters I have updated this post with some better tricks.

In a loose series I’d like to point out a few of them. As I am currently mostly programming in JavaScript, I will write most of my samples in that language; also some of the tricks I mention only apply to JavaScript. But most of them apply to most programming languages around.

Optional parameter and default value #
When defining a function in PHP you can declare optional parameters by giving them a default value (something like function myfunc($optional = "default value") {}).

In JavaScript it works a bit differently:

var myfunc = function(optional) {
if (typeof optional == "undefined") {
optional = "default value";
}
alert(optional);
}

This is a clean method to do it. Basically I pretty much recommend the use of typeof operator.

update
Michael Geary (his comment) pointed out this solution that I like.


var myfunc = function(optional) {
if (optional === undefined) {
optional = "default value";
}
alert(optional);
}

The solutions mentioned (if (!optional), optional = optional || "default value", and the like) have problems when you pass 0 (zero) or null as an argument.

Commenters said that the 0/null problem is not one as this would not be the situation to use it. I would not say so. In an AJAX world where you do serialization back to a server/database often a 0/1 to false/true mapping has to be established. For default values it is important.

In case you just need to make sure that an object is not null I do prefer the mentioned

myobject = myobject || { animal: "dog" };

end update

Parameters Hints #
The larger your app gets, the more functions you get which you would use throughout the app. It also creates a problem with maintenance. As each function can contain multiple arguments it is not unlikely that you forget what those parameters were for (especially for boolean variables) or mix up their sequence (I am especially gifted for that).

So what I do is this: update substitute variables with comments end update

var myfunc2 = function(title, enable_notify) {
// [...]
}
myfunc2(/* title */ "test", /* enable_notify */ true);

This piece of code relies on the functionality of programming languages that the return value of an assignment is the assigned value. (This is something that you should also maintain in your app, for example with database storage calls, give the assignment value as a return value. It’s minimal effort and you might be glad at some point that you did it).

If you do this you can see at any point in the code, what parameters the function takes. Of course this is not always useful, but especially for functions with many parameters it gets very useful.

Search JavaScript documentation #
When I need some documentation for JavaScript I use the mozilla development center (mdc). To quickly search for toLocaleString, I use Google: http://google.com/search?q=toLocaleString+mdc

As I am a German speaker I also use the excellent (though a bit out-dated) JavaScript section SelfHTML. I use the downloaded version on my own computer for even faster access.

The self variable #

update
… should be avoided. Even if someone like Douglas Crockford (creator of JSON) uses it and calls it that.

Let me quote Jack Slocum who put it best:

// used to fix "this" prob with Function.apply to give call proper scope
// nice method to put in your lib
function delegate(instance, method) {
return function() {
return method.apply(instance, arguments);
}
}

function Animal(name) {
this.name = name;
this.hello = function() {
alert("hello " + this.name);
}
}

var dog = new Animal("Jake");
var button = {
onclick : delegate(dog, dog.hello)
};
button.onclick();

I removed my code as it can be considered obsolete by this.
end update

Reduce indentation amount #

update
I have removed the code because it leads people into believing something different than I meant. So let me put it differently:

What I am opposing is white space deserts. If you have many levels of indentation then probably something is wrong.

If a for loop only applies to a handful of cases, don’t indent the whole loop in an if clause but rather catch the other cases at the top.
Often it is advisable to move longer functionality to a function (there is a good reason for that name) that you call throughout a loop.
end update

That’s all for now, to be continued. Further readings on this blog:

update
Eventhough some commenters disagreed with what I said, I think posts like this are very much needed in the bloggersphere. Even if they are not free of errors on the first take, great people can help improve them. I would appreciate if more people took that risk.
end update

javascript, tricks, coding practices