Kash Farooq's software development blog

.NET Developer

Git: Ignoring files for .NET development

Posted by Kash Farooq on July 10, 2011

Here is the .gitignore file I use for .NET/C# development. Add this file to the root of your Git repository so you don’t end up adding ReSharper files, bin folders, etc to your commits:

obj
bin
_ReSharper.*
*.csproj.user
*.resharper.user
*.resharper
*.suo
*.cache
~$*

Posted in Git Source Control | Tagged: | Leave a Comment »

Creating .NET objects from JSON using DataContractJsonSerializer

Posted by Kash Farooq on January 31, 2011

Creating .NET objects from JSON using DataContract and DataMember

In a previous post and demonstraed that the RESTful Google Search API returns data as JSON. I needed a way to convert the JSON data into .NET objects and this post shows what I ended up with.

Here is an example of the JSON result set returned:

{"responseData":
 {"results":
 [
  {
  "GsearchResultClass":"GwebSearch",
  "unescapedUrl":"http://www.google.com/help/features.html",
  "url":"http://www.google.com/help/features.html",
  "visibleUrl":"www.google.com",
  "cacheUrl":"http://www.google.com/search?q\u003dcache:BNRWhS8EKYAJ:www.google.com",
  "title":"\u003cb\u003eSearch\u003c/b\u003e Features - \u003cb\u003eGoogle\u003c/b\u003e",
  "titleNoFormatting":"Search Features - Google",
  "content":"To find reviews and showtimes...."
  },
  {
  "GsearchResultClass":"GwebSearch",
  etc
  },
  etc
 ],
 "cursor": {
 "pages": [
  { "start": "0", "label": 1 },
  { "start": "8", "label": 2 },
  etc
  { "start": "56","label": 8 }
  ],
  "estimatedResultCount": "59600000",
  "currentPageIndex": 0,
  "moreResultsUrl": "http://www.google.com/search?oe=utf8&ie=utf8&source=uds&start=0&hl=en&q=MY SEARCH TEXT"
  }
 },
 "responseDetails": null,
 "responseStatus": 200
}

We can use System.Runtime.Serialization to create .NET objects from this JSON data.

For example, the top level JSON responseData can be represented by the following .NET type:

[DataContract]
public class GoogleSearchResults {
  [DataMember(Name = "responseData")]
  public ResponseData ResponseData { get; set; }
}

Note that I’ve specified the Name attribute. Without it I would have had to have a property called “responseData” rather than “ResponseData”.

The rest of the data is extracted using the classes below. Note that I can be quite selective in what data I wanted to transfer from JSON to .NET. If I don’t need, say, the “cacheUrl”, I can just omit it from my .NET objects. I can also rename data. I have put the data from “titleNoFormatting” into a property called Title:

[DataContract]
public class ResponseData
{
  [DataMember(Name="results")]
  public IEnumerable<Result> Results { get; set; }

  [DataMember(Name = "cursor")]
  public Cursor Cursor { get; set; }
}

[DataContract]
public class Cursor
{
  [DataMember(Name = "moreResultsUrl")]
  public string MoreResultsUrl { get; set; }

  [DataMember(Name = "pages")]
  public IEnumerable<Page> Pages { get; set; }
}

[DataContract]
public class Result
{
  [DataMember(Name = "url")]
  public string Url { get; set; }

  [DataMember(Name = "titleNoFormatting")]
  public string Title { get; set; }
}

[DataContract]
public class Page
{
  [DataMember(Name = "start")]
  public int Start { get; set; }

  [DataMember(Name = "label")]
  public string Label { get; set; }
}

Finally, I need a method to actually deserialize a JSON string into my .NET objects. I can use System.Runtime.Serialization.Json.DataContractJsonSerializer to do this. I have created the following generic method that takes a JSON string and the type I want it to be deserialised into, and then returns an instantiated .NET object:

