Stop Checking in the Settings!!

Ideally configuration hangs off of the build setting or (better still) the deployment process takes care of the configuration. If you're using Puppet or Octopus to deploy your code then this is super easy. Having this sort of infrastructure isn't always feasible especially on smaller projects with smaller teams. The project I'm working on at the moment is one such codebase. We share settings.xml files, there are many of them and each developer needs to configure these files as per their own environment as well as the deployed environments - per feature. This is a problem we are very aware of and we have scheduled tickets to take care of it but in the mean time I'm going to look into how we can use Git to limit the pain of this.

I am a massive culprit for checking in settings files - everybody does it - especially the nub on the team (me)... It's really annoying to the poor person who does an update after the point and then has to rework the settings files. So here are a couple of ways we can fix this (this is very basic git stuff so if you're well versed on Git you'll be well aware of the following!):

Open up a command prompt and navigate to where you keep your git repos. Mine are normally in d:\git

Lets start with a fresh plate, run the following:

mkdir git-settings
cd git-settings
git init
view raw gistfile1.sh hosted with ❤ by GitHub
We've just created a brand new git repo for us to play with. very straight forward. We don't want to work in master so lets create a new branch:

git checkout -b dev
view raw gistfile1.sh hosted with ❤ by GitHub

Now that we have the dev branch we can make our settings file.

touch settings.xml
notepad settings.xml
view raw gistfile1.sh hosted with ❤ by GitHub
Add some dummy dev environment config to the settings.xml file. Now we can add that to the dev branch and commit it.

git add -A
git commit -m "adding settings"
view raw gistfile1.sh hosted with ❤ by GitHub
Now that that's safe and sound we can create our feature branch where we will want to do some work and manage our own config:
git checkout -b wayne
touch test.cs
notepad test.cs
view raw gistfile1.sh hosted with ❤ by GitHub
Put some code in test.cs so we can commit that into the wayne branch

git add -A
git commit -m "doing some work"
view raw gistfile1.sh hosted with ❤ by GitHub
Now lets customize the settings.xml file:

notepad Settings.xml
view raw gistfile1.txt hosted with ❤ by GitHub
Make the dev specific settings feature specific so you know if this works or not when we come to doing the switcheroo. Now we want to commit the feature specific settings into the feature branch:
git add -A
git commit -m "editing settings"
view raw gistfile1.txt hosted with ❤ by GitHub
Now we'll continue to do some more work:
notepad test.cs
view raw gistfile1.txt hosted with ❤ by GitHub
And commit that into the feature branch
git add -A
git commit -m "doing some more work"
view raw gistfile1.txt hosted with ❤ by GitHub
OK so now we have a dev branch with some settings in, we branched from dev to create a feature branch, did some work in that branch, configured the settings file to make it specific to that branch and then did even more work, big day in the office. What we want to do now is to merge the work in the feature branch to the dev branch - but we definitely do not want the settings from the feature branch to show in dev, that's just going to wind everyone up.
To do this we can revert the commit we made to push the settings into the git branch. We can check the log to see the commit and revert it. To do this run the following:
git log
view raw gistfile1.txt hosted with ❤ by GitHub

This will yield something like the following (type q to exit the log):
D:\git\cp-demo>git log
commit 9c7a9b7ccceff5d9279da2b98b9e09b1f02b17cd
Author: wdouglas@aditi.com <wdouglas@aditi.com>
Date: Thu Jul 17 14:38:31 2014 +0100
even more work on test.cs - v busy day
commit 114e19c1de39143ff8286be4a1af9a43ac472a27
Author: wdouglas@aditi.com <wdouglas@aditi.com>
Date: Thu Jul 17 14:34:00 2014 +0100
Revert "editing settings"
This reverts commit 965f41809225abbe2ed2b74d6e162e27c9c18a72.
commit c3ea3932d0849f081f30c0bf6c59eef6b018ea80
Author: wdouglas@aditi.com <wdouglas@aditi.com>
Date: Thu Jul 17 14:32:56 2014 +0100
doing some more work
commit 965f41809225abbe2ed2b74d6e162e27c9c18a72
Author: wdouglas@aditi.com <wdouglas@aditi.com>
Date: Thu Jul 17 14:30:24 2014 +0100
editing settings
commit 0d7513c4fb15a67b23df5a0b41f696aa797ce331
Author: wdouglas@aditi.com <wdouglas@aditi.com>
Date: Thu Jul 17 14:29:33 2014 +0100
doing some work
commit 213188eb1338862f9e64973b7920132f79a02520
Author: wdouglas@aditi.com <wdouglas@aditi.com>
Date: Thu Jul 17 14:28:13 2014 +0100
adding settings
(END)
view raw gistfile1.txt hosted with ❤ by GitHub
As you can see the commit with ID "965f41809225abbe2ed2b74d6e162e27c9c18a72" so to revert this commit we can issue the following command:
git revert 965f41809225abbe2ed2b74d6e162e27c9c18a72
view raw gistfile1.txt hosted with ❤ by GitHub
And then we can safely merge our feature branch into dev:
git checkout dev
git merge wayne dev
view raw gistfile1.txt hosted with ❤ by GitHub
Open up settings.xml and verify it's as expected - dev settings, not feature settings.
So that was one way of making sure we don't merge stuff we don't want to merge. If we wanted to do some more work in the feature branch and get the settings back we can use the same approach above to undo the commit made by git revert - git simply creates a compensating action to revert the commit by and this creates another commit - so we can just revert the commit created by the compensating action (which will create another compensating - git is just event sourcing after all!). Another approach is cherry pick commits from the feature branch. This will apply a single commit to the branch you are merging into. Here is the general gist of it:

git checkout wayne
notepad Settings.xml
--edit settings again
git add -A
git commit -m "changing settings again"
notepad test.cs
--do some more work in test.cs
git add -A
git commit -m "even more work on test.cs - v busy day"
git log
-- note commit hash - 00ae70510088ba6eb68390a2805c591cd6239e07
git checkout dev
git cherry-pick 00ae70510088ba6eb68390a2805c591cd6239e07
--verify test.cs
--verify settings.xml
view raw gistfile1.txt hosted with ❤ by GitHub

Git is powerful stuff - cherry picking is basically the converse to the 1st approach. It shows how useful doing small, discreet commits can be. In general there are only a small handful of git commands that I use frequently - you can do so much with a small amount of git commands it's ridiculous. But there are some extremely useful, more "advanced" features which really bring Git into it's own. I'm still learning Git but one thing I have found is that using it properly really pays off and there is always a sane solution to whatever insane mess I find myself in!

Comments