Mark Needham

Thoughts on Software Development

Archive for the ‘Version Control’ Category

hg: Reverting committed changes

with one comment

Continuing with our learning with Mercurial, yesterday we wanted to revert a couple of change sets that we had previously committed and go back to an old version of the code and continue working from there.

As an example, say we wanted to go back to Revision 1 and had the following changes committed:

Revision 3
Revision 2
Revision 1
Revision 0

My original thought was that we could merge revision 1 with the current tip:

hg merge -r 1

Sadly that won’t work because we can’t merge with an ancestor:

'abort: can't merge with ancestor'

I put the question to twitter and got a few different suggestions.

The first was to use ‘revert’ and go back to revision 1 like so:

hg revert -r 1

This works pretty well although my colleague Chris Turner pointed out that we could also use ‘backout’ like so:

hg backout -merge 3
hg backout -merge 2

The neat thing about that approach is that we get 2 changesets checked in showing the reversing of the changes that we previously checked in. We therefore have a better history of what exactly we’re reverted.

With this approach we could also back out changes which weren’t right near the tip of the repository as was the case in my example.

Another alternative is to clone the repository from the revision that we want to keep:

hg clone -r 1

With this approach we would lose the history of anything beyond that revision but if that’s what we want then it’s another approach to achieve our goal!

It’d be interesting to hear your opinions on which approach you take and if there are any others to solve the problem I described.

Written by Mark Needham

April 15th, 2010 at 10:35 pm

Posted in Version Control

Tagged with

Mercurial: Early thoughts

with 4 comments

We’re using Mercurial as our source control system on the project I’m working on at the moment and since I’ve not yet used a distributed source control system on a team I thought it’d be interesting to note some of my initial thoughts.

One of the neat things about having a local repository and a central one is that you can check in lots of times locally and then push those changes to the central repository when you want everyone else to get the changes that you’ve made.

So far we’ve been pushing much more frequently than would usually be the case using something like Subversion. For example I checked in after doing some tidy up on unused references whereas with Subversion I’d probably have included that as part of another checkin.

It actually makes development more fun and reminds me of a kata I did while checking in almost every minute last year.

We’re all still very much learning Mercurial but these are some of the commands that we’ve found ourselves using a lot so far:

  • To check if there are any changes to pull from the central repository:

    hg incoming
    hg in
  • To check if we have any changes that we haven’t pushed to the central repository:

    hg outgoing
    hg out
  • To add any unversioned files and remove any missing files:

    hg addremove
  • To remove a file from the repository and from the file system:

    hg remove /file/name
  • To remove a file from the repository on the next commit but not remove it from the file system:

    hg forget /file/name
  • To pull any changes from the remote repository and update your repository with them:

    hg pull -u

    This one only completely works if you don’t have any changes locally on the files you’re pulling in. Otherwise you’ll need to do a ‘hg merge’ afterwards.

    It seems like there’s a lot more merging to do when using Mercurial than with Subversion which we’re still getting used to but seems to be more natural as we use Mercurial more.

  • To undo committing a file locally:

    hg rollback
    hg ci -X /file/to/not/commit -m"message and so on"

I’ve found Mercurial: The Definitive Guide by Bryan Sullivan and Joel’s hginit to be useful resources for learning more about this tool.

Written by Mark Needham

April 10th, 2010 at 11:43 am

Posted in Version Control

Tagged with

Mercurial: hg bisect

with 3 comments

We’ve been using Mercurial locally on the project I’ve been working on and Phil showed me a cool feature called ‘bisect‘ a couple of weeks ago which can be helpful for working out which revision we managed to break our code in.

It’s been ported across from Git and is included in Mercurial from version 1.0.0 rather than just being an extension.

From the bisect extension page:

Its behaviour is fairly simple: it takes a first revision known to be correct (i.e. without the bug) and a last revision known to be bad (i.e. with the bug). The bisect extension ouputs a revision halfway between the good and the bad ones and lets you test it. If this revision is a good one, you mark it as good with hg bisect good, otherwise you mark it as bad with hg bisect bad. In both cases, bisect outputs a new revision to test, halfway between the good and the bad ones. You repeat until only one revision is left: the culprit.

The usage has changed a bit now that it’s included as part of the initial download.