public static T Deserialise<T>(string json) {
  var obj = Activator.CreateInstance<T>();
  using (var memoryStream = new MemoryStream(Encoding.Unicode.GetBytes(json))) {
    var serializer = new DataContractJsonSerializer(obj.GetType());
    obj = (T) serializer.ReadObject(memoryStream);
    return obj;
  }
}

This generic method can then be used to convert a JSON string to the specified .NET type:

string reponseJson=GetJsonDataFromGoogle("MY SEARCH TERM);
results = Deserialise<GoogleSearchResults>(responseJson);
foreach (var googleSearchResult in results.ResponseData.Results) {
  Console.WriteLine(googleSearchResult.Url);
}

Posted in .NET | Tagged: , , , | 4 Comments »

Programmatically searching Google (Part 2): Using the RESTful interface

Posted by Kash Farooq on January 30, 2011

This post follows on from part 1, in which I perform a Google search using the .NET wrapper library project. I was curious why the library didn’t appear to provide any paging functionality and seemed to just get all the search results in one hit.

So, I’m now going to look at searching directly using Google’s RESTful API.

The URL that you hit is:

http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=MY SEARCH TEXT&rsz=large&key=MY GOOGLE KEY&start=0

You can omit the key, but Google recommends you provide it.

This returns a JSON result set like the following.

[Note: also see "Creating .NET objects from JSON using DataContractJsonSerializer"]

{"responseData":
 {"results":
 [
  {
  "GsearchResultClass":"GwebSearch",
  "unescapedUrl":"http://www.google.com/help/features.html",
  "url":"http://www.google.com/help/features.html",
  "visibleUrl":"www.google.com",
  "cacheUrl":"http://www.google.com/search?q\u003dcache:BNRWhS8EKYAJ:www.google.com",
  "title":"\u003cb\u003eSearch\u003c/b\u003e Features - \u003cb\u003eGoogle\u003c/b\u003e",
  "titleNoFormatting":"Search Features - Google",
  "content":"To find reviews and showtimes...."
  },
  {
  "GsearchResultClass":"GwebSearch",
  etc
  },
  etc
 ],
 "cursor": {
 "pages": [
  { "start": "0", "label": 1 },
  { "start": "8", "label": 2 },
  etc
  { "start": "56","label": 8 }
  ],
  "estimatedResultCount": "59600000",
  "currentPageIndex": 0,
  "moreResultsUrl": "http://www.google.com/search?oe=utf8&ie=utf8&source=uds&start=0&hl=en&q=MY SEARCH TEXT"
  }
 },
 "responseDetails": null,
 "responseStatus": 200
}

Now we’re getting somewhere. The “cursor” block at the bottom of the returned data provides paging information, a “moreResultsUrl”, an estimate of the number of results. Eveything we need.

As I have been told the number of pages (in the above example there are 8 pages) and the starting point of each page (0, 8, …, 56), I can just use my original URL again, and adjust the start parameter for each call (i.e. I don’t need to use the moreResultsUrl data provided in the cursor block).

So, I can just use:

http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=MY SEARCH TEXT&rsz=large&key=MY Google KEY&start=8

After playing with some more searches I realised that a maximum of 8 pages were being returned each time.

In my example above, each page returned 8 results. 8 pages of 8 results does not give me 59600000 results!

I tried the following URL:

http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=MY SEARCH TEXT&rsz=large&start=100

The result returned was:

{"responseData": null, "responseDetails": "out of range start", "responseStatus": 400}

Google does not allow you to search for more than 64 results!

So the only way to get more than 64 results would be to screen scrape, which is ugly (but can be made more bearable by using SGMLReader and LINQ to XML). Though I’m pretty sure Google’s T’s & C’s don’t allow screen scraping!

Posted in .NET | Tagged: , , | Leave a Comment »

Programmatically searching Google (Part 1): The Google API for .NET

Posted by Kash Farooq on January 24, 2011

Also see Programmatically searching Google (Part 2): Using the RESTful interface

I needed to do some web searches and record the host names that I found, so I started investigating what APIs Google exposed.

I found the “Google APIs for .NET Framework” hosted on Google Code. There hasn’t been much activity on this project recently – the last release was April 2010 – and there is not much documentation, but it works and it is simple to use.

It provides two sets of libraries: one that wraps Google Search and one that wraps Google Translate.

Here is an example of a search:

public void SearchForSomethingUsingLib() {
  var client = new GwebSearchClient("http://mywebsite.com");
  var results = client.Search("google api for .NET", 100);
  foreach (var webResult in results) {
   Console.WriteLine("{0}, {1}, {2}", webResult.Title, webResult.Url, webResult.Content);
  }
}

The ’100′ in the above example indicates the number of search results to return.

What puzzled me was that the set of results returned didn’t appear to have a concept of paging, and the library didn’t seem to have a “Search Paged” method. What if I had asked for 1000000 results? Surely the API wasn’t going to get 1000000 results in one go and load them all into a List?

I fired up reflector. The API definitely returned a straight forward generic list. No delayed execution – one Web Request sent to Google, followed by one “new List<T>” to return the results.

I needed to investigate further, and I’ll look at that in Part 2.

Posted in .NET | Tagged: , , | Leave a Comment »

Unit Testing with SQL Lite and Fluent NHibernate

Posted by Kash Farooq on January 2, 2011

I used to unit test NHibernate criteria by, essentially, interaction testing.

It’s fairly straight forward to do this (NHibernate provides lots of interfaces that are easy to mock), but the test code ends up just mirroring the production code. Your test would check that CreateCriteria was called, then an Expression was added, then List was called, etc, etc.

If the production code changes (for example, a more efficient criteria is implemented, or HQL is used), the test would need to be completely rewritten. This defeats one of the objectives of TDD – provide an environment in which refactoring can be done safely, with the confidence that the new code does exactly what the old code did.

So, I switched to using SQL Lite to allow my unit tests to actually hit an in-memory database. I think this is perfectly acceptable for simple queries that are not using any DB specific features. The tests are also fast enough to run on a Continuous Build server.

The code in this post uses Fluent NHibernate to configure NHibernate. It allows me to easily configure my production code to use a SQL Lite database via my test code, and to use a production database via my production code.

Let’s start with a very simple Model – the data to be persisted.

namespace SystemUnderTest.Model {
  public class Person {
    public virtual long Id { get; set; }
    public virtual string FirstName { get; set; }
    public virtual string LastName { get; set; }
    public virtual DateTime DateOfBirth { get; set; }
  }
}

Next, we need some code that configures NHibernate using Fluent, and allows me to set the database type to use. Note that the code exposes the Session Factory so I can create a session when needed. It also exposes the NHibernate configuration. I will use this from the unit test to create a schema inside my SQL Lite in-memory database.

namespace SystemUnderTest.DataAccess {
  public class DataSession {
    private readonly IPersistenceConfigurer _dbType;
    public DataSession(IPersistenceConfigurer dbType) {
      _dbType = dbType;
      CreateSessionFactory();
    }

    private ISessionFactory _sessionFactory;
    private Configuration _configuration;

    public ISessionFactory SessionFactory {
      get { return _sessionFactory; }
    }

    public Configuration Configuration {
      get { return _configuration; }
    }

    private void CreateSessionFactory() {
      _sessionFactory = Fluently
      .Configure()
      .Database(_dbType)
      //Only map classes in the Assembly of 'Person' that have a namespace ending in .Model
      .Mappings(m => m.AutoMappings.Add(
         AutoMap.AssemblyOf<Person>().Where(type => type.Namespace.EndsWith(".Model"))))
      .ExposeConfiguration(cfg => _configuration = cfg)
      .BuildSessionFactory();
    }
  }
}

Now, let’s look at a unit test. I will be creating a PersonRepository to save objects, query objects, etc. The test setup for this class needs to tell the production code ‘DataSession’ class to use an in-memory SQL Lite instance, and to build a schema inside this instance based on the configuration created by Fluent NHibernate.

[TestFixture]
public class PersonRepositoryTest {
 private DataSession _dataSession;
 private ISession _session;

 [TestFixtureSetUp]
 public void TestFixtureSetUp() {
    //Use In Memory database, open session and Build Schema inside In Memory database
    _dataSession = new DataSession(SQLiteConfiguration.Standard.InMemory());
    _session = _dataSession.SessionFactory.OpenSession();
    BuildSchema(_session, _dataSession.Configuration);
 }

 public void BuildSchema(ISession session, Configuration configuration) {
   var export = new SchemaExport(configuration);
   export.Execute(true, true, false, session.Connection, null);
 }

 [TestFixtureTearDown]
 public void TestFixtureTearDown() {
   //Clean up after tests have run
   _session.Close();
   _dataSession.SessionFactory.Close();
 }

 [SetUp]
 public void SetUp() {
   CleanTheTables(); //Make sure tables are empty before each test runs
 }
}

Now, a simple test to begin with. Create a person, save it using our PersonRepository class and then make sure we can find it inside the in-memory database.


[Test]
public void SaveAPersonTest() {
  var personRepository = new PersonRepository(_session);
  personRepository.Save(
     new Person{DateOfBirth = new DateTime(1970,1,1),FirstName = "John",LastName = "Smith"});

  //Now get all Person objects from DB and make sure our object has been persisted
  IList<Person> people = _session.CreateCriteria<Person>().List<Person>();
  Assert.That(people.Count,Is.EqualTo(1));
  Assert.That(people[0].FirstName,Is.EqualTo("John"));
}

Simple.

Now for something a little more complicated; something that we could implement using several methods (e.g. using Criteria, HQL, SQL).

[Test]
public void FindPeopleOlderThanCertainAgeTest() {
  var personRepository = new PersonRepository(_session);
  SaveFourPeopleWithTwoOlderThan30(personRepository);

  //Use repository to find people older than 30
  IList<Person> peopleOlderThan30 = personRepository.GetAllPeopleOlderThan(30);
  Assert.That(peopleOlderThan30.Count,Is.EqualTo(2));
  Assert.That(peopleOlderThan30.Count(x=>x.FirstName=="John")==1);
  Assert.That(peopleOlderThan30.Count(x=>x.FirstName=="Bob")==1);
}

This test provides our TDD safeguard. We can implement GetAllPeopleOlderThan any way we like and this test will ensure that it has been implemented correctly. We can refactor the production code at a later date and the test will ensure we haven’t introduced a bug.

For completeness, here is my implemented repository class:

public class PersonRepository {
  private readonly ISession _session;
  public PersonRepository(ISession session) {
    _session = session;
  }

  public void Save(Person person) {
    _session.Save(person);
  }

  public IList<Person> GetAllPeopleOlderThan(int ageInYears) {
    ICriteria criteria = _session.CreateCriteria<Person>();
    DateTime datePersonMustBeBornBefore = DateTime.Now.AddYears(-1*ageInYears);
    criteria.Add(Expression.Le("DateOfBirth", datePersonMustBeBornBefore));
    return criteria.List<Person>();
  }
}

Posted in Fluent NHIbernate, NHibernate, Test Driven Development | Tagged: , , | 1 Comment »

Bazaar branching strategy with a subversion trunk – revised

Posted by Kash Farooq on December 16, 2010

This blog post will describe how our team ended up working with BZR and SVN.
We had to make some changes as the the method described in Bazaar branching strategy with a subversion trunk as this method made branching an expensive operation.

First we created a BZR repository on a shared server and made a branch of the SVN code:

bzr init-repo c:\bzr\SharedRepo
cd \bzr\SharedRepo
bzr branch svn://localhost/trunk --no-tree

This creates the directory c:\bzr\SharedRepo\trunk with nothing in it apart from the .bzr hidden folder.

If we wanted to work on a branch we would create a no-tree branch from the trunk. This is an incredibly fast operation:

cd c:\bzr\SharedRepo
bzr branch trunk feature_branch1 --no-tree
bzr branch trunk feature_branch2 --no-tree

This creates the directories c:\bzr\SharedRepo\feature_branch1 and c:\bzr\SharedRepo\feature_branch2, again with nothing in it apart from the .bzr hidden folder.

Now, on our development computers we also create a BZR repository and “connected” to the branches to the shared server:

cd dev
bzr init-repo MyRepo
cd MyRepo
bzr branch \\server\SharedRepo\trunk MyRepo\trunk --no-tree
bzr branch \\server\SharedRepo\feature_branch1 MyRepo\feature_branch1 --no-tree
bzr branch \\server\SharedRepo\feature_branch2 MyRepo\feature_branch2 --no-tree

We still haven’t actually got the code yet!
The finally step is as follows (and the example below sets us up to work on feature 1)

cd \dev
mkdir current
bzr checkout MyRepo\trunk trunk
bzr checkout MyRepo\feature_branch1 current

Now we can see source code in c:\dev\trunk and c:\dev\current.
We can work on, say, feature 1, commit code locally, push back to the shared server:

....after some dev.....
cd c:\dev\current
bzr commit -m "My commit comment"
bzr push  \\server\SharedRepo\feature_branch1 --remember

If we need to switch to working on feature 2:

cd c:\dev\current
bzr switch ..\MyRepo\feature_branch2

This will sync c:\dev\current so that it now matches feature_branch2. Any files you have added in feature_branch1 will be removed.
Any files that are in feature_branch2 but not in feature_branch1 will be added. Basically “current” will look like feature_branch2 now.

Once dev is complete and code has been pushed back to the shared server, and you want to merge back into the trunk:

cd c:\dev\trunk
bzr merge \\server\SharedRepo\feature_branch2
bzr commit -m "merged feature 2"
bzr push \\server\SharedRepo\trunk

Then we can hop onto the shared server and push back to SVN

cd c:\bzr\SharedRepo\trunk
bzr push svn://localhost/trunk

The basic rule we observed for the interaction with SVN was to never push to the SVN trunk except from the BZR trunk.

Posted in Bazaar Source Control | Tagged: , , , | Leave a Comment »

Bazaar branching strategy with a Subversion trunk

Posted by Kash Farooq on November 23, 2009

Edit: This post has been superseded by Bazaar branching strategy with a subversion trunk – revised

When creating a feature branch from a Subversion trunk, there are a few things to be aware of.

Consider the following Subversion repository structure representing components that are independently releasable:

trunk
  WebService1
  WebService2
  WindowsService1
  WindowsService2
  UiApp1

With this repository I am suggesting it is completely reasonable to release, say, just UiApp1 without releasing any web or windows services.

With Subversion I could create a feature branch as follows:

branches
  MyFeature
    WebService1
    WebService2
    WindowsService1
    WindowsService2
    UiApp1

Then, if MyFeature actually only needed changes made to WindowsService2, I can safely just merge WindowsService2 back into the trunk – i.e. I would use TortoiseSVN to right click on trunk\WindowsService2 and merge from branches\MyFeature\WindowsService2.

Things are different in the Bazaar world: you can only merge/pull/push from the level you branched at.
If you created a branch like the one above using Bazaar, you would have to merge/pull/push the entire branch – i.e. at the same level as your .bzr folder.

Why is this a problem?
Well, if you know that you have only changed WindowsService2, you can’t just push that back to the trunk. You have to push all folders back into the trunk. The problem arises if someone else has changed, say, WebService2 in the trunk. Bazaar will make you merge those changes into your branch first before you can push your branch back.

Example scenario (this situation happened in our team):

  • Developer 1 creates MyFeature branch and works on WindowsService2 only.
  • Developer 2 creates TheirFeature branch and works on UiApp1 only.
  • Developer 2 commits change back to trunk and creates TheirFeature_Phase2 branch.
  • Developer 1 attempts to commit change back to trunk. Bazaar says a merge in needed (even though Developer 1 hasn’t touched UiApp1).
  • Developer 1 does the merge and pushes the branch back to the trunk.
  • Now Developer 2 attempts to push back to the trunk – Bazaar says UiApp1 has changed even though only Developer 2 has worked on this bit of code!
  • Developer 2 has to merge before pushing back to the trunk.

So, there are a few pain points here. From commit logs it appears as though MyFeature changed UiApp1 when it didn’t.
Both developers had to do unnecessary, potentially confusing merges.

So, to get around this issue, we now create branches at “component level”.
If MyFeature only needs to work on, say WebService1 and WindowsService2, we only create branches for those components.

The full feature branch area on the shared server may look like this:

branches
  MyFeature
    WebService1
	  .bzr
    WindowsService2
	  .bzr
  TheirFeature
    UiApp1
	  .bzr

Now we only have to push back the code that we have actually changed.

This strategy has been successful on our team – we use the great Bazaar features to make our renames/refactors/merges simple, and with just a small amount of extra branch creation work we can keep our synchronisation back to the trunk at the right level.

Posted in Bazaar Source Control | Tagged: , | Leave a Comment »

Bazaar SVN plugin and the append_revisions_only error

Posted by Kash Farooq on November 16, 2009

If you try to push changes from your Bazaar feature branch back to a Subversion repository, and the Subversion repository has been changed since you created your Bazaar branch, you may get something like this:

bzr push
Using saved push location: svn+http://svn/repos/Trunk/MyProject
bzr: ERROR: Operation denied because it would change the mainline history. Set the append_revisions_only setting to False on branch "svn+http://svn/repos/Trunk/MyProject" to allow the mainline to change.

The current version of Bazaar on Windows does not give you much information on where you have to do this.

This is what I did to allow me to push code back into Subversion.
Find subversion.conf. It is located at:

  1. Windows Vista: C:\Users\your-user-name\AppData\Roaming\bazaar\2.0\
  2. Windows XP/2003: C:\Documents and Settings\your-user-name\ApplicationData\bazaar\2.0\

Inside this file you’ll see something like this:

[4ef181b9-d188-42c4-ae88-5d15bdaece0b]
locations = svn+http://svn/repos/Trunk/MyProject

Simply change the file to:

[4ef181b9-d188-42c4-ae88-5d15bdaece0b]
locations = svn+http://svn/repos/Trunk/MyProject
append_revisions_only = False

Posted in Bazaar Source Control | Tagged: , | 4 Comments »

Using Bazaar feature branches with a Subversion trunk

Posted by Kash Farooq on November 2, 2009

If your corporate strategy is to store source code in Subversion, but you are having merge and other Subversion problems, this is the blog post for you.

I have already listed some of the issues we were having and why we decided to move away from Subversion.

In this blog post, I’ll show how you can have a Subversion trunk but do your day-to-day development in a Bazaar feature branch.
This is all possible thanks to the Subversion plugin for Bazaar. The plugin is installed by default when you install the latest Bazaar Windows standalone package.

Here’s the example I’m going to demonstrate:

  1. Create a feature Bazaar branch from a subversion Trunk. This branch will be created in a shared location.
  2. Create a local branch this Bazaar branch.
  3. Work on the local branch, committing changes and pushing them back to the shared branch.
  4. Once the feature is complete, push changes back to the Subversion trunk.

The initial Bazaar feature branch is created in a shared location so that multiple developers can work on the feature.

Setting up

First I creat a Subversion repository, and start svnserve to serve it.

svnadmin create c:\dev\svn_repo
svnserve -d -r c:\dev\svn_repo

Then in another command prompt, I do a checkout:

svn checkout svn://localhost c:\dev\svn_checkout

Now I can add some sample code to this Subversion trunk and commit it back to the repository. [In my case, I added some sample code for a couple of design patterns.]

Create a shared bazaar feature branch

Now I will use the Bazaar Subversion plugin to create a Bazaar feature branch. I’ll do this in a shared location so that multiple developers can work on it.

cd c:\dev\bzr_svn_branch
bzr branch svn://localhost/Observer \\my_server\bzr_branches\update_design_pattern\Observer

The Subversion plugin is automatically used as I have given a SVN URI.
If you are using a Subversion repository that is accessed via HTTP, the branch command would be:

bzr branch svn+http://webserver/Observer \\my_server\bzr_branches\update_design_pattern\Observer

You need to add “svn+” so Bazaar knows that you are not accessing a Bazaar repository via HTTP.

Create a local branch to work on

Now I can create a local branch from the shared branch. This is much like working from a Bazaar repository located on, say, a USB Drive.

cd c:\dev\bzr_branch
bzr branch \\my_server\bzr_branches\update_design_pattern\Observer

This creates a local branch from the shared branch at c:\dev\bzr_branch\Observer.

You can now develop on your local branch. When you commit, you will just be committing locally.
All developers working on this feature should regularly pull from and push back to the central shared branch.

bzr pull \\my_server\bzr_branches\update_design_pattern\Observer
bzr commit
bzr push \\my_server\bzr_branches\update_design_pattern\Observer

Note – you only need to give the full path to the shared branch the first time you use the pull or push commands. Bazaar will remember it for subsequent pull/push commands.

Pushing back to the Subversion trunk

Once development is complete, you will want to push your shared Bazaar branch back to the Subversion trunk.
You have a number of options:

  1. Logon to the shared server and push back from there.
  2. Map a drive to the shared location so you can open a command prompt at, say, e:\.
  3. Pull the latest shared branch locally and push back from your there.

Whatever option you take, the commmand is simply:

cd e:\dev\bzr_branches\update_design_pattern\Observer
bzr push svn://localhost/Observer

If you have renamed and moved files in your Bazaar branch, the Subversion plugin will issue the appropriate Subversion delete and add commands.

Posted in Bazaar Source Control | Tagged: , , , | Leave a Comment »

Integrate Bazaar Source Control with your preferred merge application

Posted by Kash Farooq on October 12, 2009

I have shown how you can use any merge tool with Bazaar to deal with conflicts. In this blog post I’ll show how you can get a more integrated experience.

Bazaar 2.0 introduced a handy application called Bazaar Explorer. You can use it to issue most of the everyday commands you will use with Bazaar. You can also use it to quickly fix your conflicts.

First, configure Bazaar so it knows how to launch your favourite merge tool.
Open up C:\Documents and Settings\YourUserName\Application Data\bazaar\2.0\bazaar.conf.
Now add a reference, with appropriate command line options, to a merge tool. I like Tortoise Merge, so to the DEFAULT section I added the line:

[DEFAULT]
external_merge = tortoisemerge /base:%b /theirs:%o /mine:%t /merged:%r

Now open up Bazaar Explorer with the command:

bzr explorer

Click File, then Open, and then navigate to the location of your bzr checkout/branch – i.e. to the location with the .bzr folder.
My branch contains a conflict so I see the following:
Bazaar explorer with a conflict

Now, let’s fix that conflict:
BazaarExplorer_ResolveConflicts

Click the Resolve Conflicts menu option and Bazaar explorer will launch qconflict (i.e. Bazaar explorer will issue the command “bzr qconflicts”):
qconflicts-use_configured_default
Select the “Use Configured Default” check box at the bottom of the dialog and you will see the text we added earlier to the bazaar.conf file.

Now it is a simple case of highlighting the file you want to edit, and then clicking the launch button. In my case, this will fire up TortoiseMerge.

After you have fixed the conflict, right click the file to tell Bazaar (i.e. issue the “bzr resolve” command):
qconflicts-resolved

Posted in Bazaar Source Control | Tagged: , | 3 Comments »

 
Follow

Get every new post delivered to your Inbox.