Showing posts with label tips. Show all posts
Showing posts with label tips. Show all posts

June 02, 2009

Importing git history into a new svn repository

So the management has finally approved your project, and has asked you to start working on it. Heh ... little do they know that you'd already been working on it, and have a nice prototype working, and it's all saved on your local git repository. But your company is not as cool as you are - it has it's own svn repository, and now you have to import your code into it, history and all.

Here is the git tree, as you have developed it:

Original repostiory structure

.. and your svn repository looks similar to this -
$ svn co <svn repo url>
Checked out revision 0.

$ cd <svnrepo>

$ mkdir tags trunk branches

$ svn add *
A branches
A tags
A trunk

$ svn commit -m "initial directory structure"
Adding branches
Adding tags
Adding trunk

Committed revision 1.

Now you could copy all the files from the git repository into trunk, and commit it. But that is really not the way it should be. For one - no one will know the reason for *anything* in this repository before the big bang. Also, there might have been legitimate reasons for people to branch out from some earlier state of the code, but now no one will even know.

Fortunately, a mail on the kerneltrap archives tells us how we can export a git repository, along with all it's history, into an svn repository.
(from http://kerneltrap.org/mailarchive/git/2008/10/26/3815034)

From: Björn <B.Steinbrink@...>

...
...

This should do and uses a graft to simplify the process a bit:

Initialize git-svn:
git svn init -s --prefix=svn/ https://svn/svn/SANDBOX/warren/test2

The --prefix gives you remote tracking branches like "svn/trunk" which
is nice because you don't get ambiguous names if you call your local
branch just "trunk" then. And -s is a shortcut for the standard
trunk/tags/branches layout.

Fetch the initial stuff from svn:
git svn fetch

Now look up the hash of your root commit (should show a single commit):
git rev-list --parents master | grep '^.\{40\}$'

Then get the hash of the empty trunk commit:
git rev-parse svn/trunk

Create the graft:
echo <root-commit-hash> <svn-trunk-commit-hash>  >> .git/info/grafts

Now, "gitk" should show svn/trunk as the first commit on which your
master branch is based.

Make the graft permanent:
git filter-branch -- ^svn/trunk --all

Drop the graft:
rm .git/info/grafts

gitk should still show svn/trunk in the ancestry of master

Linearize your history on top of trunk:
git svn rebase

And now git svn dcommit -n should tell you that it is going to commit
to trunk.

If you check your svn repository log, it will look like this.
SVN log

All the history, nice and linearised for svn.

Keep in mind though, that this method is lossy. All the branches have been linearised, and you can no longer "check them out" in the original git repository. Apart from that, things work just fine, and you can continue to commit in your local git repository, and push to svn as and when needed.

May 17, 2009

Tuning LINQ performance with Mr. P and Mr. S

I thought I'd take a second look at the Mr. P and Mr. S problem, which I'd posted more than a couple of years ago. The last time I tried it, I wasn't successful. I had a strategy to solve it, but somehow I just couldn't translate it into code.

I've been programming a lot with C# lately, and decided to use LINQ to solve the puzzle. Although not very concise, compared to the Python and Haskell solutions out there, it does print out the right answer. After you've tried to solve it yourself, you can have a look at my solution here.

There's something special about LINQ queries. All LINQ queries are deferred, which means that they aren't executed until they are accessed. Also, they are re-executed when the execution context changes. Say we have a list of numbers, and a query on it like so :


var numbers = new List<int>();
var query =
from i in numbers
select i;


The query hasn't been executed yet. We add a few numbers to the list, and compare the counts of the list and the query.


numbers.Add(0);
numbers.Add(1);
numbers.Add(2);

// 3 elements in list, 3 in the query
Assert.AreEqual(numbers.Count, localDeferredQuery.Count());


The test passes. LINQ queries are "live", very much like functions. Usually, this is a good thing, as no operation is performed until it is actually needed. However, there are exceptions. For example, I used these three ranges -


public static IEnumerable OddRange(int stop) // returns odd numbers upto "stop"
{
for (int i = 1; i < stop; i+=2) yield return i;
}

public static IEnumerable EvenRange(int stop) // returns even numbers upto "stop"
{
for (int i = 2; i < stop; i+=2) yield return i;
}

public static IEnumerable Range(int stop) // returns all numbers upto "stop"
{
for (int i = 0; i < stop; ++i) yield return i;
}


To define the Deferred() and Immediate() functions below:


public void Deferred()
{
var all = Range(limit);
var even = from e in EvenRange(limit) where all.Contains(e) select e;
var odd = from o in OddRange(limit) where !even.Contains(o) select o;

var query = from q in odd select q;

foreach(var i in query) { var j = i+1; }
}

public void Immediate()
{
var all = Range(limit);
var even = (from e in EvenRange(limit) where all.Contains(e) select e) .ToArray();
var odd = (from o in OddRange(limit) where !even.Contains(o) select o) .ToArray();

var query = (from q in odd select q).ToArray();

foreach(var i in query) { var j = i+1; }
}


all, even and odd are three sub queries, each using the previous one. The Immediate() function only differs from Differed() due it's forced execution of the subqueries with ToArray(). However, Immediate() performs much better than Deferred(). I knew LINQ operators are actually euphemism for functions, and that iterator blocks are actually exploded by the compiler into a lot of code. But Deferred() was waaaayy slower than Immediate(), and the time taken would increase exponentially with the value of limit. This couldn't be just some extra code.

I posted a query on stackoverflow, and it did not disappoint. It is quite obvious in hindsight. This statement -

var odd = (from o in OddRange(limit) where !even.Contains(o) select o).ToArray();


in deferred mode, turns out to be pretty expensive indeed. It contains a call to even.Contains(o). While in the immediate mode this is an O(n) operation, in deferred mode, the sequence of calls looks like this -


odd --> even -+-> EvenRange()
|
+-> all --> Range()


A simple O(n) operation is now O(n3). We can do better than O(n), however, by using a Hashset.

var evenSet = new HashSet(even);
var odd = from o in OddRange(limit)
where !evenSet.Contains(o) select o; // Contains() is now O(1)


It doesn't get much better than this.

March 11, 2009

Use Gmail to tell the world about yourself

Here's a trick that you might find handy.

Using a combination of gmail address aliases and canned responses, you can use gmail to automatically send directed, and relevant responses on your behalf.

You have to enable canned responses ...
... add a canned response while composing ...

and set up an appropriate filter.

As you can see in the pictures above, I have set up gmail to respond to any mails to sandesh247+ci@gmail.com with my contact information. I could have a public web page that does the same thing, yes, but in this way I reveal information only to those who explicitly ask for it, plus I have an account of all the requests.

You have to be careful though, this does set your account up for spamming. An automated reply immediately validates an email id, make sure you do this only with email addresses you want to make public.