Learn » Source-Control » Intro Source Control.md

Intro Source Control

These materials are built upon the great tutorial hginit.com.

Mercurial is a source control system. Developers use it to manage source code, but it can be used to manage any line based text files. It serves two important purposes:

  1. It keeps track of every old version of every file
  2. It can merge different versions of your files, so that teammates can work independently on the file and then merge their changes

Without version control, you could try to keep old versions just by making a lot of copies of the directory containing all your file but this is tedious, takes up a lot of disk space, and confusing. Using version control is a better way to do this.

Most people work with Mercurial through the command line, which works on Windows, Unix, and Mac. The command for Mercurial is hg:

$ hg
Mercurial Distributed SCM

basic commands:

 add           add the specified files on the next commit
 annotate, blame
               show changeset information by line for each file
 clone         make a copy of an existing repository
 commit, ci    commit the specified files or all outstanding changes
 diff          diff repository (or selected files)
 export        dump the header and diffs for one or more changesets
 forget        forget the specified files on the next commit
 init          create a new repository in the given directory
 ...

Typing hg without anything else gives you a list of the most common commands that are available. You can also try hg help for a complete list of commands.

To take advantage of version control, you needed a repository. A repository stores all your old versions of every file. To save disk space, it’s not actually going to store every old version—it’s just going to store a compact list of changes.

In the old days, getting a repository was a big deal. You had to have a central server somewhere and you had to install software on it. Mercurial is distributed, so you can use it without a fancy central server. You can run it entirely on your own computer. And getting a repository is super-easy: you just go into the top-level directory where all your code lives and type hg init

$ mkdir ~/Desktop/potato_salad
$ cd ~/Desktop/potato_salad
$ hg init

There isn't any output, but if you look closely you can see a .hg directory was created for you.

$ ls -A1
.hg

That’s the repository! It’s a directory full of everything Mercurial needs. Settings, old version of files, tags, an extra pair of socks for when it rains, etc. Don’t go in there. You are almost never going to want to mess with that directory directly.

I've used Mercurial for years now and the only file I have ever edited under .hg is hgrc which contain some configuration details.

The existence if the .hg directory is also how the hg command knows what repository you are working on, it is based on where are you are when you run it. It looks in the current directory and above for a .hg directory.

Adding Files

So far we have an empty Mercurial repository. Next we want to add something, we are going to work with a recipe for potato salad. Potato salad was all the range and recipes are an example of the kind of thing source control is great for. Text which is strongly delineated by lines.

Let's start with my family recipe for potato salad

Potato Salad
============

    1 1/2 pounds of new round red potatoes, cut in to bite size pieces and boiled until just tender
        1 cup of mayonaise
        1 tablespoon of yellow mustard
        1 tablespoon of white wine vinegar
        2 teaspoons of sugar
    pinch of ground black pepper
    pinch of salt
      1/3 cup sweet pickle relish
      1/3 cup green onions, sliced
        3 hardboiled eggs, coarsely chopped

In a very large bowl stir together all the ingredients adding the potatoes and eggs last. Toss to coat. Cover and chill for 2 to 24 hours.

You can either copy the above text and save it as recipe.md or you can download it (right click and Save As). Make sure you save it or place it under ~/Desktop/potato_salad.

Now when you ls you should see the follow.

$ ls -A1
.hg
recipe.md

To add recipe.md is easy, just type hg add.

$ hg add
adding recipe.md

There’s still one more step, you have to commit your changes. What changes? The change of adding all those files.

Why do you have to commit? With Mercurial, committing says "hey, the way the files look right now—please remember that." It’s like making a copy of the whole directory, every time you have something that you've changed that you sorta like, you commit.

$ hg commit -m "Adding recipe.md"
recipe.md
committed changeset 0:260e17046da2

Before you commit for the first time you have to tell hg who you are. The easiest way to do this is

nano ~/.hgrc

And copy in this text and supply your own name and email.

[ui]
username = John Doe <john@example.com>
verbose = True

Save the file and try committing again.

hg commit -m

