Archive for the ‘Source Control’ Category.

Why you should avoid multiline string literals in C# with Git

Recently I started using Continuous Integration (CI) for my open source C# projects on GitHub. I found a would provide me this for free for my open source projects. I setup a few of my projects on the AppVeyor’s CI.

Unfortunately, one of my projects, Rhyous.EasyXml, failed four out of ten unit tests on the CI server. This made no sense. I had the code checked out on a work desktop and a laptop and all ten tests passed in both places.

I had a string that my EasyXml code generates. I had the expected Xml in the following multiline string literal.

        public string PrettyUtf8Xml =
@"<?xml version=""1.0"" encoding=""UTF-8""?>
  <MiddleName>Al Leon</MiddleName>

The test results were not helpful because the string results in the test output were identical.

Starting test execution, please wait... 
Passed   TestMethodLinearize 
Failed   TestMethodPretty 
Error Message: 
   Assert.AreEqual failed. Expected:<<?xml version="1.0" encoding="UTF-8"?>
  <MiddleName>Al Leon</MiddleName>
</Person>>. Actual:<<?xml version="1.0" encoding="UTF-8"?>
  <MiddleName>Al Leon</MiddleName>
Stack Trace: 
   at Rhyous.EasyXml.Tests.XmlTests.TestMethodPretty() in C:\projects\easyxml\src\Unit Tests\Rhyous.EasyXml.Tests\XmlTests.cs:line 102

My first guess was that somehow my UTF-8 vs UTF-16 code wasn’t working and I set up to figure out how to compare the strings in a way that shows me the difference. I quickly found a wonderful string extension method ShouldEqualWithDiff for Unit Tests by Phil Haack. Phil Haack’s extension method is extremely helpful because it provides a verticle character by character output of the string if the comparison fails.

This provided the following output and pointed the finger of the problem directly at Git. See the highlighted lines 59 and 60 below that show that characters 38 and 39 fail to match up.

Failed   TestMethodPretty 
Error Message: 
   Assert.AreEqual failed. Expected:<<?xml version="1.0" encoding="UTF-8"?>
  <MiddleName>Al Leon</MiddleName>
</Person>>. Actual:<<?xml version="1.0" encoding="UTF-8"?>
  <MiddleName>Al Leon</MiddleName>
Stack Trace: 
   at Rhyous.EasyXml.Tests.StringExtensions.ShouldEqualWithDiff(String actualValue, String expectedValue, DiffStyle diffStyle, TextWriter output) in C:\projects\easyxml\src\Unit Tests\Rhyous.EasyXml.Tests\StringExtensions.cs:line 50
   at Rhyous.EasyXml.Tests.StringExtensions.ShouldEqualWithDiff(String actualValue, String expectedValue) in C:\projects\easyxml\src\Unit Tests\Rhyous.EasyXml.Tests\StringExtensions.cs:line 12
   at Rhyous.EasyXml.Tests.XmlTests.TestMethodPretty() in C:\projects\easyxml\src\Unit Tests\Rhyous.EasyXml.Tests\XmlTests.cs:line 102
Standard Output Messages: 
     Idx Actual    Expected
     0   60   <    60   <  
     1   63   ?    63   ?  
     2   120  x    120  x  
     3   109  m    109  m  
     4   108  l    108  l  
     5   32   \u20;  32   \u20;
     6   118  v    118  v  
     7   101  e    101  e  
     8   114  r    114  r  
     9   115  s    115  s  
     10  105  i    105  i  
     11  111  o    111  o  
     12  110  n    110  n  
     13  61   =    61   =  
     14  34   "    34   "  
     15  49   1    49   1  
     16  46   .    46   .  
     17  48   0    48   0  
     18  34   "    34   "  
     19  32   \u20;  32   \u20;
     20  101  e    101  e  
     21  110  n    110  n  
     22  99   c    99   c  
     23  111  o    111  o  
     24  100  d    100  d  
     25  105  i    105  i  
     26  110  n    110  n  
     27  103  g    103  g  
     28  61   =    61   =  
     29  34   "    34   "  
     30  85   U    85   U  
     31  84   T    84   T  
     32  70   F    70   F  
     33  45   -    45   -  
     34  56   8    56   8  
     35  34   "    34   "  
     36  63   ?    63   ?  
     37  62   >    62   >  
   * 38  13   \r   10   \n 
   * 39  10   \n   60   <  
   * 40  60   <    80   P  
   * 41  80   P    101  e  
   * 42  101  e    114  r  
   * 43  114  r    115  s  
   * 44  115  s    111  o  
   * 45  111  o    110  n  
   * 46  110  n    62   >  
   * 47  62   >    10   \n 
   * 48  13   \r   32   \u20;
   * 49  10   \n   32   \u20;
   * 50  32   \u20;  60   <  
   * 51  32   \u20;  70   F  
   * 52  60   <    105  i  
   * 53  70   F    114  r  
   * 54  105  i    115  s  
   * 55  114  r    116  t  
   * 56  115  s    78   N  
   * 57  116  t    97   a  
   * 58  78   N    109  m  
   * 59  97   a    101  e  
   * 60  109  m    62   >  
   * 61  101  e    74   J  
   * 62  62   >    111  o  
   . . .