I was working on something yesterday and checking in fairly regularly before realising that I’d broken something.

I was fairly sure that the break had happened in the tip (revision 98) but I could only remember it definitely working in revision 96.

I defined the good and bad revisions like this:

hg bisect -b tip
hg bisect -g 96

In this case revision 97 was now checked out and I checked that the code was working with that revision before marking it:

hg bisect -g

It’s now able to work out that the problem is in fact in revision 98:

The first bad revision is:
changeset:   98:86260809c309
tag:         tip
user:        mneedham
date:        Fri Nov 13 16:31:02 2009 +1100
summary:     seem to have screwed up the graphs. Not sure how

I managed to mess up setting up the good and bad revisions a few times – I somehow had the impression that I needed to manually update to the original good and bad revisions which isn’t the case.

The reset command was my friend before I worked out what I was doing wrong:

hg bisect -r

It seems like a neat little feature. I’m sure there are lots of other cool things like this in Mercurial so if you know any let me know!

* Update *
As Rob points out in the comments the command is ‘bisect’ rather than ‘bisec’ as I had it originally. Both commands work for the moment though!

Written by Mark Needham

November 14th, 2009 at 11:20 am

Posted in Version Control

Tagged with , ,

Pulling from github on Windows

with one comment

My colleague Dave Cameron has been telling me about his adventures playing around with Git Sharp (a C# port of the Java Git implementation jGit) so I thought I’d get a copy of the code and have a look as well.

I tend to check out all code bases from my host machine instead of virtual machine so I got the code all checked out on the Mac and accessed it via a shared folder on my VM.

The problem with doing this is I was unable to run the tests due to the following error which I received repeatedly:

System.Security.SecurityException: That assembly does not allow partially trusted callers.
at GitSharp.Tests.ObjectCheckerTests.testInvalidCommitNoTree2()

I’m not sure exactly why I got this error but it’s probably due to the fact that I didn’t open the project in normal mode since I am accessing it on a shared drive.

I decided it would probably just be quicker to checkout the code directly from the VM instead.

I installed msysgit which all worked fine and then I went to clone my repository:

C:\Playbox>git clone git@github.com:mneedham/GitSharp.git

Which resulted in the following error:

Initialized empty Git repository in C:/Playbox/GitSharp/.git/
Permission denied (publickey).
fatal: The remote end hung up unexpectedly

I had the public key setup on my github account from when I was using Git from my Mac but I hadn’t setup the private key that it requires inside my VM!

Browsing through the instructions on the github website I realised that I needed to copy my private key into the ‘.ssh’ folder (which as I understand is the default folder for ssh settings to be stored).

This folder needs to be at the root of your user folder rather than at the root of the drive as I originally thought.

Therefore it should be at ‘C:/Documents and Settings/Administrator/.ssh’ for example rather than ‘C:/.ssh’ as I mistakenly had it.

I couldn’t find a way to create a folder which started with a ‘.’ from Windows explorer so I just created a folder called ‘ssh’ and then renamed it using ‘mv ssh .ssh’ from the command line.

I then copied my private key (which I got from the Mac by running ‘less ~/.ssh/id_rsa’) into a file called ‘id_rsa’ inside the ‘.ssh’ folder and all was good:

C:\Playbox>git clone git@github.com:mneedham/GitSharp.git
Initialized empty Git repository in C:/Playbox/GitSharp/.git/
Enter passphrase for key '/c/Documents and Settings/Administrator/.ssh/id_rsa':
remote: Counting objects: 3138, done.
remote: Compressing objects: 100% (880/880), done.
remote: Total 3138 (delta 2319), reused 3039 (delta 2220)
Receiving objects: 100% (3138/3138), 3.72 MiB | 191 KiB/s, done.
Resolving deltas: 100% (2319/2319), done.
Checking out files: 100% (505/505), done.

In the process of working out what I’d done wrong I came across a nice post by Sergio Pereira which describes the whole process of getting up and running with Git in more detail.

Written by Mark Needham

August 18th, 2009 at 12:33 am

Posted in Version Control

Tagged with ,

Mercurial: Pulling from behind a proxy

with 10 comments

I’ve been playing around with Mercurial and the mercurial hosting website bitbucket a bit this year and recently wanted to pull from a repository from behind a proxy server.

With a bit of help from the mercurial mailing list and the documentation this is how I was able to pull the repository for the Hambread project I’ve been doing a bit of work on:

hg --config http_proxy.host=ipOfYourProxyServer:portOfYourProxyServer --config http_proxy.user=user --config http_proxy.passwd=password pull http://bitbucket.org/markhneedham/hambread

After that command a ‘hg update’ updates your local repository with all the changes that have just been pulled.

What I found strange was that you needed to define the ‘– config’ part of the command three times as far as I can tell in order to pass each of the different properties related to the proxy.

I tried just defining it once and just setting the properties individually but that just produced errors.

Written by Mark Needham

May 13th, 2009 at 7:49 am

Posted in Version Control

Tagged with ,

Ignore file in Svn

with 2 comments

I spent a bit of time this afternoon marveling at the non intuitiveness of working out how to ignore files in Svn.

Normally I’d just use Tortoise SVN as it makes it so easy for you but I really wanted to know how to do it from the shell!

After a bit of Googling and conversation with a colleague I think I have it figured out to some extent.

Ignoring just one file or pattern

If you only have one pattern or file that you want to ignore then the following command should do the trick.

svn propset svn:ignore <file_or_pattern_to_ignore> <dir_in_which_to_create_ignore_file>

For example:

svn propset svn:ignore build .

This means my ‘build’ directory will now be ignored and the svn ignore file will be placed in the current directory.

Ignoring multiple files or patterns

The problem with the above approach comes when you want to ignore more than one pattern/file. If you just run the propset command again it overrides the current svn ignore file with the current value – clearly not what we want!

Luckily propedit comes to the rescue.

Running the following command will open up your chosen editor and allow you to edit the svn ignore file.

svn propedit svn:ignore <dir_where_ignore_file_resides>

When I initially did this I received the following error:

svn: None of the environment variables SVN_EDITOR, VISUAL or EDITOR is set, and no 'editor-cmd' run-time configuration option was found

I wanted my default editor to be Textmate so I entered the following:

export SVN_EDITOR=mate

This didn’t seem to work for me – the svn tmp file being opened up in Textmate was always empty for some reason. Changing my editor to vi seemed to fix the problem.

export SVN_EDITOR=vi

Running the command now opens up vi and allowed me to add the pattern ‘*.log’ to my ignore list. If it is added successfully the following message will show up on exiting vi:

Set new value for property 'svn:ignore' on '.'

Seeing which files or patterns are currently ignored

While having my Textmate problems detailed above my colleague pointed out the propget command which shows you which files/patterns are currently being ignored.

svn propget svn:ignore .

Running this command shows me the following:

build
*.log

svnbook has even more goodness on ignoring files for those that are interested.

Written by Mark Needham

October 2nd, 2008 at 9:10 pm

Posted in Version Control

Tagged with ,

Getting latest tagged revision in SVN from DOS/Batch script

with 3 comments

The way we have setup the build on our continuous integration server, Team City is configured to create a new tag every time the functional tests past successful on that machine.

We then have a QA and Showcase build that we can run to deploy all the artifacts necessary to launch the application on that machine.

Originally I had just written the batch script to take in the tag of the build which the user could find by looking through repo-browser for the last tag created. This quickly became very tedious so I started looking for a way to get the latest tagged revision from the command line.

We thought it would be possible to get this information using svn info but it turned out that the information returned by svn info about revisions doesn’t necessarily refer to the latest created tag. We ended up using svn log and then parsing through that data. It’s a bit messy but it does the job (I name each tagged version of the code as ‘build-{TeamCity-Build-Number}):

1
2
FOR /F "Tokens=2" %%i in ('svn log /tags/path --limit=1 -v ^| find "build"') do set TMP=%%i
FOR /F "Tokens=2 delims=/" %%i in ('echo %TMP%') do SET TAG=%%i

The for loop uses a space as its default delimiter so that’s what the ‘delims=/’ is doing on the second line, the ‘Tokens=2’ allows us to get the second token after the string is split and the ‘^’ in the first command is being used to escape the pipe.

Written by Mark Needham

August 16th, 2008 at 12:10 am