I always use -m and then write my commit message. If you don't an editor will pop up, you can edit the file and then save the result, but I think -m is just easier.

Commit Messages?

Writing good commit messages is a bit tricky. It is note to your future self when you are trying to find out when something changed. The key to start is to always write something. Try to be concise and answer the question, why are these changes being made?

You can type hg log to see a history of changes. It’s like your repository’s blog:

$ hg log
changeset:   0:260e17046da2
tag:         tip
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Sat Aug 23 17:47:03 2014 -0400
files:       recipe.md
description:
Adding recipe.md

Editing

Let’s edit the recipe and see what happens. Open up recipe.md in your favourite text editor and make the following changes.

 5. 1 cup of light mayonaise

11. 1/3 cup dill pickle relish

On line 5 add the word "light" and on line 11 change "sweet" to "dill".

Now Mercurial can show which files have changed and what the changes look like.

$ hg status
M recipe.md
$ hg diff
diff -r 260e17046da2 recipe.md
--- a/recipe.md Sat Aug 23 17:47:03 2014 -0400
+++ b/recipe.md Sun Aug 24 17:22:49 2014 -0400
@@ -2,13 +2,13 @@
 ============

     1 1/2 pounds of new round red potatoes, cut in to bite size pieces and boiled until just tender
-        1 cup of mayonaise
+        1 cup of light mayonaise
         1 tablespoon of yellow mustard
         1 tablespoon of white wine vinegar
         2 teaspoons of sugar
     pinch of ground black pepper
     pinch of salt
-      1/3 cup sweet pickle relish
+      1/3 cup dill pickle relish
       1/3 cup green onions, sliced
         3 hardboiled eggs, coarsely chopped

hg status shows a file by file list of changes. Here the output is

M recipe.md

M means recipe.md has been modified. A would mean the file has been added, ? would mean Mercurial doesn't know about the file, R means the file will be removed and ! means the file is missing.

hg diff list all the changes line by line including some context. Here we see most of the file file but it focus on the two lines which have changed. - at the beginning of the line means that line will be removed and + that line will be added.

The diff algrothim works better one file where each line has significance. It can be used for long bodies of text, but it isn't as optimal.

Now we know that Mercurial thinks of the current state, we can commit these changes like we did before.

$ hg commit -m "Make the mayonaise light and change to dill relish."
recipe.md
committed changeset 1:afa732ca6064

Use hg log again to see the repos history.

$ hg log
changeset:   1:afa732ca6064
tag:         tip
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Sun Aug 24 17:28:21 2014 -0400
files:       recipe.md
description:
Make the mayonaise light and change to dill relish.


changeset:   0:260e17046da2
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Sat Aug 23 17:47:03 2014 -0400
files:       recipe.md
description:
Adding recipe.md

Like any modern blogger, Mercurial puts the newest stuff on top.

I’m going to make one more change to see the whole process again. Add the following line to the bottom of the file.

Serves 6,911

Here is the whole process you should do when you make a change from status to log.

$ hg status
M recipe.md
$ hg diff
diff -r afa732ca6064 recipe.md
--- a/recipe.md Sun Aug 24 17:28:21 2014 -0400
+++ b/recipe.md Sun Aug 24 17:35:07 2014 -0400
@@ -13,3 +13,5 @@
         3 hardboiled eggs, coarsely chopped

 In a very large bowl stir together all the ingredients adding the potatoes and eggs last. Toss to coat. Cover and chill for 2 to 24 hours.
+
+Serves 6,911
$ hg commit -m "Note the number of servings."
recipe.md
committed changeset 2:f876bb636517
Air-Jackson:potato_salad amjoconn$ hg log
changeset:   2:f876bb636517
tag:         tip
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Sun Aug 24 17:35:30 2014 -0400
files:       recipe.md
description:
Note the number of servings.


changeset:   1:afa732ca6064
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Sun Aug 24 17:28:21 2014 -0400
files:       recipe.md
description:
Make the mayonaise light and change to dill relish.


