Diff for /wikisrc/users/dholland/hgnb.mdwn between versions 1.12 and 1.14

version 1.12, 2014/12/14 09:52:59 version 1.14, 2016/02/15 23:02:07
Line 1 Line 1
 ## Mercurial usage for NetBSD  ## Mercurial usage for NetBSD
 (hypothetically assuming the repositories have been converted)  (hypothetically assuming the repositories have been converted)
 Here are some directions for how one would use Mercurial after a  This page has been [[moved|http://www.netbsd.org/~dholland/notes/hg-migration/usage.html]].
 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  
 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 \  
     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...  

Removed from v.1.12  
changed lines
  Added in v.1.14

CVSweb for NetBSD wikisrc <wikimaster@NetBSD.org> software: FreeBSD-CVSweb