File:  [NetBSD Developer Wiki] / wikisrc / users / dholland / hgnb.mdwn
Revision 1.12: download - view: text, annotated - select for diffs
Sun Dec 14 09:52:59 2014 UTC (6 years, 9 months ago) by dholland
Branches: MAIN
CVS tags: HEAD
failfail

    1: ## Mercurial usage for NetBSD
    2: (hypothetically assuming the repositories have been converted)
    3: 
    4: Here are some directions for how one would use Mercurial after a
    5: NetBSD transition from CVS to Mercurial.
    6: Most of this is pretty trivial (especially for anyone who's used
    7: Mercurial before...)
    8: 
    9: There is a lot of FUD circulating about using a distributed version
   10: control system, what with talk of "workflows" and "topic branches" and
   11: other unfamiliar terms.
   12: Most of this arises from git user communities and git advocates;
   13: because git is screwy, using git is more complicated than using other
   14: better designed tools.
   15: Also, those suffering from Stockholm syndrome with respect to git tend
   16: to believe that the complexities of git are inherent to distributed
   17: version control, which is not the case; and many other people have been
   18: alarmed (or scared, or confused) by things such people have told them.
   19: 
   20: ### Basic usage
   21: 
   22: First, NetBSD will go on using a central master repository. There is
   23: nothing to be gained by changing this; we have the project
   24: infrastructure to support it, and ultimately there has to be some tree
   25: somewhere that constitutes the master copy regardless.
   26: 
   27: Therefore, the basic usage is almost entirely unchanged:
   28: 
   29:     CVS                                 Mercurial
   30: 
   31:     cvs checkout                        hg clone
   32:     cvs update -dP                      hg pull && hg update
   33:     cvs -n update                       hg status
   34:     cvs log file                        hg log file  [or just hg log]
   35: 
   36:     cvs update -p file                  hg cat file
   37:     cvs annotate                        hg annotate
   38:     cvs diff -u                         hg diff
   39:     cvs add                             hg add
   40:     cvs rm                              hg rm
   41:     [no can do]                         hg cp
   42:     [no can do]                         hg mv
   43:     cvs commit                          hg commit && hg push
   44:     cvs tag                             hg tag
   45: 
   46: You will notice that CVS's update and commit have been divided into
   47: two now-separable actions: in Mercurial, pull fetches changes from a
   48: remote repository but doesn't affect your working tree, and update
   49: updates your working tree to (by default) the latest new changes.
   50: Similarly, commit integrates changes from your working tree, but
   51: locally only; push publishes those changes to the remote repository.
   52: 
   53: This means that you can commit many times before pushing; this is
   54: often desirable if you're working on something nontrivial and you want
   55: to wait until it's ready before shipping it out.
   56: 
   57: There is one catch, which is that other people can commit (and push to
   58: the master repository) while you're working. You can mostly avoid
   59: this, if you haven't committed anything locally yet, by doing "hg pull
   60: && hg update" before committing, which will merge into your
   61: uncommitted changes and works exactly like updating before committing
   62: in CVS. However, if you've committed a number of changes, or someone
   63: got a new change in right between when you last pulled and when you
   64: committed, you need to do an explicit merge instead, and then you can
   65: push.
   66: 
   67: In the simple case, you do an explicit merge as follows:
   68: 
   69:                                         hg pull
   70:                                         hg merge
   71:                                         hg commit
   72: 
   73: When you get a merge conflict, you first need to resolve it (in the
   74: usual way by editing) and then you must tag it resolved in hg before
   75: hg will let you commit, like this:
   76: 
   77:                                         hg resolve -m file
   78: 
   79: You can list unresolved conflicts thus:
   80: 
   81:                                         hg resolve -l
   82: 
   83: Note that even with the explicit merge this is almost exactly
   84: equivalent to the CVS behavior when someone commits ahead of you.
   85: The chief difference is that because Mercurial does whole-tree
   86: commits, *any* change ahead of you needs to be merged, not just one
   87: that touches the same files you've edited.
   88: 
   89: There is one gotcha, which is that you can't do explicit merges in a
   90: tree with uncommitted changes. The best way around this is to stash
   91: your changes:
   92: 
   93:                                         hg stash
   94:                                         hg merge
   95:                                         ...whatever merge stuff...
   96:                                         hg unstash
   97: 
   98: You can also do the merge in another tree; because Mercurial is a
   99: distributed tool, you can create a temporary copy of your tree, or
  100: push the changes you need to another tree you already have, do the
  101: work there, and push the results back. Let's suppose you have two
  102: trees, "src" and "scratch", where you never keep uncommitted changes
  103: in "scratch" so it can be used for this kind of thing. Then you can do
  104: the following (starting at the top of src):
  105: 
  106:                                         hg push ../scratch
  107:                                         cd ../scratch
  108:                                         hg update
  109:                                         hg merge
  110:                                         ...whatever merge stuff, including commit...
  111:                                         cd ../src
  112:                                         hg pull ../scratch
  113:                                         hg update
  114: 
  115: ### Disconnected operation
  116: 
  117: Mercurial is a distributed system, and works by cloning the entire
  118: history into each tree you create.
  119: This has its downsides; but it means that you get disconnected
  120: operation for free.
  121: The only operations that need to contact the master repository are
  122: push, pull, incoming, and outgoing.
  123: 
  124: ### Some other bits
  125: 
  126: A commit with no descendents (that is, the most recent commit on any
  127: line of development) is called a "head".
  128: You can list these as follows:
  129: 
  130:                                         hg heads
  131: 
  132: This will include commits that have descendents only on other
  133: branches, e.g. the last commit on a development branch that's been
  134: merged but not closed. Use "-t" ("topological heads") to hide these.
  135: 
  136: You can see what "hg pull" and "hg push" are going to do via "hg
  137: incoming" and "hg outgoing" respectively.
  138: (FWIW, git can't do this.)
  139: 
  140: If you interrupt Mercurial (or Mercurial gets interrupted, e.g. by a
  141: system crash) you want to do this afterwards:
  142: 
  143:                                         hg recover
  144: 
  145: and if you have reason to think the repository might be corrupt you
  146: can check it like this:
  147: 
  148:                                         hg verify
  149: 
  150: ### Development branches
  151: 
  152: A development branch is one where you're working on some new feature
  153: and you expect to merge the branch into the trunk later.
  154: Unlike in CVS, this is very cheap in Mercurial.
  155: The following are the operations you need, using "libc13" as an
  156: example branch name.
  157: 
  158: Note that even if you're working on something nontrivial that will
  159: take a number of commits, if you aren't intending to push the changes
  160: out before they're done you don't need to make a branch and there's
  161: nothing gained by doing so.
  162: However, if you expect to be working over a long period of time on a
  163: major effort (such as the mythical libc version bump), and/or you
  164: want or expect other developers to contribute or at least test your
  165: changes before they're done, go ahead and create a branch.
  166: 
  167: Create a new branch:
  168: 
  169:     cvs update -dP                      hg pull && hg update            (if needed)
  170:     update doc/BRANCHES                 update doc/BRANCHES             (if appropriate)
  171:     cvs commit doc/BRANCHES             hg commit doc/BRANCHES          (if needed)
  172:     cvs tag libc13-base                 hg tag libc13-base
  173:     cvs ph'tagn                         hg branch libc13
  174:     [make first change]                 [make first change]
  175:     cvs commit                          hg commit
  176:                                         hg push
  177: 
  178: Mercurial warns you that branches are permanent and expensive; this
  179: warning is aimed at git users who ought to be creating bookmarks
  180: instead and not something you need to be concerned about.
  181: 
  182: Check out a new tree on a branch:
  183: 
  184:     cvs co -P -rlibc13                  hg clone [url]
  185:                                         cd src
  186:                                         hg update -r libc13
  187: 
  188: Switch to a new tree on a branch:
  189: 
  190:     cvs up -dP -A -rlibc13              hg pull                         (if needed)
  191:                                         hg update -r libc13
  192: 
  193: Note that if you have uncommitted changes, Mercurial will balk at
  194: crossing from one branch to another because it doesn't know how to
  195: merge them.
  196: In that case do this:
  197: 
  198:                                         hg update -r libc13-base
  199:                                         [resolve conflicts if needed]
  200:                                         hg update -r libc13
  201:                                         [resolve conflicts if needed]
  202: 
  203: Check which branch you're currently on:
  204: 
  205:     cat CVS/Tag                         hg branch
  206: 
  207: See list of branches:
  208: 
  209:     [no can do reliably]                hg branches     
  210: 
  211: Note that unlike with CVS there's no version-control-related reason to
  212: get a new tree just to work on a branch.
  213: (Although of course it's still possible to commit to the wrong branch
  214: by accident.)
  215: Get a new tree if and only if you want to have a different tree for
  216: administrative reasons.
  217: 
  218: Sync your branch with the trunk ("HEAD" in CVS):
  219: 
  220:     cvs ph'tagn                         hg merge default
  221:     [resolve conflicts]                 [resolve conflicts]
  222:     cvs commit                          hg commit
  223:                                         hg push
  224: 
  225: When you're done with your branch, in Mercurial you can "close" it so
  226: it's no longer active.
  227: This causes it to disappear from some reports, reduces some internal
  228: management overheads, and prevents accidental commits on it.
  229: 
  230:     [no can do]                         hg commit --close-branch
  231: 
  232: Don't forget to update doc/BRANCHES too.
  233: 
  234: ### Vendor branches
  235: 
  236: A vendor branch is one where code from a third party is committed in
  237: unmodified state, so it can be updated easily from upstream later.
  238: 
  239: Note that in CVS vendor branches are magic (in a bad way); in
  240: Mercurial we'll just use an ordinary branch. We'll start it from the
  241: empty revision so it doesn't contain any unwanted rubbish.
  242: 
  243: To start a new vendor branch for the upstream package "frobozz",
  244: assuming you've already written frobozz2netbsd if one's needed:
  245: 
  246:     mkdir tmp
  247:     cd tmp
  248:                                         hg update -r0000
  249:                                         mkdir external && cd external
  250:                                         mkdir bsd && cd bsd
  251:                                         mkdir frobozz && cd frobozz
  252:     tar -xvzf frobozz-1.0.tgz           tar -xvzf frobozz-1.0.tgz
  253:     mv frobozz-1.0 dist                 mv frobozz-1.0 dist
  254:     cp .../frobozz2netbsd .             cp .../frobozz2netbsd .
  255:     ./frobozz2netbsd                    ./frobozz2netbsd                (if needed)
  256:     cvs import src/distrib/bsd/frobozz \
  257:       FROBOZZ frobozz-1-0
  258:                                         hg add
  259:                                         hg branch FROBOZZ
  260:                                         hg commit
  261:                                         hg tag frobozz-1-0
  262:     cd ../src
  263:     cvs update -dP
  264:                                         hg update -r default
  265:                                         hg merge FROBOZZ
  266:                                         hg commit
  267:     [hack as needed]                    [hack as needed]
  268:     cvs commit                          hg commit
  269:                                         hg push
  270:     cd ..
  271:     rm -r tmp
  272: 
  273: Note that in both cases this imports frobozz2netbsd on the branch;
  274: this seems the most convenient but I'm not sure if it's been our
  275: standard procedure.
  276: 
  277: To update "frobozz" to 1.1:
  278: 
  279:     mkdir tmp
  280:     cd tmp
  281:                                         hg update -rFROBOZZ
  282:                                         cd external/bsd/frobozz
  283:     tar -xvzf frobozz-1.1.tgz           tar -xvzf frobozz-1.1.tgz
  284:                                         rm -r dist
  285:     mv frobozz-1.1 dist                 mv frobozz-1.1 dist
  286:     ./frobozz2netbsd                    ./frobozz2netbsd
  287:     cvs import src/distrib/bsd/frobozz \
  288:       FROBOZZ frobozz-1-0
  289:                                         hg addremove
  290:                                         hg commit
  291:                                         hg tag frobozz-1-1
  292:     cd ..
  293:     mkdir tmp2 && cd tmp2
  294:     cvs ph'tagn
  295:                                         hg update -r default
  296:                                         hg merge FROBOZZ
  297:     [resolve conflicts]                 [resolve conflicts]
  298:     cvs commit                          hg commit
  299:     cd ../src
  300:     cvs update -dP
  301:     [hack as needed]                    [hack as needed]
  302:     cvs commit                          hg commit
  303:                                         hg push
  304:     cd ..
  305:     rm -r tmp tmp2
  306: 
  307: ### Release branches
  308: 
  309: A release branch is one that diverges from the main branch and is not
  310: expected to be merged back into it.
  311: However, changes from the main branch are (individually) merged into
  312: it after review.
  313: 
  314: Creating a release branch in Mercurial is the same as creating a
  315: feature branch; see above.
  316: So is checking it out.
  317: Committing a change to a release branch is no different from
  318: committing to the default branch or any other branch.
  319: 
  320: TODO: we should probably use the Mercurial cherrypick extension for at
  321: least some release branch pullups; I don't know how to do that offhand
  322: without looking it up.
  323: 
  324: Tagging a release:
  325: 
  326:     cvs rtag -r netbsd-7 \              hg tag -r netbsd-7 \
  327:       netbsd-7-0-RELEASE                  netbsd-7-0-RELEASE
  328: 
  329: Viewing the changes on a branch:
  330: 
  331:     cvs log > file                      hg log -b netbsd-7
  332:     [page through and curse]
  333: 
  334: Extracting tarballs:
  335: 
  336:     mkdir tmp
  337:     cd tmp
  338:     cvs export -r netbsd-7-0-RELEASE \  hg archive -r netbsd-7-0-RELEASE \
  339:       src                                 ../netbsd-7.0.tar.gz
  340:     mv src netbsd-7.0
  341:     tar -cvzf ../netbsd-7.0.tar.gz \
  342:       netbsd-7.0
  343:     cd ..
  344:     rm -r tmp
  345: 
  346: 
  347: ### Reverting a bad commit
  348: 
  349: Sometimes somebody commits something that needs to be unwound later.
  350: In CVS you have to track down each per-file change and undo each one
  351: separately, then commit them all.
  352: In Mercurial, because Mercurial has whole-tree commits, you can do it
  353: with a single command.
  354: 
  355:     cvs update -j1.6 -j1.5 foo.c
  356:     cvs update -j1.9 -j1.8 bar.c
  357:     cvs update -j1.15 -j1.14 baz.c
  358:                                         hg backout -r 101abcde
  359:     [resolve conflicts]                 [resolve conflicts]
  360:     cvs commit                          hg commit
  361:                                         hg push
  362: 
  363: Note that apparently if you use hg backout to back out the most recent
  364: commit, it auto-commits.
  365: (This seems to me like a UI bug.)
  366: 
  367: ### Carrying local changes
  368: 
  369: In CVS you can keep uncommitted changes in your tree indefinitely with
  370: no ill effects.
  371: (Or at least, no ill effects until you want to commit other changes to
  372: the same files, run into merge conflicts, or hit PR 42961.)
  373: 
  374: In Mercurial having uncommitted changes keeps you from doing explicit
  375: merges, which you need to do much more often than in CVS.
  376: There are several ways around this:
  377: 
  378: * You can stash your uncommitted changes any time you need to merge.
  379: This works fine but it quickly becomes a nuisance.
  380: * You can use different trees for hacking and for building the system
  381: for install, since presumably you only need the local changes in
  382: the latter case.
  383: This works fine until you need to shift partially-completed hacking to
  384: the installable tree, and then becomes painful.
  385: * You can commit your local changes as "secret" using the evolve
  386: extension (I recommend reading the docs for the evolve extension);
  387: then they're committed and can be merged and so on, but won't get
  388: pushed back to the master repository.
  389: The downside of this is that you can't readily distribute your local
  390: changes among your own repositories.
  391: * You can use the mq patch queue extension and store your local
  392: changes as patches against the tree; then they can be popped off
  393: easily for other work.
  394: The downside of this is that merging stuff into your local changes
  395: becomes awkward.
  396: * You can finish your local changes so they can be committed upstream :-)
  397: 
  398: None of these solutions is perfect, but one or the other of these
  399: approaches is probably good enough in most cases.
  400: 
  401: ### Reverting stuff locally
  402: 
  403: In CVS you can use "cvs update" to pin a subtree down to a specific
  404: point in history, where it will stay while you update the rest of the
  405: tree around it.
  406: (Accidental engagement of this feature is probably as common as
  407: intentional use...)
  408: 
  409: There is no direct equivalent in Mercurial.
  410: However, you can easily alter a file or subtree to roll it back to a
  411: specific point in history, and then carry the resulting diff as a
  412: local modification until whatever issue prompted you to do this gets
  413: sorted out.
  414: 
  415: To revert to a specific version:
  416: 
  417:                                         hg revert -r rev subtree
  418: To revert to a specific date:
  419: 
  420:                                         hg revert -d date subtree
  421: 
  422: 
  423: ### Other stuff
  424: 
  425: Have I forgotten anything?
  426: Email me questions...

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