changeset:   0:260e17046da2
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Sat Aug 23 17:47:03 2014 -0400
files:       recipe.md
description:
Adding recipe.md

OK, that was a lot of fun. I made some changes, and each time I made a significant change, I committed it to the repository.

I know what you’re thinking. You’re thinking, “THIS ALL SEEMS LIKE A BIG WASTE OF TIME.” Why go through all this rigamarole of committing?

Patience, young grasshopper. You’re about to learn how to get some benefit out of this.

Number one, let’s say you make a huge mistake editing, like you delete your file.

rm recipe.md

Go ahead do it.

Do it, don't be scared.

In the days before Mercurial, this would be a good opportunity to go crying to the system administrator and asking piercingly sad questions about why the backup system is “temporarily” out of commission and has been for the last eight months.

I mean maybe you use some kind of back up solution on your own computer, but restoring can be being pain. Anyway, yeah, there’s no backup.

Thanks to Mercurial, though, when you’re unhappy with your changes, you can just issue the handy command hg revert which will immediately revert your directory back to the way it was at the time of the last commit.

Let's check the status and then revert

$ hg status
! recipe.md
$ hg revert --all
reverting recipe.md

We used the command line argument --all because we wanted to revert all files back to their original state. You can also revert a single file at a time.

Like magic our recipe is back form the dead! We also saw with hg status that Mercurial knew that the file was supposed to be there. If coding some times feels scary like you are a trapeze artist then source control is your trust safety net. When some text has been committed Mercurial will work very heard to make your you do not indavertly delete it.

So, when you’re working on source code with Mercurial:

  1. Make some changes
  2. See if they work
  3. Use status to see what changes
  4. Use diff to see the changes in detail
  5. If you like them, commit them
  6. If they don’t, revert them
  7. Repeat

Removing Files

What if you actually wanted remove a file, maybe you accidentally added something to your repo? That is easy as well.

.hgignore

There is a handy configure file which lives beside .hg which can specify files and directories Mecurial should always ignore. It is handy for .pyc file or build directories.

Read the doc about .hgignore syntax

Let's add a garbage file to the repo.

$ touch badfile.txt  # or use your text editor to create thie file
$ hg add
adding badfile.txt
$ hg status
A badfile.txt
$ hg commit -m "Add a bad file"
badfile.txt
committed changeset 3:9a3a2a2b6053
$ ls -lA
.hg
badfile.txt
recipe.md

You can use hg rm to explicitly remove the file both from the disk and from the repository.

$ hg remove badfile.txt
removing badfile.txt
$ hg status
R badfile.txt

Just like when you make changes and add files you need commit the removal.

$ hg commit -m "Remove the bad file"
committed changeset 4:148da6f2ab2a
$ ls -lA
.hg
recipe.md
$ hg log
changeset:   4:148da6f2ab2a
tag:         tip
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Mon Aug 25 17:12:30 2014 -0400
files:       badfile.txt
description:
Remove the bad file


changeset:   3:9a3a2a2b6053
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Mon Aug 25 17:10:14 2014 -0400
files:       badfile.txt
description:
Add a bad file


changeset:   2:f876bb636517
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Sun Aug 24 17:35:30 2014 -0400
files:       recipe.md
description:
Note the number of servings.


changeset:   1:afa732ca6064
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Sun Aug 24 17:28:21 2014 -0400
files:       recipe.md
description:
Make the mayonaise light and change to dill relish.


changeset:   0:260e17046da2
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Sat Aug 23 17:47:03 2014 -0400
files:       recipe.md
description:
Adding recipe.md

Time Travel

One more thing about the output from hg log: the changeset line shows us a number to every commit-actually two numbers: a handy, short one, like “0” for your initial revision, etc., and a long, goofy hexadecimal one which you can ignore for now.

Remember that Mercurial keeps, in the repository, enough information to reconstruct any old version of any file.

First of all, the simple command hg cat can be used to print any old version of a file. For example, to see what recipe.md looks like now:

