10095
Comment: +enables throw away experimentation
|
392
|
Deletions are marked like this. | Additions are marked like this. |
Line 1: | Line 1: |
Mercurial's decentralized development model can be confusing to new users. This page attempts to illustrate some of the basic concepts. See the ["Tutorial"] for step-by-step instructions. ''(Translations: [:BrazilianPortugueseUnderstandingMercurial:Brazilian Portuguese], [:ChineseUnderstandingMercurial:Chinese], [:FrenchUnderstandingMercurial:French], [:GermanUnderstandingMercurial:German], [:ItalianUnderstandingMercurial:Italian], [:JapaneseUnderstandingMercurial:Japanese], [:KoreanUnderstandingMercurial:Korean], [:RussianUnderstandingMercurial:Russian], [:SpanishUnderstandingMercurial:Spanish] )'' [[TableOfContents]] == What's in a Repository == Mercurial [:Repository:repositories] contain a [:WorkingDirectory:working directory] coupled with a store: {{{#!dot digraph G { rankdir = LR; compound=true; background="#999999"; subgraph cluster_0 { label="working directory"; style=filled; color=lightgrey; node [style=filled,color=white]; edge [style=invis]; "main.c" -> "main.h" -> ".hgignore" -> ".hgtags"; } subgraph cluster_1 { label = "store"; labelloc = b; style=filled; color="#eeeeee"; node [shape=box, style=filled, color=lightgray]; "rev 0" -> "rev 1" -> "rev 2" -> "rev 3" [dir=back, label="parent"]; } "main.c" -> "rev 2" [ltail=cluster_0, label="parent", labeldistance=5, minlen=2]; } }}} The store contains the '''complete''' history of the project. Unlike traditional [:SCM:SCMs], where there's only one central copy of this history, every working directory is paired with a private copy of the history. This allows development to go on in parallel. The working directory contains a copy of the project's files at a given point in time (eg rev 2), ready for editing. Because [:Tag:tags] and [:.hgignore:ignored files] are revision-controlled, they are also included. == Committing Changes == When you [:Commit:commit], the state of the working directory relative to its [:Parent:parents] is recorded as a new [:ChangeSet:changeset] (also called a new "[:Revision:revision]"): {{{#!dot digraph G { compound=true; rankdir = LR background="#999999"; subgraph cluster_0 { label="working directory"; style=filled; color=lightgrey; node [style=filled,color=white]; edge [style=invis]; "main.c"-> "main.h" -> ".hgignore" -> ".hgtags" } subgraph cluster_1 { label = "store"; labelloc = b; style=filled; color="#eeeeee"; node [shape=box,style=filled,color=lightgray]; "rev 0" -> "rev 1" -> "rev 2" -> "rev 3" [dir=back]; "rev 2" -> "rev 4" [dir=back]; } "rev 2" -> ".hgtags" [dir=back, style=dotted, lhead=cluster_0, label="parent before commit"] "rev 4" -> ".hgtags" [dir=back, color=red, lhead=cluster_0, headlabel="commit", labelfontcolor=red ] } }}} Note here that revision 4 is a '''[:Branch:branch]''' of revision 2, which was the revision in the working directory. Now revision 4 is the working directory's '''parent'''. == Revisions, Changesets, Heads, and Tip == Mercurial groups related changes to multiple files into single atomic [:ChangeSet:changesets], which are revisions of the whole project. These each get a sequential [:RevisionNumber:revision number]. Because Mercurial allows distributed parallel development, these revision numbers may disagree between users. So Mercurial also assigns each revision a global [:ChangeSetID:changeset ID]. Changeset IDs are 40-digit hexadecimal numbers, but they can be abbreviated to any unambiguous prefix, like "e38487". {{{#!dot digraph { rankdir = LR node [shape=record] rev0 [label="{{<p1> p1 | <p2> p2} | rev 0:838e}"]; rev1 [label="{{<p1> p1 | <p2> p2} | rev 1:34ef}"]; rev2 [label="{{<p1> p1 | <p2> p2} | rev 2:4563}"]; rev3 [label="{{<p1> p1 | <p2> p2} | rev 3:fe56}"]; rev4 [label="{{<p1> p1 | <p2> p2} | rev 4:ac98}"]; rev5 [label="{{<p1> p1 | <p2> p2} | rev 5:0345}"]; rev6 [label="{{<p1> p1 | <p2> p2} | rev 6:19e3 (tip)}"]; workingdir [label="{{<p1> p1 | <p2> p2} | working directory}"]; rev0 -> rev1:p1 [dir=back] rev1 -> rev2:p1 [dir=back] rev1 -> rev3:p1 [dir=back] rev2 -> rev4:p1 [dir=back] rev3 -> rev4:p2 [dir=back] rev4 -> rev5:p1 [dir=back] rev4 -> rev6:p1 [dir=back] rev6 -> workingdir:p1 [dir=back] label="example repository" } }}} Branches and [:Merge:merges] in the revision history can occur at any point. Each unmerged branch creates a new [:Head:head] of the revision history. Here, revisions 5 and 6 are heads. Mercurial considers revision 6 to be the [:Tip:tip] of the repository, the head with the highest revision number. Revision 4 is a [:MergeChangeset:merge changeset], as it has ''two'' parent changesets (revisions 2 and 3). == Cloning, Making Changes, Merging, Pulling and Updating == Let's start with a user Alice, who has a repository that looks like: {{{#!dot digraph { label="Alice's repo" rankdir = LR node [shape=box] a -> b -> c -> d -> "working dir" [dir=back] } }}} Bob [:Clone:clones] this repo, and ends up with a complete, independent, local copy of Alice's store and a clean checkout of the tipmost revision d in his working directory: {{{#!dot digraph { label="Bob's repo" rankdir = LR node [shape=box] a -> b -> c -> d -> "working dir" [dir=back] } }}} Bob can now work independently of Alice. He then [:Commit:commits] two changes e and f: {{{#!dot digraph { label="Bob's repo" rankdir = LR node [shape=box] a -> b -> c -> d -> e -> f -> "working dir" [dir=back] e [color=blue] f [color=blue] } }}} Alice then makes her own change g in parallel, which causes her repository store to diverge from Bob's, thus creating a [:Branch:branch]: {{{#!dot digraph { label="Alice's repo" rankdir = LR node [shape=box] a -> b -> c -> d -> g -> "working dir" [dir=back] g [color=red] } }}} Bob then [:Pull:pulls] Alice's repo to synchronize. This copies all of Alice's changes into Bob's repository store (here, it's just a single change g). Note that Bob's working directory is '''not''' changed by the pull: {{{#!dot digraph { label="Bob's repo" rankdir = LR node [shape=box] a -> b -> c -> d -> e -> f -> "working dir" [dir=back] e [color=blue] f [color=blue] d -> g [dir=back] g [color=red, label="g (tip)"] } }}} Because Alice's '''g''' is the newest head in Bob's repository, it's now the '''tip'''. Bob then does a [:Merge:merge], which combines the last change he was working on (f) with the tip in his working directory. Now, his working directory has two parent revisions (f and g): {{{#!dot digraph { label="Bob's repo" rankdir = LR node [shape=box] a -> b -> c -> d -> e -> f [dir=back] e [color=blue] f [color=blue] d -> g [dir=back] g [color=red] f -> "working dir" [dir=back, weight=3.0] g -> "working dir" [dir=back, weight=3.0] } }}} After examining the result of the merge in his working directory and making sure the merge is perfect, Bob commits the result and ends up with a new [:MergeChangeset:merge changeset] h in his store: {{{#!dot digraph { label="Bob's repo" rankdir = LR node [shape=box] a -> b -> c -> d -> e -> f [dir=back] e [color=blue] f [color=blue] d -> g [dir=back] g [color=red] f -> h [dir=back, weight=3.0] g -> h [dir=back, weight=3.0] h -> "working dir" [dir=back] h [color=green, label="h (tip)"] } }}} Now if Alice '''pulls''' from Bob, she will get Bob's changes e, f, and h into her store: {{{#!dot digraph { label="Alice's repo" rankdir = LR node [shape=box] a -> b -> c -> d -> e -> f [dir=back] e [color=blue] f [color=blue] d -> g [dir=back] g [color=red] f -> h [dir=back, weight=3.0] g -> h [dir=back, weight=3.0] g -> "working dir" [dir=back] h [color=green;label="h (tip)"] } }}} Note that Alice's working directory was not changed by the pull. She has to do an [:Update:update] to synchronize her working directory to the merge changset h. This changes the parent changeset of her working directory to changeset h and updates the files in her working directory to revision h. {{{#!dot digraph { label="Alice's repo" rankdir = LR node [shape=box] a -> b -> c -> d -> e -> f [dir=back] e [color=blue] f [color=blue] d -> g [dir=back] g [color=red] f -> h [dir=back, weight=3.0] g -> h [dir=back, weight=3.0] h -> "working dir" [dir=back] h [color=green, label="h (tip)"] } }}} Now Alice and Bob are fully synchronized again. == A Decentralized System == Mercurial is a completely decentralized system, and thus has no internal notion of a central repository. Thus users are free to define their own topologies for sharing changes (see CommunicatingChanges): {{{#!dot digraph { Alice -> Central Central -> Alice Bob -> Central Alice -> Bob Alice -> Carl Carl -> Central Bob -> Carl Carl -> Bob "Carl's Laptop" -> Carl Carl -> "Carl's Laptop" "Carl's Laptop" -> Central Central [style=fill;color=blue;label="Main Public Repo"] label="A Mercurial Network" } }}} Unlike a centralized version control system in which experimentation can be disastrous, with a DVCS like Mercurial, you just clone and experiment. If you like the results, push them back, otherwise wipe the cloned repository and try something else. == What Mercurial can't do == Many SVN/CVS users expect to host related projects together in one repository. This is really not what hg was made for, so you should try a different way of working. This especially means, that you cannot check out only one directory of a repository. If you absolutely need to host multiple projects in a kind of meta-repository though, you could try the ForestExtension. For a hands-on introduction to using Mercurial, see the ["Tutorial"]. |
Obstetrician Damian is hooked on Costa Blanca Holiday ([[http://community.urbansocietyd2r.com/groups/have-better-travel-experiences-with-such-great-tips/|http://community.urbansocietyd2r.com/groups/have-better-travel-experiences-with-Such-great-tips/]]), electronic devices and astronomy. On top of that he favors enjoying an Carolina hurricanes ice-hockey-match positioned in the stadium. |
Obstetrician Damian is hooked on Costa Blanca Holiday (http://community.urbansocietyd2r.com/groups/have-better-travel-experiences-with-Such-great-tips/), electronic devices and astronomy. On top of that he favors enjoying an Carolina hurricanes ice-hockey-match positioned in the stadium.