Tuesday, November 23, 2010

How to use GIT with SVN repositories

In the previous series of post, I narrated the real incident that made us move to GIT.  By now, its must be obvious to you guys that, GIT is an integral part of any project that we execute from now on.

Most of the client projects we execute use Subversion (SVN) as their central repository.  There are various reasons because of which they will not move to pure GIT repositories in near future.  But this should not stop us from reaping the benefits of GIT right!

In this post, I am going to demonstrate the basic set of commands required to use GIT with SVN repositories.

Introduce your self to GIT:

Its just good manners to introduce ourselves to people who we are going to work with, isn't it!  So lets introduce ourselves to GIT

The above config values tells GIT that,
  • User name is for all the git repositories on this machine is Deep Shah 
  • Email address for all the git repositories on this machine is  deep@gitshah.com
This step is not required, but is considered good practice.

Next, lets bring some color in our dull lives.

These configs will show some colors on the git prompt.  Don't execute the above commands, if you hate colors.

Thats about all the configs you need.  All set!  Lets get some code!

Getting the code:

In this step, we will get the code from SVN and create a local GIT repository.  There are two types of SVN repositories.
  • Repositories with the standard layout.  Standard layout repository, is a repository that has trunk, tags and branches folders at its root.  As the name suggests, these folders hold the trunk, tags and branches of the repository.  Pretty straight forward!  Look at this link https://play-with-hg-svn.googlecode.com/svn for an example of standard layout SVN repository
  • Repositories that do not use standard layout.  Non standard repositories could have any weird layout.  I have seen repositories having, trunk somewhere nested under the branches!  In short layout could be absolutely anything.  Have a look at this link http://non-standard-repository.googlecode.com/svn/branches/ for an example of non-standard layout SVN repository.
GIT supports both types of SVN Repositories equally well.  But, for the sake of simplicity we will look at standard layout SVN repositories in this post.  In the next post we will look at non-standard SVN repositories.

To get the code you will need to clone the repository at https://play-with-hg-svn.googlecode.com/svn.  This can be done using the following command.

The above command will create a git repository locally on your machine.  The repository will be created under the folder called play-with-hg-svn-git.

If you open that folder you will see, a folder named .git is created.  This is the only folder that GIT needs.  It does not create any other folder anywhere else.

Comparing this with SVN, SVN keeps the information littered around in countless .svn folders.  For each directory/sub-directory in the project there will be a .svn folder.  Man that is a lot of .svn folders!

The -s option tells GIT that, the SVN repository follows a standard layout (trunk/, tags/ and branches/).

GIT will download the information from revision 1 to the current or the HEAD revision.  The entire revision history is kept on the local machine.

What? What did I just say?  The revision information from revision 1 to the current or the HEAD revision will be kept on my local machine?  Man! that will take my entire hard disk.  

Actually, it wont!  GIT keeps all the history in the compressed format.  I have tried cloning very big repositories (once that have around 1 GB of content).  The entire .git directory (which holds information about all the revisions) was around 350 MB.  Wow!  That's incredible!  The entire history (of a very big repository) is on my local machine and is packed in under 350 MB!

If you still feel that, downloading so much history is just pure waste of bandwidth, don't worry, GIT has an alternative for you as well.  For e.g. lets say that, you are going to need the history form revision 20 onwards only, then use the following command

The above command will start downloading history from revision 20 onwards.  For your project substitute 20 with any other revision number.

The clone command my take some time to finish for bigger repositories.  Be patient.  Grab a cup of coffee or play a game on XBox while it finishes.

After clone finishes, you will see that we have got all he code checked out.  Got the code, lets start hacking it!

Ignoring files:

All serious projects generate a few binary files.  We do not intent to commit those files.  Hence, we must ignore them.

To ignore files in a GIT repository we have to create a file called .gitignore directly under your root directory (i.e. in this example under play-with-hg-svn-git).  This file accepts ant like path expressions.  Any path or file name you put in this file would be ignored and will not be shown while you commit your changes.

Its a good idea is to commit the .gitignore file itself to SVN.  This will help other developers who are using GIT on the same repository.

To generate this file automatically using the SVN ignores, use the following command