$ hg cat recipe.md 
Potato Salad
============

    1 1/2 pounds of new round red potatoes, cut in to bite size pieces and boiled until just tender
        1 cup of light mayonaise
        1 tablespoon of yellow mustard
        1 tablespoon of white wine vinegar
        2 teaspoons of sugar
    pinch of ground black pepper
    pinch of salt
      1/3 cup dill pickle relish
      1/3 cup green onions, sliced
        3 hardboiled eggs, coarsely chopped

In a very large bowl stir together all the ingredients adding the potatoes and eggs last. Toss to coat. Cover and chill for 2 to 24 hours.

Serves 6,911

To see what it looked like in the past, I can just pick a changeset number from the log. Then I use the cat command with the -r (“revision”) argument:

$ hg cat -r 0 recipe.md
Potato Salad
============

    1 1/2 pounds of new round red potatoes, cut in to bite size pieces and boiled until just tender
        1 cup of mayonaise
        1 tablespoon of yellow mustard
        1 tablespoon of white wine vinegar
        2 teaspoons of sugar
    pinch of ground black pepper
    pinch of salt
      1/3 cup sweet pickle relish
      1/3 cup green onions, sliced
        3 hardboiled eggs, coarsely chopped

In a very large bowl stir together all the ingredients adding the potatoes and eggs last. Toss to coat. Cover and chill for 2 to 24 hours.

There is our original reciple potato salad!

If you want to see what changed in a file over time you can use the diff command with -r.

$ hg diff -r 0:1 recipe.md
diff -r 260e17046da2 -r afa732ca6064 recipe.md
--- a/recipe.md Sat Aug 23 17:47:03 2014 -0400
+++ b/recipe.md Sun Aug 24 17:28:21 2014 -0400
@@ -2,13 +2,13 @@
 ============

     1 1/2 pounds of new round red potatoes, cut in to bite size pieces and boiled until just tender
-        1 cup of mayonaise
+        1 cup of light mayonaise
         1 tablespoon of yellow mustard
         1 tablespoon of white wine vinegar
         2 teaspoons of sugar
     pinch of ground black pepper
     pinch of salt
-      1/3 cup sweet pickle relish
+      1/3 cup dill pickle relish
       1/3 cup green onions, sliced
         3 hardboiled eggs, coarsely chopped

0:1 meand start with revision 0 and compare to revision 1. You could do the reverse, and compare revision 1 with revision 0, 1:0 or revision 0 with revision 4, 0:4. Give it a try.

One last thing, update enables you to actually checkout old versions on to your disk, check it out:

$ hg update -r 0
resolving manifests
getting recipe.md
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cat recipe.md
Potato Salad
============

    1 1/2 pounds of new round red potatoes, cut in to bite size pieces and boiled until just tender
        1 cup of mayonaise
        1 tablespoon of yellow mustard
        1 tablespoon of white wine vinegar
        2 teaspoons of sugar
    pinch of ground black pepper
    pinch of salt
      1/3 cup sweet pickle relish
      1/3 cup green onions, sliced
        3 hardboiled eggs, coarsely chopped

In a very large bowl stir together all the ingredients adding the potatoes and eggs last. Toss to coat. Cover and chill for 2 to 24 hours.
$ hg update -r 1
resolving manifests
getting recipe.md
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cat recipe.md
Potato Salad
============

    1 1/2 pounds of new round red potatoes, cut in to bite size pieces and boiled until just tender
        1 cup of light mayonaise
        1 tablespoon of yellow mustard
        1 tablespoon of white wine vinegar
        2 teaspoons of sugar
    pinch of ground black pepper
    pinch of salt
      1/3 cup dill pickle relish
      1/3 cup green onions, sliced
        3 hardboiled eggs, coarsely chopped

In a very large bowl stir together all the ingredients adding the potatoes and eggs last. Toss to coat. Cover and chill for 2 to 24 hours.
$ hg update
resolving manifests
getting recipe.md
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cat recipe.md
Potato Salad
============

    1 1/2 pounds of new round red potatoes, cut in to bite size pieces and boiled until just tender
        1 cup of light mayonaise
        1 tablespoon of yellow mustard
        1 tablespoon of white wine vinegar
        2 teaspoons of sugar
    pinch of ground black pepper
    pinch of salt
      1/3 cup dill pickle relish
      1/3 cup green onions, sliced
        3 hardboiled eggs, coarsely chopped

