Annotation of wikisrc/users/dholland/mercurial.mdwn, revision 1.1
1.1 ! dholland 1: ## Using Mercurial and mq to work on NetBSD
! 2:
! 3: This page contains directions for using Mercurial as a commit buffer
! 4: for NetBSD.
! 5:
! 6: (It will not do you much good if you're trying to convert the master
! 7: NetBSD tree to Mercurial or to work with such a converted tree.)
! 8:
! 9: ### What it is
! 10:
! 11: Mercurial is a distributed version control system ("DVCS").
! 12: mq is an extension to Mercurial for handling patch queues.
! 13: The concept of patch queues was introduced by Quilt some years back.
! 14:
! 15: This document assumes you already know more or less how to use
! 16: Mercurial but may not have used mq before.
! 17:
! 18: ### The model we're using here
! 19:
! 20: What we're going to do is commit a NetBSD CVS working tree into a
! 21: Mercurial repository.
! 22: You can then use Mercurial to merge; it is better at this than CVS.
! 23: You can also commit changes locally and ship them back to the CVS
! 24: master later; this is useful in a variety of ways.
! 25: You can potentially also clone the Mercurial tree and work jointly
! 26: with other people, but there are limits to this as we'll discuss in a
! 27: moment.
! 28:
! 29: Because the NetBSD tree is rather large, you will find that if you
! 30: commit the whole thing into Mercurial that a number of operations
! 31: (anything that scans the working tree for changes) become annoyingly
! 32: slow.
! 33: It isn't slow enough to be unusable, and it's quite a bit faster than a
! 34: comparable CVS option (like running cvs update from the top level),
! 35: but it's slow enough to be annoying.
! 36:
! 37: For this reason, in most cases, I recommend committing only part of
! 38: the tree into Mercurial and telling it to ignore the rest. This means
! 39: you can't in general usefully clone the resulting Mercurial repo
! 40: (although that depends on exactly what you leave out) but this is not
! 41: a major problem unless you're specifically trying to work with someone
! 42: else.
! 43:
! 44: So the basic model here is that you check out a CVS working tree and
! 45: use Mercurial to manage local changes to part of it, then later on
! 46: commit those changes back to the master CVS repository.
! 47:
! 48: ### Branches vs. patches
! 49:
! 50: There are two ways you can manage your changes: as a branch, or as a
! 51: patch queue.
! 52: The advantage of a patch queue is that you can easily commit each
! 53: patch individually back to CVS, and you can go back and forth between
! 54: them and debug and polish each one separately.
! 55: The disadvantage is that the merge facilities are (as far as I know
! 56: anyway) relatively limited.
! 57:
! 58: Conversely, if you commit your changes to a branch, you get all the
! 59: native merging support in Mercurial.
! 60: However, it is painful to try to commit anything other than one big
! 61: diff for the whole branch back to CVS.
! 62: (You might be able to do it via bookmarks and rebasing, but I've never
! 63: tried and have no desire to figure out how.)
! 64:
! 65: If you don't want to keep the incremental history of your local
! 66: commits, use a branch.
! 67: If you do, use a patch queue.
! 68:
! 69: It is possible to use multiple branches to allow you to commit back in
! 70: several stages.
! 71: However, managing this is a major pain and I don't recommend it -- you
! 72: might get away with two branches but more than that is probably a bad
! 73: idea.
! 74:
! 75: There's a Mercurial extension called the "patch branch extension" that
! 76: lets you manage a whole graph of patches using branches.
! 77: I haven't tried using it in some years; at the time it had scaling
! 78: problems such that it became horrifyingly slow once you had more than
! 79: a handful of such branches.
! 80: That might have been improved in the meantime; if you find yourself
! 81: wanting to use both branches and patches, it might be worth looking
! 82: into.
! 83:
! 84: It is also fairly probable that there is now a solution for merging
! 85: with patch queues; it's been a while since I had time to look closely.
! 86:
! 87: ### Setting up
! 88:
! 89: First, check out a CVS working tree.
! 90: You probably want to use a different one for each project, because
! 91: different projects require changing different parts of the tree and so
! 92: you will probably want to have Mercurial ignore different subtrees for
! 93: different projects.
! 94: (At least, I find it so; it depends on what you're working on.)
! 95:
! 96: % cvs -d cvs.netbsd.org:/cvsroot checkout -dP src
! 97:
! 98: Now create a Mercurial repository at the top level.
! 99: (If you are working only in a subtree and you are *sure* that you will
! 100: never need to change anything in other parts of the tree, you can
! 101: create the Mercurial repository in a subtree.
! 102: But unless you're absolutely certain, don't take the risk.)
! 103:
! 104: % cd src
! 105: % hg init
! 106:
! 107: If you're going to be using a patch queue, now enable mq.
! 108:
! 109: % vi .hg/hgrc
! 110: and add
! 111: [extensions]
! 112: hgext.mq =
! 113: (Since the extension is built into Mercurial, that's all you need.)
! 114: You can if you prefer also put this in your .hgrc so mq is always on.
! 115: Then do
! 116: hg qinit -c
! 117: The -c option tells mq that you'll be checkpointing your patches,
! 118: which is usually a good idea.
! 119:
! 120: Now prepare a .hgignore file.
! 121: This file contains one regular expression per line; Mercurial ignores
! 122: files (and subdirectories) whose paths from the repository root match
! 123: one of the regexps.
! 124: Add at least:
! 125: ^CVS$
! 126: /CVS$
! 127: to ignore all the CVS control directories in the CVS checkout.
! 128: While you can commit these to Mercurial, there's no point and it gets
! 129: awkward if owing to mistakes later you end up having to merge them.
! 130:
! 131: If you aren't arranging to put the tree's object directories somewhere
! 132: else, then also add
! 133: ^obj\.[0-9a-z]$
! 134: /obj\.[0-9a-z]$
! 135: and you might want
! 136: ^sys/arch/[0-9a-z]*/compile/[A-Z]
! 137: to ignore kernel build directories.
! 138:
! 139: Ignore subtrees that you aren't working in.
! 140: You don't have to bother to be very selective; the goal is to rapidly
! 141: rule out a few large subtrees that you definitely don't care about, in
! 142: order to avoid wasting time scanning them for changes.
! 143: Unless you plan to be working with 3rd-party software,
! 144:
! 145: ^external$
! 146: ^gnu/dist$
! 147:
! 148: is a good starting point.
! 149: Alternatively, if you aren't going to be working on MD kernel stuff or
! 150: bootloaders,
! 151:
! 152: ^sys/arch$
! 153:
! 154: is a good choice as it's also large.
! 155:
! 156: You can always unignore stuff later, so don't worry about remote
! 157: possibilities.
! 158:
! 159: Now commit the .hgignore file:
! 160:
! 161: % hg add .hgignore
! 162: % hg commit -m 'add .hgignore file' .hgignore
! 163:
! 164: Now add and commit the contents of the working tree:
! 165:
! 166: % hg add
! 167: % hg commit -m 'HEAD of 20130101'
! 168: (or whatever date)
! 169:
! 170: You are now in business.
! 171:
! 172: ### Working
! 173:
! 174: If you're using a branch, remember to change branches before you
! 175: commit anything:
! 176: % hg branch mystuff
! 177: You want to keep the default branch an untouched CVS tree so you can
! 178: use Mercurial to merge.
! 179: (And also so you can use Mercurial to extract diffs against CVS HEAD
! 180: and so forth.)
! 181:
! 182: Similarly, if you're using a patch queue, put everything in patches
! 183: and don't commit.
! 184: (There's a section below about working with mq if you aren't familiar
! 185: with it.)
! 186:
! 187: You can edit and build and test as normal.
! 188: Use hg commit or hg qrefresh to sync stuff into Mercurial.
! 189:
! 190: If you're using mq, it's a good idea to checkpoint your patch queue
! 191: periodically.
! 192: This is done as follows:
! 193: % hg qcommit
! 194: The patches directory (.hg/patches) is stored in its own Mercurial
! 195: repository, and this commits the patches to that repository.
! 196: If necessary you can then fetch older versions of the patches back and
! 197: so forth.
! 198:
! 199: ### Updating from CVS
! 200:
! 201: First, make sure all your changes are committed.
! 202: (If you have unfinished changes that aren't ready to commit, there's a
! 203: Mercurial extension for stashing them temporarily.
! 204: If you have stuff that you don't want to commit at all, like debugging
! 205: printouts or quick hacks, it's often convenient to keep those in their
! 206: own mq patch, even if you aren't using mq for development.)
! 207:
! 208: Now go back to a clean CVS tree.
! 209: If using branches, go back to the default branch:
! 210: % hg update -r default
! 211: If using mq, pop all the patches:
! 212: % hg qpop -a
! 213:
! 214: DO NOT run cvs update until/unless you have done this; it will make a
! 215: mess.
! 216: When you eventually do this by accident, see the section below on
! 217: recovering from mistakes.
! 218:
! 219: Now run cvs update from the top of the source tree:
! 220: % cvs -q update -dP
! 221:
! 222: You should get no conflicts from CVS and nothing should show as
! 223: modified.
! 224: (It is usually a good habit to save the cvs update output to a file to
! 225: be able to check this.)
! 226:
! 227: Tell hg to sync up:
! 228: % hg addremove
! 229:
! 230: Use hg to check what it thinks has changed:
! 231: % hg status
! 232:
! 233: Commit the changes to Mercurial:
! 234: % hg commit -m 'Updated to 20130202"
! 235:
! 236: Now you get to merge.
! 237:
! 238: If you're using a branch, you want to merge the changes into your
! 239: branch rather than merge your branch into the changes:
! 240: % hg update -r mystuff
! 241: % hg merge default
! 242: (edit and resolve as needed)
! 243: % hg commit -m 'sync with HEAD'
! 244:
! 245: If it tells you "update crosses branches" when trying to update back
! 246: to your branch, update to the parent changeset (the previous version
! 247: from CVS) first, as that's an ancestor of your branch.
! 248:
! 249: If you're using mq, the thing to do now is to push all your patches,
! 250: and if any reject, clean up the mess and refresh them.
! 251:
! 252: If patch tells you "hunk N succeeded at offset MMM with fuzz Q", it's
! 253: a good idea to manually inspect the results -- patch being what it is,
! 254: sometimes this means it's done the wrong thing.
! 255: Edit if needed.
! 256: Then (even if you didn't edit) refresh the patch so it won't happen
! 257: again.
! 258:
! 259: As I said above, it's quite likely that by now there's a better scheme
! 260: for merging with mq that I don't know about yet.
! 261:
! 262: ### Pushing back to CVS
! 263:
! 264: When you're ready to push your changes back to CVS (so they're really
! 265: committed), first (unless you're absolutely sure it's not necessary)
! 266: update from CVS as above and merge.
! 267: Then:
! 268:
! 269: If you're using a branch, go back to the default branch and merge your
! 270: changes into it:
! 271: % hg update -r default
! 272: % hg merge mystuff
! 273: % hg commit -m "prepare to commit back to cvs"
! 274: Now cvs add any new directories and files; be sure not to forget this.
! 275: It is a good idea to crosscheck with cvs diff and/or cvs update:
! 276: % cvs diff -up | less
! 277: % cvs -nq update -dP
! 278: Then you can cvs commit:
! 279: % cvs commit
! 280: Because of RCSIDs, committing into cvs changes the source files.
! 281: So now you need to do:
! 282: % hg commit -m 'cvs committed'
! 283: and if you intend to keep working in this tree, you want to merge that
! 284: changeset back into your branch to avoid having it cause merge
! 285: conflicts later.
! 286: Do that as above.
! 287:
! 288:
! 289: If you're using a patch queue, usually it's because you want to commit
! 290: each patch back to CVS individually.
! 291: First pop all the patches:
! 292: % hg qpop -a
! 293: Now, for each patch:
! 294: % hg qpush
! 295: % hg qfinish -a
! 296: % cvs commit
! 297: % hg commit -m "cvs committed previous"
! 298: With a long patch queue, you'll want to use the patch comments as the
! 299: CVS commit messages.
! 300: Also, running cvs commit from the top for every patch is horribly slow.
! 301: Both these problems can be fixed by putting the following in a script:
! 302: hg log -v -r. | sed '1,/^description:$/d' > patch-message
! 303: cat patch-message
! 304: echo -n 'cvs commit -F patch-message '
! 305: hg log -v -r. | grep '^files:' | sed 's/^files://'
! 306: (I call this "dogetpatch.sh") and then the procedure is:
! 307: % hg qpop -a
! 308: then for each patch:
! 309: % hg qpush && hg qfinish -a && dogetpatch.sh
! 310: % cvs commit [as directed]
! 311: % hg commit -m "cvs committed previous"
! 312: (This could be automated further but doing so seems unwise.)
! 313:
! 314: ### Using CVS within Mercurial
! 315:
! 316: You can successfully do any read-only CVS operation in the hybrid
! 317: tree: diff, annotate, log, update -p, etc.
! 318: Read-write operations should be avoided; if you mix upstream changes
! 319: with your changes you will find it much harder to commit upstream
! 320: later, and you may get weird merge conflicts or even accidentally
! 321: revert other people's changes and cause problems.
! 322:
! 323: If you clone the Mercurial tree and you didn't include the CVS control
! 324: files in it, you won't be able to do CVS operations from clones.
! 325: Including the CVS control files in the Mercurial tree is one way
! 326: around that.
! 327:
! 328: You will find that any large CVS operation on a clone is horribly
! 329: slow.
! 330: This is because making a clone causes CVS to think all the files in
! 331: the clone have been modified since you last ran it; it then re-fetches
! 332: every file you ask it about so it can update its own information.
! 333: For this reason cloning the Mercurial tree usually isn't worthwhile
! 334: and even when it is, including the CVS files in the Mercurial tree
! 335: isn't.
! 336:
! 337: Another consequence of this: do not try to cvs update in a cloned
! 338: Mercurial repository; use only the original.
! 339: Updating a clone basically downloads the entire tree over again from
! 340: the CVS server.
! 341:
! 342: DO NOT CVS COMMIT FROM A CLONE.
! 343: It is known that some operations that muck with the timestamps in a
! 344: CVS working tree can cause CVS to lose data.
! 345: It is not clear if hg clone is such an operation; don't be the person
! 346: who finds out the hard way.
! 347:
! 348: ### Recovering from mistakes
! 349:
! 350: The most common mistake is CVS updating when the Mercurial tree is not
! 351: in the proper state from that; e.g. onto your branch or while you have
! 352: patches applied.
! 353:
! 354: The basic strategy for this is to use hg revert to restore the part of
! 355: the tree it knows about, then go back to CVS, clean up the mess there,
! 356: and update properly.
! 357:
! 358: If you're using a branch:
! 359: % hg revert -C
! 360: % hg update -r default
! 361: If you're using a patch queue:
! 362: % hg revert -C
! 363: % hg qpop -a
! 364:
! 365: The problem is, CVS will now think you've changed every file that
! 366: Mercurial is managing, and the modifications are to revert all the
! 367: changes that have happened since your previous update.
! 368: You do *not* want that to turn into reality.
! 369: Hunt down (with cvs -n update) any files that CVS thinks are modified,
! 370: then rm them and run cvs update on them.
! 371: CVS will print "Warning: foo was lost" and restore an unmodified copy.
! 372:
! 373: When you have no files left that CVS thinks are modified, do a CVS
! 374: update on the whole tree and merge it as described above.
! 375: (You must do this, as the parts of the tree that Mercurial is ignoring
! 376: will otherwise be out of sync with the parts it's managing.)
! 377:
! 378: If you stored the CVS control files in Mercurial, then the revert will
! 379: restore them, but your tree will still be inconsistent so you still
! 380: need to do a proper update and merge immediately.
! 381:
! 382: ### mq
! 383:
! 384: The basic idea of mq (like quilt) is it maintains a series of patches
! 385: against the source tree, that are to be applied in order.
! 386: By applying them or removing them one at a time, you can move the tree
! 387: to any intermediate state; and then you can update the topmost patch,
! 388: insert a new patch, or whatever.
! 389:
! 390: To see the list of patches:
! 391: % hg qseries
! 392:
! 393: To apply the next patch:
! 394: % hg qpush
! 395:
! 396: To remove the current patch:
! 397: % hg qpop
! 398:
! 399: To merge current working tree changes into the current patch:
! 400: % hg qrefresh
! 401:
! 402: To also update the current patch's change comment:
! 403: % hg qrefresh -e
! 404:
! 405: To collect current working tree changes (if any) into a new patch:
! 406: % hg qnew PATCHNAME
! 407:
! 408: When there's an mq patch applied, you can't commit.
! 409: (Doing qrefresh is basically equivalent to committing the current
! 410: patch.)
! 411: Diff will show the changes against the last refreshed version of the
! 412: current patch; to see the complete changes for the current patch
! 413: (including current changes), use "hg qdiff".
! 414:
! 415: You can delete patches with "hg qrm" and rename them with "hg qmv".
! 416:
! 417: Patches are applied with patch, unfortunately, which means that if
! 418: they don't apply (which can happen if you or someone else changes
! 419: something under one) you get .rej files you have to clean up by hand
! 420: rather than a Mercurial merge.
! 421:
! 422: When a patch is ready to be committed for real, you do "hg qfinish" on
! 423: it.
! 424: This removes it from the patch queue and converts it to a normal
! 425: Mercurial changeset.
! 426:
! 427: To change the ordering of patches, you edit the file
! 428: .hg/patches/series.
! 429: If the patches aren't orthogonal you'll have to fix the rejections
! 430: when you next apply them.
! 431: (Don't do this with patches that are currently applied.)
! 432:
! 433: Use "hg help mq" to see the full list of mq-related commands.
! 434:
! 435: I'm sure there are better mq tutorials out there.
! 436:
! 437: ### Using mq
! 438:
! 439: The basic process when using mq is that you start a new patch, edit
! 440: and hack for a while, use hg qrefresh to commit it (once or many
! 441: times), and when you're done go on to the next one.
! 442:
! 443: If you find a bug in an earlier patch, you can go back to the patch
! 444: that introduced it and fix the bug there, creating a new version of
! 445: the offending patch that no longer contains the bug.
! 446: (Or you can create a new patch that fixes the bug, but insert it
! 447: immediately after the patch that created the bug.)
! 448:
! 449: When a patch is ready to be seen by other people, you "finish" it and
! 450: then it becomes a normal immutable changeset.
! 451:
! 452: One catch is that you can't push or pop the patch queue while you have
! 453: unsynced (uncommitted) changes.
! 454: There are two ways around this; there's a separate "stash" extension
! 455: that lets you put unfinished changes aside while you do something else.
! 456: Or, alternatively, you can create a new temporary patch holding your
! 457: unfinished changes, and then later use hg qfold to combine that with
! 458: the patch you originally meant this for.
! 459:
! 460: A variant of this problem is when you discover a bug, open an editor,
! 461: fix it, and then realize that you wanted to make the edit in an
! 462: earlier patch.
! 463: Then you go to pop the queue and it complains that you have a modified
! 464: file.
! 465: If the modification in question is the only uncommitted change, the
! 466: best way to deal with this is to create a new patch for it, then pop
! 467: to where you wanted it to go and use hg qfold to apply it there.
CVSweb for NetBSD wikisrc <wikimaster@NetBSD.org> software: FreeBSD-CVSweb