Remember, when you are working with GIT, you will always be working on a local branch.  By default GIT creates a local branch called master.  It might feel that this branch has special meaning, but its simply a default name chosen by the GIT folks.  It could have been named anything for e.g. servant, batman, robin or absolutely anything else.

At this point, you are all set.  The SVN repository has been cloned, code is checked out and ignores have been setup.

Viewing History:

You still do not believe that you have entire history on your local machine, do you?  OK, its time for some demonstration!  Disconnect from network, turn off your WiFi connection, remove the network cord and type in the following command

This command will show you the graphical representation of all your commits at lightning fast speed.  You have no network connection, but still you can view the changes made in the first revision!  With SVN this was never possible!

Next, try this command 

This command shows the text representation of your commit history in the less format.  To navigate to the next/previous pages use the keys "<space>/b" respectively.  To quit from this view use the key "q"

Local Commits:

The best thing about GIT is, ability to create cheap local branches.  These branches reside on your local machine.  This feature helps a great deal.  This feature makes it possible for us to work on multiple streams of work.  Will explain in detail how this is done in future posts.

To view what branches you have currently use the following command

This command should show you something like the above image.

See the "*" besides the master branch, that means currently you are on the master branch.  The branches shown in red color are the remote branches.  They correspond to the actual SVN branches.  We always work on the local branch and never ever on the remote branch.  Currently we are working on the master  local branch.

Lets make some code changes.

At this point if you type the following command

This shows some information on the screen which looks cryptic.

Actually its very simple.  Things that are in red color (with a "-" prefix) have been removed and things that are in green color (with a "+" prefix) have been added to the first.txt file.  As simple as that!

This command shows you the current status of the master branch.

It give some important information to us.  First it says that we are on branch master (as if we didn't know).  Next, it says changed but not updated.  This means, one file first.txt has changed but it has not been staged yet.

GIT has a concept of staging the files before committing.  For now just remember that to commit the file first.txt you will have to stage it first.  Here's how you could do it

Above command will stage only one file first.txt.  To stage all files, use the following command.

You can do the same thing using the git gui command.

Now we need to commit our changes.  But wait we have no network connectivity!  How can we commit without having any network connectivity?

Offline/local commits are single most important advantage of using GIT.

To commit your changes use the following command

At this point, if you look at the log (git log), you should see a brand new commit at the top with the comment First commit from GIT.

Reverting commits and files:

Strange looking 40 char long alphanumeric strings in your git log, are nothing but git commit ids.  Although its 40 char long, each commit can be uniquely identified by using the first 7 or 8 chars.

After full days of hard work you find out, the commit you have made will not work and it might break some functionality.  You want to revert that commit.  To revert a commit, use the following command

This will open up your favorite text editor.  Lets you edit the revert message, shows you what files will be reverted.  Save and quit from the editor would revert your changes.

If you now do a git log, you will see two commits on the top.  One that you created and one that you reverted.

Reverting a file:

To revert a file that has not been staged, use the following command

Read this command as, checkout the last committed version of the file over your changes

To revert a file that has been staged, you will first have to un-stage it using the following command

Then you can revert the first.txt using the checkout command

Updating from and Committing to SVN:

Time has come!  Time has come to commit our changes to SVN.  But before that, its always a good practice to take the latest from SVN.

To get the latest changes from SVN use this

This command will take the latest changes from SVN and apply your local commits on top of those changes.  This means that, all your local commits will appear on top of the latest changes we received from SVN.  This is exactly what we want!

All the commits that we have made so far are only in your local repository.  They are not visible to other developers.  To push your commits to SVN do this

Each of your local commits, will now be committed to SVN as a separate commit.

There is an obvious advantage with this strategy, you can keep making local commits as often as you want, i.e. at every local point, without effecting other developers.  When you are ready with the feature you were developing, make those commits public by pushing local commits to SVN.  This enables developers to go back in time and see how a feature evolved, when it was under development.  The version history of every logical point in the feature development is maintained!  This was not possible when we used only SVN.

That's all folks!  This much information is enough for you to get started with GIT.  Initially it might feel like too much work, but trust me on this, it pays off!

The advantages are far too many.  Do not waste any more time, go GIT it!
Have some Fun!