In a very large bowl stir together all the ingredients adding the potatoes and eggs last. Toss to coat. Cover and chill for 2 to 24 hours.

Serves 6,911

hg update is actually modifying every file in the directory that changed to go backwards and forwards through time. If a file was added or removed, it adds or removes it. Without any arguments, hg update goes to the latest version.

Test yourself

OK! That’s it for part 1. Here’s all the things you should know how to do now:

  1. Create a repository
  2. Add and remove files in a repository
  3. After making changes, see what uncommitted changes you made, then
  4. commit if you like them,
  5. or revert if you don’t.
  6. See old versions of files, or even move your directory backwards and forwards in time

Sharing Code and Working with Others

So far we have used Mercurial on your local machine, and it is very useful especially for experimentation, but there is more. You can use source control like Mecurial to share your code and collaborate with people all over the world.

Webservices like bitbucket.org host your Mercurial repository enabling to see your code and changes online. Other people can make a copy of your code, called "forking", make some local changes and then request that you include their changes, called a "pull request". It is entirely up to you to accept or reject these changes. This approach really opens amazing possibility for collaboration.

For the paranoid, you may not truth a 3rd party service, but since every copy of your repository is a complete copy, you can use a service without depending on it.

Let's look at what is would take to share you potato salad with the world.

Publish to bitbucket.org

The first step is to create a bitbucket.org account which should be pretty easy and free.

Free Repositories and Educational Pricing

Bitbuckets allow open source repos with unlimited collaborates and private repos with up to 5 collaborators for free. If you sign up with an educational email such as @uwaterloo.ca you can collaborate is more people in a private repo.

Once logged in select Repositories > Create Repository. Call the repositorypotato_salad, make sure it is Mecurial, and make it public.

On the project page expand the "I have an existing project" section and follow the instructions.

$ hg push https://[username]@bitbucket.org/[username]/potato_salad
searching for changes
5 changesets found
remote: adding changesets
remote: adding manifests
remote: adding file changes
remote: added 5 changesets with 4 changes to 2 files

Replace [username] with your Bitbucket username.

Use your favorite editor to create a file under that .hg folder which is your repository called hgrc if it doesn't already exist. The file should contain the following

[paths]
default = https://[username]@bitbucket.org/[username]/potato_salad

Again replace [username] with your Bitbucket username.

We have made this change to make pushing and pulling changes easier. What does pushing and pulling mean? more on that soon.

Right now though you can view you awesome repository including your history online in full HD enhanced graphics, non of this text based hg log stuff.

https://bitbucket.org/<username>/potato_salad/commits/all

You can look at the history and file. If you enabled them you could get an issue tracker and an wiki as well.

You and Your Imaginary Friend

To play with collaboration we are going to need to create a repository for our imaginary friend, lets call her Jill. Create a folder for Jill's copy of the repository under your desktop.

$ mkdir -p ~/Desktop/jill/potato_salad
$ cd ~/Desktop/jill/potato_salad
$ ls -A1

Jill's potato salad folder is empty and distinct from the work we have been doing so far, but we can quickly change that.

$ hg clone https://[username]@bitbucket.org/[username]/potato_salad .
requesting all changes
adding changesets
adding manifests
adding file changes
added 5 changesets with 4 changes to 2 files
updating to branch default
resolving manifests
getting recipe.md
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ ls -A1
.hg
recipe.md

This fetches the a copy of the whole repository and places it in Jill's folder, which could be on a different computer. It might be right beside your original copy, but use your imagination, it could be anywhere in the world. All this will one relatively simple command!

A Rose by any other Username

Something we have glossed over is Jill probably has a different Bitbucket username. Let's say Jill's username was jillisawesome22, then the clone url would look like this.