The cause is carriage returns. Why would AppVeyor’s tests have only \n while running the tests on any of my machines has \r\n? Yes, Git is the reason. Git normalizes carriage returns when you check in and check out your code. On a Windows box, \r\n is converted to \n on check-in. On checkout \n is converted to \r\n. When AppVeyor checks out my code, the conversion from \n to \r\n doesn’t occur.

So my options to fix this are these:

  1. Change Git to:
    1. use \r\n and not change line endings at all
    2. Change my code to be a single line string

    I chose the second option. I did not want to mess with the Git settings. Different people could have difference Git settings and if anyone else forked my code, and ran the tests, I wanted them to work. So I changed my code. Now the string literal is on one line and the new lines are indicated with \r\n.

            public string PrettyUtf8Xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<Person>\r\n  <FirstName>John</FirstName>\r\n  <MiddleName>Al Leon</MiddleName>\r\n  <LastName>Doe</LastName>\r\n</Person>";

    And now my Continuous Integration on AppVeyor is building and passing tests.

Sharing checked out source between Visual Studio instances on Virtual Machines using a network share

I have a lot of Virtual Machines and having to checkout a large code base from source control to each box is annoying and time consuming. There are a couple of branches that take almost an hour to get the latest code.

I am using Visual Studio and TFS. Visual Studio and TFS is installed on all my VMs. So I set out to have the VM host store the source and then all the Virtual Machines map a drive to the host.

At first this appeared to work just fine, but then I started to run into errors. I fixed the errors one at a time.

There were a few things I had to do to make this work and I thought I would share them:

System Changes

  1. Map the drive and make it persistent. That means the drive stays mapped after reboot.
  2. Add the mapped drive as a local intranet site in Internet Explorer’s Security settings.

Visual Studio Changes

  1. Make sure to always log into to TFS in Visual Studio with the same user account. There will be TFS problems if you use a different user account.
  2. Add the loadFromRemoteSources tag to the section of the devenv.exe.config file and set it to true:

    Note: I had to run Notepad++ as administrator to make this change.

    Visual Studio 2010:
    C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe.configVisual Studio 2012
    C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe.config

  3. Add the loadFromRemoteSources tag to other .config files.
    Note: In order to debug a web service, I had to also add this tag to the  WcfSvcHost.exe.config.

    Visual Studio 2010:
    C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\WcfSvcHost.exe.config

    Visual Studio 2012
    C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\WcfSvcHost.exe.config

    In that IDE folder there were a 22 .config files in VS 2010 and 32 in VS 2012. I am not sure which ones will ever need this. There are two schools of thought: 1. Add the loadFromRemoteSources tag to all of the config files or 2. Add them only when you encounter and error. Since I am in a lab environment and everything is on one physical box (the host and the hosted VMs) I went ahead and added this to all the config files.

  4. Sometimes when running Visual Studio as administrator, the mapped drive appears off line. Simple click File | Open | File and browse to the network drive. You don’t have to actually open anything. Just click cancel. It seems as soon as you browse to the mapped drive, Visual Studio knows about it and everything works fine.This doesn’t seem to work as well in VS 2012 on Windows Server 2012.  You may even have to have the drive mapped twice. Once as the logged in user and once as the Administrator. To do this open two command prompts: 1. A regular command prompt. 2. A command prompt running as Administrator. Run the mapped drive command in both: (Yes, use the same drive letter in both on Windows 2013 or Windows 8)

    net use z: \\pcname.domain.tld\yourshare /PERSISTENT:YES

Be aware you’ll get more prompts

I noticed than when running executables orVBScripts or PowerShell scripts, that I was prompted. This is because your running them from a network share, which is completely fine as long as you trust the network share.


Having all your Virtual Machines share the same source repository is possible and saves a lot of time checking out code as you don’t have to do it an each Virtual Machine.

Doing this for multiple users did not work well as the we used TFS and the source seemed to be tied to the user.

I have not yet tried to share between VS 2010 and VS 2012. I hope that works…I’ll update when I know.

Feature branching fits the Kanban model – Branching by MMF

I have to say I am a fan of branching for feature or for team.  I think branching for feature, or branching for a Minimal Marketable Feature (MMF), really fits into the Kanban model.

However, decouple first. This article was really good about talking about a decoupling branching strategy.

Once decouple, branch by feature or in the Kanban world, Branch by MMF.

Here are the positive and negatives.

Branch by feature or team (team and feature are similar)




Having read all of these. The negatives are important to read.

It seems that a lot of the negatives are eliminated by the following.

  1. Decoupled code
  2. Using Interface-based design (which is a method for decoupling code)
  3. Keeping MMFs as small as possible (which they should be anyway: “Minimal” marketable feature
  4. Merging main to the feature branch daily/weekly
  5. Running tests on CI on feature branches as well as on main
  6. Checkin’s are gated so a failed build/test prevents check in.

Also read the comments as there are real experiences shared there (assuming the author of the comments are sincere).

A successful branch by MMF strategy can be done with any source control tool.

Side Note 1:

I’ve been using GIT lately for a project in my Masters of Computer Science’s Security course. I finally understand why GIT has become the de facto source control for Open Source, because branching on your local machine can be helpful and efficient. The local check out on your dev box IS A BRANCH and can be branched and you can branch by feature or by task locally.

I recently wrote something I couldn’t check in and couldn’t branch it locally with our source control, but I could have with GIT.

Side Note 2:

Another side note: TortoiseGit and TortoiseSVN are both on my dev box now and explorer.exe is constantly at 45% CPU slowing my system.