3.2. Demo of Mercurial
This section will demonstrate basic version control usage using the Mercurial version control system.
Please note: by choosing Mercurial I do not mean to imply that it is the best VCS out there or that you should necessarily use it. By all means, it is likely that there are other VCSes which are better in many respects. However, I'm familiar with Mercurial, and I think it is suitable for the demonstration here.
If you're interested in choosing a version control system, you can refer to these resources:
- The Better SCM Site
- The Free Version Control Systems appendix of “Producing Open Source Software” by Karl Fogel.
- The Wikipedia list of version control systems
The Demo
First of all, install Mercurial using your operating system's package manager, or by downloading an installer from the Mercurial site.
Then create a new empty directory and run hg init .
:
$p4n/5/merc-test$ hg init .
Now let's add some files. Start your favourite text editor and put these contents in the file MyModule.pm
:
# This is MyModule.pm package MyModule; use strict; use warnings; sub add { my ($x, $y) = @_; return $x+$y*2; } 1;
Now let's put it under version control:
$p4n/5/merc-test$ mkdir MyModule $p4n/5/merc-test$ cd MyModule/ $p4n/5/merc-test/MyModule$ gvim MyModule.pm # Edit it. $p4n/5/merc-test/MyModule$ ls MyModule.pm $p4n/5/merc-test/MyModule$ hg status ? MyModule/MyModule.pm
As we can see from the output of hg status
, the file is not tracked. Let's add it:
$p4n/5/merc-test/MyModule$ hg add MyModule.pm $p4n/5/merc-test/MyModule$ hg status A MyModule/MyModule.pm $p4n/5/merc-test/MyModule$
Now the file is scheduled to be committed (note the A
). Let's commit it:
$p4n/5/merc-test/MyModule$ hg commit -m "Added MyModule.pm" $p4n/5/merc-test/MyModule$ hg status $p4n/5/merc-test/MyModule$
We can see it in the output of the version control command hg log
, which, as it name implies, gives a log of what has been done in the past:
$p4n/5/merc-test/MyModule$ hg log changeset: 0:7dec17ed3e88 tag: tip user: Shlomi Fish <shlomif@ELIDED> date: Fri Jan 14 18:07:32 2011 +0200 summary: Added MyModule.pm
Now let's add a test:
$p4n/5/merc-test/MyModule$ gvim mytest.t # Test $p4n/5/merc-test/MyModule$ cat mytest.t use strict; use warnings; use Test::More tests => 1; use MyModule; is (MyModule::add(0, 0), 0, "0+0 is 0."); shlomif[homepage]:$p4n/5/merc-test/MyModule$ prove mytest.t mytest.t .. ok All tests successful. Files=1, Tests=1, 0 wallclock secs ( 0.03 usr 0.01 sys + 0.02 cusr 0.00 csys = 0.06 CPU) Result: PASS $p4n/5/merc-test/MyModule$ hg status ? MyModule/mytest.t $p4n/5/merc-test/MyModule$ hg add mytest.t $p4n/5/merc-test/MyModule$
And let's commit it as well by using hg commit
.
$p4n/5/merc-test/MyModule$ hg commit -m "Added the test."
Now let's add another test assertion:
shlomif[homepage]:$p4n/5/merc-test/MyModule$ cat mytest.t \#!/usr/bin/perl use strict; use warnings; use Test::More tests => 2; use MyModule; \# TEST is (MyModule::add(0, 0), 0, "0+0 is 0."); \# TEST is (MyModule::add(2, 0), 2, "2+0 is 2."); $p4n/5/merc-test/MyModule$ prove mytest.t mytest.t .. ok All tests successful. Files=1, Tests=2, 0 wallclock secs ( 0.03 usr 0.00 sys + 0.02 cusr 0.00 csys = 0.05 CPU) Result: PASS
However, before we commit let's see which changes have been made:
shlomif[homepage]:$p4n/5/merc-test/MyModule$ hg diff diff -r e2b34f948dcd MyModule/mytest.t --- a/MyModule/mytest.t Fri Jan 14 18:14:05 2011 +0200 +++ b/MyModule/mytest.t Fri Jan 14 18:18:57 2011 +0200 @@ -3,9 +3,13 @@ use strict; use warnings; -use Test::More tests => 1; +use Test::More tests => 2; use MyModule; \# TEST is (MyModule::add(0, 0), 0, "0+0 is 0."); + +# TEST +is (MyModule::add(2, 0), 2, "2+0 is 2."); +
This displays the differences from the working copy to the pristine version in the repository.
$p4n/5/merc-test/MyModule$ hg status M MyModule/mytest.t $p4n/5/merc-test/MyModule$ hg commit -m "Add another assertion" $p4n/5/merc-test/MyModule$ hg status
And it's committed.
We can now continue doing commits, adding more tests and fixing bugs as we go. For example, let's add another test:
$ gvim mytest.t # Edit $ hg diff @@ -3,7 +3,7 @@ use strict; use warnings; -use Test::More tests => 2; +use Test::More tests => 3; use MyModule; @@ -13,3 +13,6 @@ \# TEST is (MyModule::add(2, 0), 2, "2+0 is 2."); +# TEST +is (MyModule::add(1, 1), 2, "1+1 is 2."); + $ prove mytest.t mytest.t .. 1/3 mytest.t .. Dubious, test returned 1 (wstat 256, 0x100) Failed 1/3 subtests Test Summary Report ------------------- mytest.t (Wstat: 256 Tests: 3 Failed: 1) Failed test: 3 Non-zero exit status: 1 Files=1, Tests=3, 0 wallclock secs ( 0.03 usr 0.01 sys + 0.03 cusr 0.00 csys = 0.07 CPU) Result: FAIL
Oops! The test has failed, now we need to fix a bug. With every commit, it is important that all tests will pass (unless perhaps we are working on a branch.). Let's correct it:
$ gvim MyModule.pm $ hg diff MyModule.pm diff -r ebc249691c24 MyModule/MyModule.pm --- a/MyModule/MyModule.pm Fri Jan 14 18:20:29 2011 +0200 +++ b/MyModule/MyModule.pm Sat Jan 15 10:43:16 2011 +0200 @@ -8,7 +8,7 @@ { my ($x, $y) = @_; - return $x+$y*2; + return $x+$y; } 1;
Corrected, and now the test passes. Let's see which files changed:
$ hg status . M MyModule.pm M mytest.t
Two files are changed in the working copy. We can now put them in the repository using hg commit
:
$ hg commit -m "Fixed a bug - we did x+y*2 instead of x+y"
Now let's suppose we broke something and the change is too big to fix, and we wish to revert to the pristine version. Our version control system allows us to do that:
$ hg diff diff -r a7599e97a8d8 MyModule/MyModule.pm --- a/MyModule/MyModule.pm Sat Jan 15 10:46:24 2011 +0200 +++ b/MyModule/MyModule.pm Sat Jan 15 10:48:04 2011 +0200 @@ -8,7 +8,7 @@ { my ($x, $y) = @_; - return $x+$y; + return $x*100+$y; } 1; $ prove mytest.t mytest.t .. 1/3 \# Failed test '2+0 is 2.' \# at mytest.t line 14. \# got: '200' \# expected: '2' \# Failed test '1+1 is 2.' \# at mytest.t line 17. \# got: '101' \# expected: '2' \# Looks like you failed 2 tests of 3. mytest.t .. Dubious, test returned 2 (wstat 512, 0x200) Failed 2/3 subtests Test Summary Report ------------------- mytest.t (Wstat: 512 Tests: 3 Failed: 2) Failed tests: 2-3 Non-zero exit status: 2 Files=1, Tests=3, 0 wallclock secs ( 0.03 usr 0.01 sys + 0.02 cusr 0.00 csys = 0.06 CPU) Result: FAIL $ hg status . M MyModule.pm $ hg revert My MyModule.pm MyModule.pm~ $ hg revert MyModule.pm $ hg status . ? MyModule.pm.orig $ prove mytest.t mytest.t .. ok All tests successful. Files=1, Tests=3, 0 wallclock secs ( 0.04 usr 0.00 sys + 0.02 cusr 0.00 csys = 0.06 CPU) Result: PASS $
Now that it's working we can perform more changes, and continue to commit them. We can see the log of all our changes:
$ hg update 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg log changeset: 3:a7599e97a8d8 tag: tip user: Shlomi Fish <shlomif@ELIDED> date: Sat Jan 15 10:46:24 2011 +0200 summary: Fixed a bug - we did x+y*2 instead of x+y changeset: 2:ebc249691c24 user: Shlomi Fish <shlomif@ELIDED> date: Fri Jan 14 18:20:29 2011 +0200 summary: Add another assertion changeset: 1:e2b34f948dcd user: Shlomi Fish <shlomif@ELIDED> date: Fri Jan 14 18:14:05 2011 +0200 summary: Added mytest.t. changeset: 0:7dec17ed3e88 user: Shlomi Fish <shlomif@ELIDED> date: Fri Jan 14 18:07:32 2011 +0200 summary: Added MyModule.pm