$ hg clone https://jillisawesome22@bitbucket.org/[username]/potato_salad .

The first username, the one before @bitbucket.org is the username for the user cloning the repo, the second one is the username of the owner of the repo.

Lock it down with SSH Keys

We are using http based auth with username and passwords. If you are comfortable with it, using ssh keys is much more secure. You can upload your public key to Bitbucket. You can also add public keys for deployment (read access) only. You can read about it in their docs: https://confluence.atlassian.com/display/BITBUCKET/Add+an+SSH+key+to+an+account

Jill tried making the potato salad, and discovered that the recipe could be improved by providing guidence on how long to boil the potatos.

    1 1/2 pounds of new round red potatoes, cut in to bite size pieces and boil for 15 minutes or until just tender

She makes an edit and commits it to her local repository.

$ hg status
M recipe.md
$ hg diff
diff -r 148da6f2ab2a recipe.md
--- a/recipe.md Mon Aug 25 17:12:30 2014 -0400
+++ b/recipe.md Sun Sep 07 22:55:48 2014 -0400
@@ -1,7 +1,7 @@
 Potato Salad
 ============

-    1 1/2 pounds of new round red potatoes, cut in to bite size pieces and boiled until just tender
+    1 1/2 pounds of new round red potatoes, cut in to bite size pieces and boil for 15 minutes until just tender
         1 cup of light mayonaise
         1 tablespoon of yellow mustard
         1 tablespoon of white wine vinegar
$ hg commit -m "Fix a typo and provide a time for boiling the potatos."
recipe.md
committed changeset 5:b1c809205aa1

We have seen this all before, but it is a good refesher.

Jill has committed her change, but we don't know about yet. If we switched to our folder and ran hg log we wouldn't see changeset 5. It isn't on Bitbucket yet either.

In order to share changes with other people committers need to push their commits. This means you can use the revision control locally and only share when you are ready.

hg push will push changes up to the repository you cloned from or the one you configured when you edit hgrc to set the default path.

$ hg push
pushing to https://[username]@bitbucket.org/[username]/potato_salad
searching for changes
1 changesets found
http authorization required
realm: Bitbucket.org HTTP
user: <username>
password: 
remote: adding changesets
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 1 changes to 1 files

Once you have pushed you can view the commit on Bitbucket. It is kind of like hg log but prettier. You can find the commits here, just replace the username placeholder with your own.

https://bitbucket.org/[username]/potato_salad/commits/all

Finally you can get the change into your original repository using hg pull -u.

$ cd ~/Desktop/potato_salad
$ hg pul -u
searching for changes
all local heads known remotely
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
resolving manifests
getting recipe.md
1 files updated, 0 files merged, 0 files removed, 0 files unresolved

The option -u tells Mecurial to checkout the change you just got to your local working folder. hg pull with out the -u would pull the change to your local repository but you would need to run hg update to be able to edit them.

Let's have one more look at the log.

$ hg log
changeset:   5:b1c809205aa1
tag:         tip
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Sun Sep 07 22:56:01 2014 -0400
files:       recipe.md
description:
Fix a typo and provide a time for boiling the potatos.


changeset:   4:148da6f2ab2a
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Mon Aug 25 17:12:30 2014 -0400
files:       badfile.txt
description:
Remove the bad file
...

If our friend wasn't so imaginary, then the user lin in the log would be different, it would have Jill's name and email.

Simple Merging

As our last trick we will see that happens when you make change and your imaginary friend Jill makes a change at the same time.

Let's go back to Jill's repo and make another change.

$ cd ~/Desktop/jill/potato_salad

Jill really likes Dijon mustard and found it gave the potato salad a bit of a kick. She changes the 3rd line of the receipe to reflect this.

        1 tablespoon of Djion mustard

Mmmmm tasty. She follow the normal sequence of committing and push her change.

