--- wikisrc/users/dholland/hgnb.mdwn 2014/12/14 09:52:59 1.12 +++ wikisrc/users/dholland/hgnb.mdwn 2016/02/15 23:02:07 1.14 @@ -1,426 +1,4 @@ ## Mercurial usage for NetBSD (hypothetically assuming the repositories have been converted) -Here are some directions for how one would use Mercurial after a -NetBSD transition from CVS to Mercurial. -Most of this is pretty trivial (especially for anyone who's used -Mercurial before...) - -There is a lot of FUD circulating about using a distributed version -control system, what with talk of "workflows" and "topic branches" and -other unfamiliar terms. -Most of this arises from git user communities and git advocates; -because git is screwy, using git is more complicated than using other -better designed tools. -Also, those suffering from Stockholm syndrome with respect to git tend -to believe that the complexities of git are inherent to distributed -version control, which is not the case; and many other people have been -alarmed (or scared, or confused) by things such people have told them. - -### Basic usage - -First, NetBSD will go on using a central master repository. There is -nothing to be gained by changing this; we have the project -infrastructure to support it, and ultimately there has to be some tree -somewhere that constitutes the master copy regardless. - -Therefore, the basic usage is almost entirely unchanged: - - CVS Mercurial - - cvs checkout hg clone - cvs update -dP hg pull && hg update - cvs -n update hg status - cvs log file hg log file [or just hg log] - - cvs update -p file hg cat file - cvs annotate hg annotate - cvs diff -u hg diff - cvs add hg add - cvs rm hg rm - [no can do] hg cp - [no can do] hg mv - cvs commit hg commit && hg push - cvs tag hg tag - -You will notice that CVS's update and commit have been divided into -two now-separable actions: in Mercurial, pull fetches changes from a -remote repository but doesn't affect your working tree, and update -updates your working tree to (by default) the latest new changes. -Similarly, commit integrates changes from your working tree, but -locally only; push publishes those changes to the remote repository. - -This means that you can commit many times before pushing; this is -often desirable if you're working on something nontrivial and you want -to wait until it's ready before shipping it out. - -There is one catch, which is that other people can commit (and push to -the master repository) while you're working. You can mostly avoid -this, if you haven't committed anything locally yet, by doing "hg pull -&& hg update" before committing, which will merge into your -uncommitted changes and works exactly like updating before committing -in CVS. However, if you've committed a number of changes, or someone -got a new change in right between when you last pulled and when you -committed, you need to do an explicit merge instead, and then you can -push. - -In the simple case, you do an explicit merge as follows: - - hg pull - hg merge - hg commit - -When you get a merge conflict, you first need to resolve it (in the -usual way by editing) and then you must tag it resolved in hg before -hg will let you commit, like this: - - hg resolve -m file - -You can list unresolved conflicts thus: - - hg resolve -l - -Note that even with the explicit merge this is almost exactly -equivalent to the CVS behavior when someone commits ahead of you. -The chief difference is that because Mercurial does whole-tree -commits, *any* change ahead of you needs to be merged, not just one -that touches the same files you've edited. - -There is one gotcha, which is that you can't do explicit merges in a -tree with uncommitted changes. The best way around this is to stash -your changes: - - hg stash - hg merge - ...whatever merge stuff... - hg unstash - -You can also do the merge in another tree; because Mercurial is a -distributed tool, you can create a temporary copy of your tree, or -push the changes you need to another tree you already have, do the -work there, and push the results back. Let's suppose you have two -trees, "src" and "scratch", where you never keep uncommitted changes -in "scratch" so it can be used for this kind of thing. Then you can do -the following (starting at the top of src): - - hg push ../scratch - cd ../scratch - hg update - hg merge - ...whatever merge stuff, including commit... - cd ../src - hg pull ../scratch - hg update - -### Disconnected operation - -Mercurial is a distributed system, and works by cloning the entire -history into each tree you create. -This has its downsides; but it means that you get disconnected -operation for free. -The only operations that need to contact the master repository are -push, pull, incoming, and outgoing. - -### Some other bits - -A commit with no descendents (that is, the most recent commit on any -line of development) is called a "head". -You can list these as follows: - - hg heads - -This will include commits that have descendents only on other -branches, e.g. the last commit on a development branch that's been -merged but not closed. Use "-t" ("topological heads") to hide these. - -You can see what "hg pull" and "hg push" are going to do via "hg -incoming" and "hg outgoing" respectively. -(FWIW, git can't do this.) - -If you interrupt Mercurial (or Mercurial gets interrupted, e.g. by a -system crash) you want to do this afterwards: - - hg recover - -and if you have reason to think the repository might be corrupt you -can check it like this: - - hg verify - -### Development branches - -A development branch is one where you're working on some new feature -and you expect to merge the branch into the trunk later. -Unlike in CVS, this is very cheap in Mercurial. -The following are the operations you need, using "libc13" as an -example branch name. - -Note that even if you're working on something nontrivial that will -take a number of commits, if you aren't intending to push the changes -out before they're done you don't need to make a branch and there's -nothing gained by doing so. -However, if you expect to be working over a long period of time on a -major effort (such as the mythical libc version bump), and/or you -want or expect other developers to contribute or at least test your -changes before they're done, go ahead and create a branch. - -Create a new branch: - - cvs update -dP hg pull && hg update (if needed) - update doc/BRANCHES update doc/BRANCHES (if appropriate) - cvs commit doc/BRANCHES hg commit doc/BRANCHES (if needed) - cvs tag libc13-base hg tag libc13-base - cvs ph'tagn hg branch libc13 - [make first change] [make first change] - cvs commit hg commit - hg push - -Mercurial warns you that branches are permanent and expensive; this -warning is aimed at git users who ought to be creating bookmarks -instead and not something you need to be concerned about. - -Check out a new tree on a branch: - - cvs co -P -rlibc13 hg clone [url] - cd src - hg update -r libc13 - -Switch to a new tree on a branch: - - cvs up -dP -A -rlibc13 hg pull (if needed) - hg update -r libc13 - -Note that if you have uncommitted changes, Mercurial will balk at -crossing from one branch to another because it doesn't know how to -merge them. -In that case do this: - - hg update -r libc13-base - [resolve conflicts if needed] - hg update -r libc13 - [resolve conflicts if needed] - -Check which branch you're currently on: - - cat CVS/Tag hg branch - -See list of branches: - - [no can do reliably] hg branches - -Note that unlike with CVS there's no version-control-related reason to -get a new tree just to work on a branch. -(Although of course it's still possible to commit to the wrong branch -by accident.) -Get a new tree if and only if you want to have a different tree for -administrative reasons. - -Sync your branch with the trunk ("HEAD" in CVS): - - cvs ph'tagn hg merge default - [resolve conflicts] [resolve conflicts] - cvs commit hg commit - hg push - -When you're done with your branch, in Mercurial you can "close" it so -it's no longer active. -This causes it to disappear from some reports, reduces some internal -management overheads, and prevents accidental commits on it. - - [no can do] hg commit --close-branch - -Don't forget to update doc/BRANCHES too. - -### Vendor branches - -A vendor branch is one where code from a third party is committed in -unmodified state, so it can be updated easily from upstream later. - -Note that in CVS vendor branches are magic (in a bad way); in -Mercurial we'll just use an ordinary branch. We'll start it from the -empty revision so it doesn't contain any unwanted rubbish. - -To start a new vendor branch for the upstream package "frobozz", -assuming you've already written frobozz2netbsd if one's needed: - - mkdir tmp - cd tmp - hg update -r0000 - mkdir external && cd external - mkdir bsd && cd bsd - mkdir frobozz && cd frobozz - tar -xvzf frobozz-1.0.tgz tar -xvzf frobozz-1.0.tgz - mv frobozz-1.0 dist mv frobozz-1.0 dist - cp .../frobozz2netbsd . cp .../frobozz2netbsd . - ./frobozz2netbsd ./frobozz2netbsd (if needed) - cvs import src/distrib/bsd/frobozz \ - FROBOZZ frobozz-1-0 - hg add - hg branch FROBOZZ - hg commit - hg tag frobozz-1-0 - cd ../src - cvs update -dP - hg update -r default - hg merge FROBOZZ - hg commit - [hack as needed] [hack as needed] - cvs commit hg commit - hg push - cd .. - rm -r tmp - -Note that in both cases this imports frobozz2netbsd on the branch; -this seems the most convenient but I'm not sure if it's been our -standard procedure. - -To update "frobozz" to 1.1: - - mkdir tmp - cd tmp - hg update -rFROBOZZ - cd external/bsd/frobozz - tar -xvzf frobozz-1.1.tgz tar -xvzf frobozz-1.1.tgz - rm -r dist - mv frobozz-1.1 dist mv frobozz-1.1 dist - ./frobozz2netbsd ./frobozz2netbsd - cvs import src/distrib/bsd/frobozz \ - FROBOZZ frobozz-1-0 - hg addremove - hg commit - hg tag frobozz-1-1 - cd .. - mkdir tmp2 && cd tmp2 - cvs ph'tagn - hg update -r default - hg merge FROBOZZ - [resolve conflicts] [resolve conflicts] - cvs commit hg commit - cd ../src - cvs update -dP - [hack as needed] [hack as needed] - cvs commit hg commit - hg push - cd .. - rm -r tmp tmp2 - -### Release branches - -A release branch is one that diverges from the main branch and is not -expected to be merged back into it. -However, changes from the main branch are (individually) merged into -it after review. - -Creating a release branch in Mercurial is the same as creating a -feature branch; see above. -So is checking it out. -Committing a change to a release branch is no different from -committing to the default branch or any other branch. - -TODO: we should probably use the Mercurial cherrypick extension for at -least some release branch pullups; I don't know how to do that offhand -without looking it up. - -Tagging a release: - - cvs rtag -r netbsd-7 \ hg tag -r netbsd-7 \ - netbsd-7-0-RELEASE netbsd-7-0-RELEASE - -Viewing the changes on a branch: - - cvs log > file hg log -b netbsd-7 - [page through and curse] - -Extracting tarballs: - - mkdir tmp - cd tmp - cvs export -r netbsd-7-0-RELEASE \ hg archive -r netbsd-7-0-RELEASE \ - src ../netbsd-7.0.tar.gz - mv src netbsd-7.0 - tar -cvzf ../netbsd-7.0.tar.gz \ - netbsd-7.0 - cd .. - rm -r tmp - - -### Reverting a bad commit - -Sometimes somebody commits something that needs to be unwound later. -In CVS you have to track down each per-file change and undo each one -separately, then commit them all. -In Mercurial, because Mercurial has whole-tree commits, you can do it -with a single command. - - cvs update -j1.6 -j1.5 foo.c - cvs update -j1.9 -j1.8 bar.c - cvs update -j1.15 -j1.14 baz.c - hg backout -r 101abcde - [resolve conflicts] [resolve conflicts] - cvs commit hg commit - hg push - -Note that apparently if you use hg backout to back out the most recent -commit, it auto-commits. -(This seems to me like a UI bug.) - -### Carrying local changes - -In CVS you can keep uncommitted changes in your tree indefinitely with -no ill effects. -(Or at least, no ill effects until you want to commit other changes to -the same files, run into merge conflicts, or hit PR 42961.) - -In Mercurial having uncommitted changes keeps you from doing explicit -merges, which you need to do much more often than in CVS. -There are several ways around this: - -* You can stash your uncommitted changes any time you need to merge. -This works fine but it quickly becomes a nuisance. -* You can use different trees for hacking and for building the system -for install, since presumably you only need the local changes in -the latter case. -This works fine until you need to shift partially-completed hacking to -the installable tree, and then becomes painful. -* You can commit your local changes as "secret" using the evolve -extension (I recommend reading the docs for the evolve extension); -then they're committed and can be merged and so on, but won't get -pushed back to the master repository. -The downside of this is that you can't readily distribute your local -changes among your own repositories. -* You can use the mq patch queue extension and store your local -changes as patches against the tree; then they can be popped off -easily for other work. -The downside of this is that merging stuff into your local changes -becomes awkward. -* You can finish your local changes so they can be committed upstream :-) - -None of these solutions is perfect, but one or the other of these -approaches is probably good enough in most cases. - -### Reverting stuff locally - -In CVS you can use "cvs update" to pin a subtree down to a specific -point in history, where it will stay while you update the rest of the -tree around it. -(Accidental engagement of this feature is probably as common as -intentional use...) - -There is no direct equivalent in Mercurial. -However, you can easily alter a file or subtree to roll it back to a -specific point in history, and then carry the resulting diff as a -local modification until whatever issue prompted you to do this gets -sorted out. - -To revert to a specific version: - - hg revert -r rev subtree -To revert to a specific date: - - hg revert -d date subtree - - -### Other stuff - -Have I forgotten anything? -Email me questions... +This page has been [[moved|http://www.netbsd.org/~dholland/notes/hg-migration/usage.html]].