Differences between revisions 9 and 105 (spanning 96 versions)
Revision 9 as of 2009-01-20 11:03:19
Size: 10740
Editor: IsaacJurado
Comment: Added a link to the January 2009 mercurial tags discussion
Revision 105 as of 2013-09-02 12:53:27
Size: 675
Editor: ChiU75
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
#pragma section-numbers 2
= Mercurial for Git users =

[http://git-scm.com Git] is a very popular DistributedSCM that works very
similarly to Mercurial. However, there are some design and conceptual
differences that may cause trouble when coming from Git to Mercurial.

[[TableOfContents]]


== Logical architecture ==

At the conceptual level from the user's perspective, Mercurial and Git are
basically the same. Only with nomenclature and interface differences. Due to
historic reasons, Git tends to expose more concepts to the user and that is one
of the reasons it is so hard to learn.

Mercurial has always focused more on interface aspects so it is easier to learn.
In comparison to Git, a shallower understanding is required to operate with
Mercurial in a useful manner. In the long run, such ''encapsulation'' has given
Hg the false appearance of being less powerful and featureful as it really is.

This section tries to prove that de only logical architecture difference between
the two systems, is nomenclature.


=== History model ===

One of the first Git lessons is the repository basic object types: blob, tree
and commit. These are the building blocks for the history model. Mercurial
also builds up history upon the same three concepts, respectively: file,
[:Manifest:manifest] and [:Changeset:changeset].

To identify these objects both systems use a SHA1 hash value, what Mercurial
calls [:Nodeid:nodeid]. Aditionally, Mercurial also provides a '''local'''
ascending number for each [:Changeset:changeset] instead of the reverse count
notation provided by Git (like HEAD~4).

From that, Mercurial's view of history is, just like Git's, a
[:UnderstandingMercurial:DAG] or Directed Acyclic Graph of
[:Changeset:changesets]. For instance, the graphical representation of history
is the same in the two.


=== Branch model ===

Also like in Git, Mercurial supports branching in different ways. First and
foremost, each clone of a repository represents a branch; eventually identical
to other clones of the same repositories. This way of branching sometimes
referred as ''heavy branches'' and it works almost the same in both systems.

Then Git has its famous ''lightweight branches'', which allow to switch between
development lines within the same clone of a repository. Take the following
history graph as an example:

{{{#!dot
digraph {
    label = "Light branches example";
    rankdir = LR;
    node [shape=box];
    a -> b -> c [dir=back];
    c -> d -> e [dir=back];
    c -> f -> g [dir=back];
    e -> X [dir=back, style=dotted];
    g -> Y [dir=back, style=dotted];
    X [shape=plaintext];
    Y [shape=plaintext];
}
}}}

In Git, branches `X` and `Y` are simply references to the `e` and `g` commits.
If a new commit is appended to `e` then the reference `X` would then point to
such commit, like so:

{{{#!dot
digraph {
    label = "Moving reference example";
    rankdir = LR;
    node [shape=box];
    a -> b -> c [dir=back];
    c -> d -> e -> h [dir=back];
    c -> f -> g [dir=back];
    h -> X [dir=back, style=dotted];
    g -> Y [dir=back, style=dotted];
    X [shape=plaintext];
    Y [shape=plaintext];
}
}}}

Mercurial has '''always''' supported these kind of branches, but with a
different name and somehow in an anonymous way. In Hg, the `X` and `Y`
branches are called ''heads'' and, until recently, they had to be referred by
their changeset identifier; either local (number) or global (SHA1 hash). In
brief, is like using Git detached heads instead of branch names, but much
easier (see `hg help heads`).

Since Mercurial 1.1, the BookmarksExtension provides a way to identify (and
follow) a light branch with a symbolic name, similarly to Git. The
''bookmarks'' does not perfectly mimic Git branches in the case of two bookmarks
pointing to the same head (or two branches referencing the same commit). In
Git, a commit only updates the working branch while in Mercurial, a changeset
updates all the bookmarks pointing to it.

  (!) In BookmarksExtension since Mercurial version 1.2 (to be released), this
  issue is solved and, thus, gets closer in approaching Git's lightweight
  branches.

``
  <!> Keep in mind that bookmarks do not propagate over clones, pulls nor pushes
  because they are not part of the history data nor reflected on the
  WireProtocol.

Finally, Mercurial has another branching functionality called NamedBranches,
also known as long lived branches. This kind of branch does not have a Git
equivalent. For more information about named branches:

  * [:Branch:Branch]
  * NamedBranches
  * MultipleHeads


=== Tag model ===

Like with branches. Both Git and Mercurial support two tag levels: ''local''
and ''global''. Local tags are only visible where they were created and do not
propagate, so they behave practically the same in both systems.

Global tags is one of the aspects that is really different from git. Apparently
they serve the same purpose, however they are treated differently. In Git,
global tags have a dedicated repository object type; these tags are usually
referred as ''annotated tags''. In Mercurial, though, they are stored in a
special text file called `.hgtags` residing in the root directory of a
repository clone. Because the `.hgtags` file is versioned as a normal file, all
the file modifications are stored as part of the repository history.

Two important things need to be remembered about how `.hgtags` is handled:

  1. The file only grows and should not be edited, except when it (rarely)
     generates a merge conflict.

  2. Because it is revision controlled, there is a corresponding
     [:Revlog:revlog]. When looking for tags, only the latest revision of
     `.hgtags` is parsed; never mind the checked out copy revision.

Although it is questioned by many Mercurial users, this design allows to keep
track of all global tagging operations. Nevertheless, it also confuses many Hg
newcomers because it can lead to some puzzling scenarios. For example, consider
the following history graph:

{{{#!dot
digraph {
    label = "Global tag example";
    rankdir = LR;
    node [shape=box];
    a -> b -> c [dir=back];
    c -> T [dir=back, style=dotted];
    T [shape=plaintext];
    c -> "d: add tag T" -> e -> f [dir=back];
}
}}}

In the graph, `T` is a global tag pointing to changeset `c`. This tagging
action generated changeset `d` because `.hgtags` had to be committed. Now, if
you clone a new repository using `hg clone --rev T`, the history graph of the
cloned repository would look like this:

{{{#!dot
digraph {
    label = "Clone by global tag example";
    rankdir = LR;
    node [shape=box];
    a -> b -> c [dir=back];
}
}}}

Therefore, in the new repository tag `T` does not exist. The reason behind this
is because in the original repository tag `T` points to changeset `c`; however,
tag `T` is added by commit `d` which is a descendant of `c`. As the clone
command limits the history up to changeset `c`, the addition of the tag is not
included in the new repository. Things work similarly when tagging a particular
revision using `hg tag --rev ...`

Regarding tag propagation across repositories, Mercurial has very simple
semantics. From the history and WireProtocol point of view, the `.hgtags` file
is treated like the rest of the tracked files, which means that any global
tagging operation becomes visible to everyone just like any other commit. It
also implies that merge conflicts can occur over `.hgtags`.

The rationale behind Mercurial's global tags is briefly justified in
[http://www.selenic.com/pipermail/mercurial/2009-January/023271.html this thread]
(January 2009).

See also: [http://hgbook.red-bean.com/hgbookch8.html#x12-1580008.1 Giving a persistent name to a revision].


== Behavioral differences ==

In most design decisions, Mercurial tries to avoid exposing excessive complexity
to the user. This sometimes can lead to believe both systems have nothing in
common when in practice the difference is subtle, and vice versa.


=== Communication between repositories ===

It has already been explained how similar the branching model is in both Git and
Mercurial. When it comes to move history between different repositories, the
behaviour is slightly mismatched.

Git adds the notion of ''tracking branch'', a branch that is used to follow
changes from another repository. Tracking branches allow to selectively pull or
push branches from or to a remote repository.

Mercurial keeps things simpler in this aspect: when you pull, you bring all
remote heads into your local repository. Then you can decide whether to merge
or not. Or else, pull and merge automatically using the FetchExtension. While
this scheme may seem more rigid, it actually helps maintaining cleaner public
repositories. Following the same rationale, all pushes that may create new
heads (i.e. light branches) are forbidden.

Remember also that [:BookmarksExtension:bookmarks] do '''not''' propagate over
pushes nor pulls.


=== Git's staging area ===

Git is the only [:DistributedSCM:DistributedSCM] that exposes the concept of
''index'' or ''staging area''. The others may implement and hide it, but in no
other case the user is aware nor has to deal with it.

Mercurial's rough equivalent is the DirState, which controls working copy status
information to determine the files to be included in the next commit. But in
any case, this file is handled automatically. Additionally, it is possible to
be more selective at commit time either by specifying the files you want to
commit on the command line or by using the RecordExtension.

If you felt uncomfortable dealing with the index, you are switching for the
better ;-)


== Command equivalence table ==

The table presented below is far from being complete due to the large amount of
command and switch combinations that Git offers. Nevertheless, it tries to
cover the most shocking changes when moving from Git to Hg:

||<:>'''Git command'''||<:>'''Hg command'''||<:>'''Notes'''||
||`git pull`||`hg fetch`||Requires the FetchExtension to be enabled.||
||`git fetch`||`hg pull`|| ||
||`git reset --hard`||`hg revert -a --no-backup`|| ||
||`git revert <commit>`||`hg backout <cset>`|| ||
||`git add <new_file>`||`hg add <new_file>`||Only equivalent when `<new_file>` is not tracked.||
||`git add <file>`||&mdash;||Not necessary in Mercurial.||
||`git add -i`||`hg record`||Requires the RecordExtension to be enabled.||
||`git reset --hard`||`hg revert -a --no-backup`|| ||
People call me Jordon and I was born in North Carolina in the United States - I am a student majoring in Veterinary Medicine and I also run a magnificent site about [[http://blueeye99.com/wiki/index.php/%EC%82%AC%EC%9A%A9%EC%9E%90:DemetriaQ72|Link Building]].The simple reality that lots of people devote rather a great deal of their time every day to link building shows that it is one crucial job. For one, it produces connections in between pages and other websites that send site visitors our means. The most critical reason for constructing links is to help a website attain greater ranks in popular search engines and as an outcome send out lots of traffic its means.

People call me Jordon and I was born in North Carolina in the United States - I am a student majoring in Veterinary Medicine and I also run a magnificent site about Link Building.The simple reality that lots of people devote rather a great deal of their time every day to link building shows that it is one crucial job. For one, it produces connections in between pages and other websites that send site visitors our means. The most critical reason for constructing links is to help a website attain greater ranks in popular search engines and as an outcome send out lots of traffic its means.

GitConcepts (last edited 2020-12-05 18:06:40 by KevinLocke)