$ hg status
M recipe.md
$ hg diff
diff -r b1c809205aa1 recipe.md
--- a/recipe.md Sun Sep 07 22:56:01 2014 -0400
+++ b/recipe.md Fri Sep 12 10:28:02 2014 -0400
@@ -3,7 +3,7 @@

     1 1/2 pounds of new round red potatoes, cut in to bite size pieces and boil for 15 minutes until just tender
         1 cup of light mayonaise
-        1 tablespoon of yellow mustard
+        1 tablespoon of Djion mustard
         1 tablespoon of white wine vinegar
         2 teaspoons of sugar
     pinch of ground black pepper
$ hg commit -m "Make it Djion"
recipe.md
committed changeset 6:8c11a3be22a9
$ hg push
pushing to https://amjoconn@bitbucket.org/amjoconn/potato_salad
searching for changes
1 changesets found
http authorization required
realm: Bitbucket.org HTTP
user: [username]
password: 
remote: adding changesets
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 1 changes to 1 files

Meanwhile, you in your repo have made a different change. After some soul searching you decide that sweet relish is where it is at. It is just too easy to over dill.

To simulate this first make sure you move into your version of the repo.

$ cd ~/Desktop/potato_salad/
$ hg log
changeset:   5:b1c809205aa1
tag:         tip
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Sun Sep 07 22:56:01 2014 -0400
files:       recipe.md
description:
Fix a typo and provide a time for boiling the potatos.


changeset:   4:148da6f2ab2a
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Mon Aug 25 17:12:30 2014 -0400
files:       badfile.txt
description:
Remove the bad file
...

We can see in your repo the change #6 that Jill made isn't there yet. Do not pull yet, we are going test out merging when both people make a change.

Change line 8 of the recipe to sweet relish.

      1/3 cup sweet pickle relish

Now do your normal commit thing, but don't push yet.

$ hg status
M recipe.md
$ hg diff
diff -r b1c809205aa1 recipe.md
--- a/recipe.md Sun Sep 07 22:56:01 2014 -0400
+++ b/recipe.md Fri Sep 12 10:34:17 2014 -0400
@@ -8,7 +8,7 @@
         2 teaspoons of sugar
     pinch of ground black pepper
     pinch of salt
-      1/3 cup dill pickle relish
+      1/3 cup sweet pickle relish
       1/3 cup green onions, sliced
         3 hardboiled eggs, coarsely chopped

$ hg commit -m "Back to sweet relish."
recipe.md
committed changeset 6:0dcd9d7c8ee2

We have 3 repos. Jill have commit #6 which is her Djion change, and this change is also into the version of the repo on Bitbucket. In our copy of the repo we have commit #6 as well, but it is a relish change.

The commands outgoing and incoming let us see what we would be about to push or pull.

$ hg outgoing
comparing with https://amjoconn@bitbucket.org/amjoconn/potato_salad
searching for changes
changeset:   6:0dcd9d7c8ee2
tag:         tip
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Fri Sep 12 10:34:26 2014 -0400
files:       recipe.md
description:
Back to sweet relish.


$ hg incoming
comparing with https://amjoconn@bitbucket.org/amjoconn/potato_salad
searching for changes
changeset:   7:8c11a3be22a9
tag:         tip
parent:      5:b1c809205aa1
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Fri Sep 12 10:28:21 2014 -0400
files:       recipe.md
description:
Make it Djion

Well that is interesting, you local copy of hg is dynamically calling the incoming commit #7. I guess it knows what is coming. We are going to merge these changes.

Before we do that what would happen if you just pushed. Maybe you didn't know Jill had been working on the recipe?.

$ hg push
pushing to https://amjoconn@bitbucket.org/amjoconn/potato_salad
searching for changes
new remote heads on branch 'default'
new remote head 0dcd9d7c8ee2
abort: push creates new remote head 0dcd9d7c8ee2!
(you should pull and merge or use push -f to force)

The phrase "push creates new remote head" might not be the clearest. Basically it means that you have change and there are change in the repo which need to be merged before you can push.

Note Mercurial does let you do the push if you really mean it with -f, but there are very few situations where you will really want to push without merging. I have done it maybe once in 4 years.

