Simple guide to few common Mercurial DVCS use-cases
===================================================
Written by Matti 'ccr' Hamalainen <ccr@tnsp.org>, 2009


Tricks of the trade
===================

 - Use 'fetch' extension instead of 'pull' and 'update'. It takes care
   of automatic merges .. well, automatically. If a merge fails, see
   the merging section of this guide.

 - Always remember to 'fetch' before 'push'. Mercurial will complain
   about creating new heads in the remote repository if you haven't
   merged the remote changes to your own before the push.

 - Learn to utilize local clones of repositories for temporary
   testing, etc. Cloning a local repository is fast (under Linux
   the files are initially hardlinked.)

   For example, if you wish to quickly test something, but have
   just been editing files in your working repository, just clone it
   to another, 'hg clone orig tmp'. Tmp will be a copy of the
   repository state, so any non-committed changes from 'orig' will
   not be there.

 - Did some silly edits in your repo, that you don't want to commit?
   'hg revert file.c' will get rid of the changes in 'file.c' or
   just nuke all the non-committed changes via 'hg revert -a'.

   Oh, those reverts will actually be backed up to files ending to
   '.orig' (e.g. 'file.c.orig'), so you can usually recover from
   accidental reverts too.

 - Strive to write good commit messages. ;)


Rollback and what it does
=========================
'hg rollback' is a handy command that can be used to roll back exactly
_one_ action performed in the local repository clone. Basically it is
like rewinding the commit clock back by one commit, erasing that one
commit/action from history completely. This is why it should NOT be
used on repositories other people might have access to. (Your local
clone is usually ok, of course.)

Rollback function is sometimes useful, if you make some mistake that
you immediately realize after committing, like a typo in commit message
for example. In such situation, you can run:

$ hg rollback

In your local clone, and then do the commit again, no harm done. Another
example of rollback's usefulness would be in abortion of 'backout',
explained to more detail in next section.

Do notice that rollbacks cannot (and should not) be done after pushes
etc. If your changeset has propagated, you will need to use 'hg backout'
which will reverse the changes of the changeset, but preserves history.


Backing out a changeset
=======================
0) Ensure we are up to date:

   $ hg fetch

1) Back out or "revert" (as in Subversion and GIT terms) a changeset

   $ hg backout --merge [-r] <changeset_id or revision>

2a) Actually push it to the upstream repository. You will need to commit
    the backout merge - the backout itself is committed automatically
    but the merge isn't. Why, you ask? Because the merge might not go
    without conflicts, and is thus left for the user to finish.

    However, if there were no conflicts, you can commit:

    $ hg ci

    And then push to upstream:

    $ hg push

    If there are complaints about multiple heads, you need to 'pull'
    or preferably 'fetch', as there have been changes in the upstream
    which you need to merge to your repository clone.

    After fetching, push again.

    If there were merging conflicts during fetch, see the merge section
    of this guide.


2b) Oops, I didn't actually want to do that backout at all! In this
    situation, you can do a local rollback if you haven't done anything
    else like pushed the backout to other repositories etc.

    If you DID 'push', see 2c) below.

    $ hg rollback

    After rollbacking, you will need to update your working copy.

    $ hg update -C

    After this, your repository and work copies of files should be
    just like before you issued the backout command.


2c) So you backed out and propagated the changes to other people, but
    came to regret this. The solution is to backout the backed out
    changeset.

    $ hg backout --merge <backout changeset id>
    $ hg fetch && hg push

    As usual, normal rules for merge conflicts apply.


Merging and conflicts
=====================
Sometimes, when changesets contain changes to files that touch each other
or are close enough in proximity, Mercurial will not be able to
automatically merge these changes. This is called a merge conflict, and
it works similarly in most version control systems like CVS, Subversion,
GIT, etc.

0) When a conflict occurs, Mercurial will inform you about it with a message
   resembling something like (when using 'fetch' extension; if you are
   using plain 'hg pull', you will need to do 'hg merge' too):

   |There are unresolved merges, you can redo the full merge using:
   |  hg update -C 5589
   |  hg merge 5587

   One important thing this message actually tells us (beside the fact that
   automatic merging failed), is that you can return to _current_ state by
   issuing 'hg update -C 5589'.

   This may be helpful, if you fumble while editing the files you are trying
   to merge manually. Additionally, you don't actually need to usually
   specify the revision in this situation, so plain 'hg update -C' is enough.

1) First thing to do when doing manual merge, is to run 'hg diff', which will
   show us what was not automatically merged. Like with Subversion etc.
   the failed sections show up in the diff/files marked with specific
   separators, for example:

----------------------------------------------------------------------------
diff -r c55af7b7242c src/libaudgui/ui_fileopener.c
--- a/src/libaudgui/ui_fileopener.c     Wed Sep 09 22:06:03 2009 +0100
+++ b/src/libaudgui/ui_fileopener.c     Thu Sep 10 00:17:20 2009 +0300
@@ -116,6 +116,14 @@
         gtk_widget_destroy(browser);
         return TRUE;
     }
+<<<<<<< /home/ccr/audacious/tmp/src/libaudgui/ui_fileopener.c
+=======
+    else if (event->keyval == GDK_Returnz)
+    {
+        action_button_cb (browser, data);
+        return TRUE;
+    }
+>>>>>>> /tmp/ui_fileopener.c~other._xsy4I
 
     return FALSE;
 }
----------------------------------------------------------------------------

   Just like with other 3-way merging tools, the first section (<<<< til ====)
   is the "incoming" change, e.g. what the other committer(s) have done and
   the latter section is yours.

2) After you have edited the conflicting sections to what you think is good
   and proper (it's good to do 'hg diff' again and glance through to make
   sure you didn't miss anything), you can then commit the merge:

   $ hg ci

   And then push the changes to upstream repository.

   $ hg push

   Of course, if you took lots of time to perform the merge, someone may
   have pushed before you, and you may need to 'fetch' again before pushing.
   Maybe not so amusing, but it is just the way DVCS's work.


Update and revert
=================
These two Mercurial commands may sometimes seem bit confusing, after all
you can use 'hg update' to change the repository to any given
revision/changeset. This happens by reparenting, so for example after
'updating' to old revision, the history after that revision is to be
considered "future" from our viewpoint.

Indeed, revert does a bit similar thing, it goes back to the _parent_ of
the current working repository, effectively reverting the changes non-
committed changes in your working directories/repo.

In Subversion terms, 'hg update' can be thought as 'svn co' and actually
Mercurial considers checkout/co as aliases to 'update'. Revert then
is canonical to Subversion's revert.

But unlike in Subversion, in Mercurial you can actually go back to a given
revision (via 'hg update [-C] <rev>'), make changes, commit them and then
_merge_ those changes from the viewpoint of the old revision vs. later ones.

Yes, it's a kind of magic.
