Tuesday, 2 October 2012

Baseless Merge with TFS 2010

When you would like to use Source Control Merge Wizard in Visual Studio (e.g.; by right clicking a branch folder then going to 'Branching and Merging' -> 'Merge') and you find that the intended target is not in the 'Target branch' selection that means the source does not have any relationship with the target. You can proof this from 'Branching and Merging' -> 'View Hierarchy' option. This is when we need to do baseless merge operation.

To perform this operation, we can use the merge command on TFS command line tool. The syntax is
Tf merge /baseless /recursive /version:[versionspec] [source path] [target path] 
- path can be physical folder or source control location.
- [versionspec] can be a changeset, range of (inclusive) changesets separated by '~' character, a label, a date or versions. If we don't specify /version then it will merge all changes.

Below are some examples:
- Merge all changes from branch to trunk
D:\My_Project>tf merge /baseless /recursive "$/My Project/branch/one" "$/My Project/trunk" 

- Merge all changesets up to changeset 1000
D:\My_Project>tf merge /baseless /recursive /version:1000 "$/My Project/branch/one" "$/My Project/trunk" 

- Merge only changeset 1000
D:\My_Project>tf merge /baseless /recursive /version:1000~1000 "$/My Project/branch/one" "$/My Project/trunk" 

- Merge changesets 1000 to 1010 inclusively
D:\My_Project>tf merge /baseless /recursive /version:1000~1010 "$/My Project/branch/one" "$/My Project/trunk" 

If it is happened that the merge causing a lot of checkouts of unmodified files then we can use TFS Power Tools to undo the checkouts.
D:\My Project\trunk>tfpt uu /r /noget *
'uu' - undo unchanged
'/r' - recursive
'/noget' - do the operation without getting latest

If this one is still not working and leaving a lot of unmodified files checked out, we have to do Undo Changes manually. This can be done through the Pending Changes view, right click on any file from the list then select 'Undo'. The Undo Pending Changes dialog will pop up. Check all the files then click 'Undo Changes' button. A confirmation dialog with the message "... has changed. Undo check-out and discard changes?' will be shown. Click 'No to All' button. Then all unmodified files will be reverted while the modified ones from the merge operation stay.

Team Foundation Merge Command on MSDN
Command-Line Syntax (Version Control)

Monday, 1 October 2012

Deferred Execution in LINQ Query Expression or Standard Query Operators Extension Methods

An IQueryable and IEnumerable type variable can be used to specify a query in query or method syntax (query syntax is also known as query expression while method syntax as standard query operators extension methods; see this MSDN article for definition). However the execution will take place when the items are required.

Methods such as Count(), ToList(), ToArray(), ToDictionary() or ToLookup() will iterate through items thus executing the query definition. Other methods such as Average(), Sum(), Max() and Min() will also execute the query definition.

If one of those methods mentioned above are called twice then the query definition will be executed again to get the result. The execution can be very expensive as the result may be retrieved from database, network, etc. This is done to get fresh result every time from the source.

To avoid re-executing the query definition in a query expression or standard query operators extension methods, store the result into a collection. When obtaining result from the collection, the query definition won't be run again rather the cached/stored result will be used.

Below is an example to clarify:
static void Main(string[] args)
    List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };

    int invocationsCount = 0;
    Func<int, int> func = number =>
        return number;

    // 1. define the query expression or extension methods (method invocations)
    IEnumerable<int> selection = from n in numbers
                                    select func(n);
    //IEnumerable<int> selection = numbers.Select(n => func(n));
    Console.WriteLine("1. invocationsCount = {0}", invocationsCount);

    // 2. do a loop
    foreach (var item in selection)
    Console.WriteLine("2. invocationsCount = {0}", invocationsCount);

    // 3. do a count
    Console.WriteLine("3. invocationsCount = {0}", invocationsCount);

    // 4. do an average
    Console.WriteLine("4. invocationsCount = {0}", invocationsCount);

    // 5. do another loop
    foreach (var item in selection)
    Console.WriteLine("5. invocationsCount = {0}", invocationsCount);

    // 6. do ToList() and cache it to a collection
    List<int> collection = selection.ToList();
    Console.WriteLine("6. invocationsCount = {0}", invocationsCount);

    // 7. do the loop on the cache collection
    foreach (var item in collection)
    Console.WriteLine("7. invocationsCount = {0}", invocationsCount);