One of the big ideas behind source control system like Mercurial is the person making the chanage should do the merge, not the person taking care the main version of the repo.

Fortunately this merge is going to be pretty easy.

  1. We will pull the change
  2. Mercurial will tell us a merge needs to happen
  3. We will checkout the heads
  4. We will instruct Mercurial to merge automatically
  5. We will commit the merge
  6. We will push our commit and the merge to the Bitbucket repo

Here is what it looks like.

$ hg pull
pulling from https://amjoconn@bitbucket.org/amjoconn/potato_salad
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)
$ hg heads
changeset:   7:8c11a3be22a9
tag:         tip
parent:      5:b1c809205aa1
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Fri Sep 12 10:28:21 2014 -0400
files:       recipe.md
description:
Make it Djion


changeset:   6:0dcd9d7c8ee2
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Fri Sep 12 10:34:26 2014 -0400
files:       recipe.md
description:
Back to sweet relish.


Air-Jackson:potato_salad amjoconn$ hg merge
resolving manifests
couldn't find merge tool hgmerge
merging recipe.md
0 files updated, 1 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg commit -m "Merge"
recipe.md
committed changeset 8:3a775d7b2d9a
$ hg push
pushing to https://amjoconn@bitbucket.org/amjoconn/potato_salad
searching for changes
2 changesets found
http authorization required
realm: Bitbucket.org HTTP
user: [username]
password: 
remote: adding changesets
remote: adding manifests
remote: adding file changes
remote: added 2 changesets with 2 changes to 1 files

There you go. We can switch back to Jill version, pull eveything down and checkout the resulting history.

$ cd ~/Desktop/jill/potato_salad/
$ hg pull
pulling from https://amjoconn@bitbucket.org/amjoconn/potato_salad
searching for changes
all local heads known remotely
adding changesets
adding manifests
adding file changes
added 2 changesets with 2 changes to 1 files
(run 'hg update' to get a working copy)
$ hg up
resolving manifests
getting recipe.md
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg log
changeset:   8:3a775d7b2d9a
tag:         tip
parent:      7:0dcd9d7c8ee2
parent:      6:8c11a3be22a9
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Fri Sep 12 10:41:39 2014 -0400
files:       recipe.md
description:
Merge


changeset:   7:0dcd9d7c8ee2
parent:      5:b1c809205aa1
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Fri Sep 12 10:34:26 2014 -0400
files:       recipe.md
description:
Back to sweet relish.


changeset:   6:8c11a3be22a9
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Fri Sep 12 10:28:21 2014 -0400
files:       recipe.md
description:
Make it Djion


changeset:   5:b1c809205aa1
user:        Albert O'Connor <amjoconn@gmail.com>
date:        Sun Sep 07 22:56:01 2014 -0400
files:       recipe.md
description:
Fix a typo and provide a time for boiling the potatos.

...

Looking at the log we have Jill commit, your commit and the merge. If you checkout the recipe.md file everything happy. We have Djion with sweet relish combined into one file.

Merge Conflicts

That wasn't so hard, and may merges are this smooth. It is possible though for the merge to not be able to be done automatically. In this case Mercurial lets you modify the files in conflict before you commit the result. You can read a tutorial on merging if you want to know more.

Wrap Up

That brings us the end of our source control journey. Let's review our workflow again.

When you’re working on a team, your workflow is going to look a lot like this:

  1. If you haven’t done so in a while, get the latest version that everyone else is working off of:
    • hg pull
    • hg up
  2. Make some changes
  3. Commit them (locally)
  4. Repeat steps 2-3 until you’ve got some nice code that you’re willing to inflict on everyone else
  5. When you’re ready to share:
    • hg pull to get everyone else’s changes (if there are any)
    • hg merge to merge them into yours (if there are any)
    • test! to make sure the merge didn’t screw anything up
    • hg commit (the merge)
    • hg push

When you are ready for more, there is a more complete tutorial available called hginit.com. The material here was inspired by the ground up and team tutorials but rest of the section cover even mroe stuff including merge conflicts.