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