File:  [NetBSD Developer Wiki] / wikisrc / users / dholland / hgnb.mdwn
Revision 1.2: download - view: text, annotated - select for diffs
Sun Dec 14 02:56:04 2014 UTC (8 years, 9 months ago) by dholland
Branches: MAIN
CVS tags: HEAD
test markup

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

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