##// END OF EJS Templates
Kill trailing spaces
Thomas Arendsen Hein -
r4659:7a7d4937 default
parent child Browse files
Show More
@@ -1,56 +1,56 b''
1 #!/bin/sh
1 #!/bin/sh
2 #
2 #
3 # This is an example of using HGEDITOR to create of diff to review the
3 # This is an example of using HGEDITOR to create of diff to review the
4 # changes while commiting.
4 # changes while commiting.
5
5
6 # If you want to pass your favourite editor some other parameters
6 # If you want to pass your favourite editor some other parameters
7 # only for Mercurial, modify this:
7 # only for Mercurial, modify this:
8 case "${EDITOR}" in
8 case "${EDITOR}" in
9 "")
9 "")
10 EDITOR="vi"
10 EDITOR="vi"
11 ;;
11 ;;
12 emacs)
12 emacs)
13 EDITOR="$EDITOR -nw"
13 EDITOR="$EDITOR -nw"
14 ;;
14 ;;
15 gvim|vim)
15 gvim|vim)
16 EDITOR="$EDITOR -f -o"
16 EDITOR="$EDITOR -f -o"
17 ;;
17 ;;
18 esac
18 esac
19
19
20
20
21 HGTMP=""
21 HGTMP=""
22 cleanup_exit() {
22 cleanup_exit() {
23 rm -rf "$HGTMP"
23 rm -rf "$HGTMP"
24 }
24 }
25
25
26 # Remove temporary files even if we get interrupted
26 # Remove temporary files even if we get interrupted
27 trap "cleanup_exit" 0 # normal exit
27 trap "cleanup_exit" 0 # normal exit
28 trap "exit 255" 1 2 3 6 15 # HUP INT QUIT ABRT TERM
28 trap "exit 255" 1 2 3 6 15 # HUP INT QUIT ABRT TERM
29
29
30 HGTMP="${TMPDIR-/tmp}/hgeditor.$RANDOM.$RANDOM.$RANDOM.$$"
30 HGTMP="${TMPDIR-/tmp}/hgeditor.$RANDOM.$RANDOM.$RANDOM.$$"
31 (umask 077 && mkdir "$HGTMP") || {
31 (umask 077 && mkdir "$HGTMP") || {
32 echo "Could not create temporary directory! Exiting." 1>&2
32 echo "Could not create temporary directory! Exiting." 1>&2
33 exit 1
33 exit 1
34 }
34 }
35
35
36 (
36 (
37 grep '^HG: changed' "$1" | cut -b 13- | while read changed; do
37 grep '^HG: changed' "$1" | cut -b 13- | while read changed; do
38 hg diff "$changed" >> "$HGTMP/diff"
38 hg diff "$changed" >> "$HGTMP/diff"
39 done
39 done
40 )
40 )
41
41
42 cat "$1" > "$HGTMP/msg"
42 cat "$1" > "$HGTMP/msg"
43
43
44 MD5=$(which md5sum 2>/dev/null) || \
44 MD5=$(which md5sum 2>/dev/null) || \
45 MD5=$(which md5 2>/dev/null)
45 MD5=$(which md5 2>/dev/null)
46 [ -x "${MD5}" ] && CHECKSUM=`${MD5} "$HGTMP/msg"`
46 [ -x "${MD5}" ] && CHECKSUM=`${MD5} "$HGTMP/msg"`
47 if [ -s "$HGTMP/diff" ]; then
47 if [ -s "$HGTMP/diff" ]; then
48 $EDITOR "$HGTMP/msg" "$HGTMP/diff" || exit $?
48 $EDITOR "$HGTMP/msg" "$HGTMP/diff" || exit $?
49 else
49 else
50 $EDITOR "$HGTMP/msg" || exit $?
50 $EDITOR "$HGTMP/msg" || exit $?
51 fi
51 fi
52 [ -x "${MD5}" ] && (echo "$CHECKSUM" | ${MD5} -c >/dev/null 2>&1 && exit 13)
52 [ -x "${MD5}" ] && (echo "$CHECKSUM" | ${MD5} -c >/dev/null 2>&1 && exit 13)
53
53
54 mv "$HGTMP/msg" "$1"
54 mv "$HGTMP/msg" "$1"
55
55
56 exit $?
56 exit $?
@@ -1,3045 +1,3045 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 import demandimport; demandimport.enable()
8 import demandimport; demandimport.enable()
9 from node import *
9 from node import *
10 from i18n import _
10 from i18n import _
11 import bisect, os, re, sys, urllib, shlex, stat
11 import bisect, os, re, sys, urllib, shlex, stat
12 import ui, hg, util, revlog, bundlerepo, extensions
12 import ui, hg, util, revlog, bundlerepo, extensions
13 import difflib, patch, time, help, mdiff, tempfile
13 import difflib, patch, time, help, mdiff, tempfile
14 import errno, version, socket
14 import errno, version, socket
15 import archival, changegroup, cmdutil, hgweb.server, sshserver
15 import archival, changegroup, cmdutil, hgweb.server, sshserver
16
16
17 # Commands start here, listed alphabetically
17 # Commands start here, listed alphabetically
18
18
19 def add(ui, repo, *pats, **opts):
19 def add(ui, repo, *pats, **opts):
20 """add the specified files on the next commit
20 """add the specified files on the next commit
21
21
22 Schedule files to be version controlled and added to the repository.
22 Schedule files to be version controlled and added to the repository.
23
23
24 The files will be added to the repository at the next commit. To
24 The files will be added to the repository at the next commit. To
25 undo an add before that, see hg revert.
25 undo an add before that, see hg revert.
26
26
27 If no names are given, add all files in the repository.
27 If no names are given, add all files in the repository.
28 """
28 """
29
29
30 names = []
30 names = []
31 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
31 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
32 if exact:
32 if exact:
33 if ui.verbose:
33 if ui.verbose:
34 ui.status(_('adding %s\n') % rel)
34 ui.status(_('adding %s\n') % rel)
35 names.append(abs)
35 names.append(abs)
36 elif repo.dirstate.state(abs) == '?':
36 elif repo.dirstate.state(abs) == '?':
37 ui.status(_('adding %s\n') % rel)
37 ui.status(_('adding %s\n') % rel)
38 names.append(abs)
38 names.append(abs)
39 if not opts.get('dry_run'):
39 if not opts.get('dry_run'):
40 repo.add(names)
40 repo.add(names)
41
41
42 def addremove(ui, repo, *pats, **opts):
42 def addremove(ui, repo, *pats, **opts):
43 """add all new files, delete all missing files
43 """add all new files, delete all missing files
44
44
45 Add all new files and remove all missing files from the repository.
45 Add all new files and remove all missing files from the repository.
46
46
47 New files are ignored if they match any of the patterns in .hgignore. As
47 New files are ignored if they match any of the patterns in .hgignore. As
48 with add, these changes take effect at the next commit.
48 with add, these changes take effect at the next commit.
49
49
50 Use the -s option to detect renamed files. With a parameter > 0,
50 Use the -s option to detect renamed files. With a parameter > 0,
51 this compares every removed file with every added file and records
51 this compares every removed file with every added file and records
52 those similar enough as renames. This option takes a percentage
52 those similar enough as renames. This option takes a percentage
53 between 0 (disabled) and 100 (files must be identical) as its
53 between 0 (disabled) and 100 (files must be identical) as its
54 parameter. Detecting renamed files this way can be expensive.
54 parameter. Detecting renamed files this way can be expensive.
55 """
55 """
56 sim = float(opts.get('similarity') or 0)
56 sim = float(opts.get('similarity') or 0)
57 if sim < 0 or sim > 100:
57 if sim < 0 or sim > 100:
58 raise util.Abort(_('similarity must be between 0 and 100'))
58 raise util.Abort(_('similarity must be between 0 and 100'))
59 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
59 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
60
60
61 def annotate(ui, repo, *pats, **opts):
61 def annotate(ui, repo, *pats, **opts):
62 """show changeset information per file line
62 """show changeset information per file line
63
63
64 List changes in files, showing the revision id responsible for each line
64 List changes in files, showing the revision id responsible for each line
65
65
66 This command is useful to discover who did a change or when a change took
66 This command is useful to discover who did a change or when a change took
67 place.
67 place.
68
68
69 Without the -a option, annotate will avoid processing files it
69 Without the -a option, annotate will avoid processing files it
70 detects as binary. With -a, annotate will generate an annotation
70 detects as binary. With -a, annotate will generate an annotation
71 anyway, probably with undesirable results.
71 anyway, probably with undesirable results.
72 """
72 """
73 getdate = util.cachefunc(lambda x: util.datestr(x.date()))
73 getdate = util.cachefunc(lambda x: util.datestr(x.date()))
74
74
75 if not pats:
75 if not pats:
76 raise util.Abort(_('at least one file name or pattern required'))
76 raise util.Abort(_('at least one file name or pattern required'))
77
77
78 opmap = [['user', lambda x: ui.shortuser(x.user())],
78 opmap = [['user', lambda x: ui.shortuser(x.user())],
79 ['number', lambda x: str(x.rev())],
79 ['number', lambda x: str(x.rev())],
80 ['changeset', lambda x: short(x.node())],
80 ['changeset', lambda x: short(x.node())],
81 ['date', getdate], ['follow', lambda x: x.path()]]
81 ['date', getdate], ['follow', lambda x: x.path()]]
82 if (not opts['user'] and not opts['changeset'] and not opts['date']
82 if (not opts['user'] and not opts['changeset'] and not opts['date']
83 and not opts['follow']):
83 and not opts['follow']):
84 opts['number'] = 1
84 opts['number'] = 1
85
85
86 ctx = repo.changectx(opts['rev'])
86 ctx = repo.changectx(opts['rev'])
87
87
88 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
88 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
89 node=ctx.node()):
89 node=ctx.node()):
90 fctx = ctx.filectx(abs)
90 fctx = ctx.filectx(abs)
91 if not opts['text'] and util.binary(fctx.data()):
91 if not opts['text'] and util.binary(fctx.data()):
92 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
92 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
93 continue
93 continue
94
94
95 lines = fctx.annotate(follow=opts.get('follow'))
95 lines = fctx.annotate(follow=opts.get('follow'))
96 pieces = []
96 pieces = []
97
97
98 for o, f in opmap:
98 for o, f in opmap:
99 if opts[o]:
99 if opts[o]:
100 l = [f(n) for n, dummy in lines]
100 l = [f(n) for n, dummy in lines]
101 if l:
101 if l:
102 m = max(map(len, l))
102 m = max(map(len, l))
103 pieces.append(["%*s" % (m, x) for x in l])
103 pieces.append(["%*s" % (m, x) for x in l])
104
104
105 if pieces:
105 if pieces:
106 for p, l in zip(zip(*pieces), lines):
106 for p, l in zip(zip(*pieces), lines):
107 ui.write("%s: %s" % (" ".join(p), l[1]))
107 ui.write("%s: %s" % (" ".join(p), l[1]))
108
108
109 def archive(ui, repo, dest, **opts):
109 def archive(ui, repo, dest, **opts):
110 '''create unversioned archive of a repository revision
110 '''create unversioned archive of a repository revision
111
111
112 By default, the revision used is the parent of the working
112 By default, the revision used is the parent of the working
113 directory; use "-r" to specify a different revision.
113 directory; use "-r" to specify a different revision.
114
114
115 To specify the type of archive to create, use "-t". Valid
115 To specify the type of archive to create, use "-t". Valid
116 types are:
116 types are:
117
117
118 "files" (default): a directory full of files
118 "files" (default): a directory full of files
119 "tar": tar archive, uncompressed
119 "tar": tar archive, uncompressed
120 "tbz2": tar archive, compressed using bzip2
120 "tbz2": tar archive, compressed using bzip2
121 "tgz": tar archive, compressed using gzip
121 "tgz": tar archive, compressed using gzip
122 "uzip": zip archive, uncompressed
122 "uzip": zip archive, uncompressed
123 "zip": zip archive, compressed using deflate
123 "zip": zip archive, compressed using deflate
124
124
125 The exact name of the destination archive or directory is given
125 The exact name of the destination archive or directory is given
126 using a format string; see "hg help export" for details.
126 using a format string; see "hg help export" for details.
127
127
128 Each member added to an archive file has a directory prefix
128 Each member added to an archive file has a directory prefix
129 prepended. Use "-p" to specify a format string for the prefix.
129 prepended. Use "-p" to specify a format string for the prefix.
130 The default is the basename of the archive, with suffixes removed.
130 The default is the basename of the archive, with suffixes removed.
131 '''
131 '''
132
132
133 node = repo.changectx(opts['rev']).node()
133 node = repo.changectx(opts['rev']).node()
134 dest = cmdutil.make_filename(repo, dest, node)
134 dest = cmdutil.make_filename(repo, dest, node)
135 if os.path.realpath(dest) == repo.root:
135 if os.path.realpath(dest) == repo.root:
136 raise util.Abort(_('repository root cannot be destination'))
136 raise util.Abort(_('repository root cannot be destination'))
137 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
137 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
138 kind = opts.get('type') or 'files'
138 kind = opts.get('type') or 'files'
139 prefix = opts['prefix']
139 prefix = opts['prefix']
140 if dest == '-':
140 if dest == '-':
141 if kind == 'files':
141 if kind == 'files':
142 raise util.Abort(_('cannot archive plain files to stdout'))
142 raise util.Abort(_('cannot archive plain files to stdout'))
143 dest = sys.stdout
143 dest = sys.stdout
144 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
144 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
145 prefix = cmdutil.make_filename(repo, prefix, node)
145 prefix = cmdutil.make_filename(repo, prefix, node)
146 archival.archive(repo, dest, node, kind, not opts['no_decode'],
146 archival.archive(repo, dest, node, kind, not opts['no_decode'],
147 matchfn, prefix)
147 matchfn, prefix)
148
148
149 def backout(ui, repo, node=None, rev=None, **opts):
149 def backout(ui, repo, node=None, rev=None, **opts):
150 '''reverse effect of earlier changeset
150 '''reverse effect of earlier changeset
151
151
152 Commit the backed out changes as a new changeset. The new
152 Commit the backed out changes as a new changeset. The new
153 changeset is a child of the backed out changeset.
153 changeset is a child of the backed out changeset.
154
154
155 If you back out a changeset other than the tip, a new head is
155 If you back out a changeset other than the tip, a new head is
156 created. This head is the parent of the working directory. If
156 created. This head is the parent of the working directory. If
157 you back out an old changeset, your working directory will appear
157 you back out an old changeset, your working directory will appear
158 old after the backout. You should merge the backout changeset
158 old after the backout. You should merge the backout changeset
159 with another head.
159 with another head.
160
160
161 The --merge option remembers the parent of the working directory
161 The --merge option remembers the parent of the working directory
162 before starting the backout, then merges the new head with that
162 before starting the backout, then merges the new head with that
163 changeset afterwards. This saves you from doing the merge by
163 changeset afterwards. This saves you from doing the merge by
164 hand. The result of this merge is not committed, as for a normal
164 hand. The result of this merge is not committed, as for a normal
165 merge.'''
165 merge.'''
166 if rev and node:
166 if rev and node:
167 raise util.Abort(_("please specify just one revision"))
167 raise util.Abort(_("please specify just one revision"))
168
168
169 if not rev:
169 if not rev:
170 rev = node
170 rev = node
171
171
172 cmdutil.bail_if_changed(repo)
172 cmdutil.bail_if_changed(repo)
173 op1, op2 = repo.dirstate.parents()
173 op1, op2 = repo.dirstate.parents()
174 if op2 != nullid:
174 if op2 != nullid:
175 raise util.Abort(_('outstanding uncommitted merge'))
175 raise util.Abort(_('outstanding uncommitted merge'))
176 node = repo.lookup(rev)
176 node = repo.lookup(rev)
177 p1, p2 = repo.changelog.parents(node)
177 p1, p2 = repo.changelog.parents(node)
178 if p1 == nullid:
178 if p1 == nullid:
179 raise util.Abort(_('cannot back out a change with no parents'))
179 raise util.Abort(_('cannot back out a change with no parents'))
180 if p2 != nullid:
180 if p2 != nullid:
181 if not opts['parent']:
181 if not opts['parent']:
182 raise util.Abort(_('cannot back out a merge changeset without '
182 raise util.Abort(_('cannot back out a merge changeset without '
183 '--parent'))
183 '--parent'))
184 p = repo.lookup(opts['parent'])
184 p = repo.lookup(opts['parent'])
185 if p not in (p1, p2):
185 if p not in (p1, p2):
186 raise util.Abort(_('%s is not a parent of %s') %
186 raise util.Abort(_('%s is not a parent of %s') %
187 (short(p), short(node)))
187 (short(p), short(node)))
188 parent = p
188 parent = p
189 else:
189 else:
190 if opts['parent']:
190 if opts['parent']:
191 raise util.Abort(_('cannot use --parent on non-merge changeset'))
191 raise util.Abort(_('cannot use --parent on non-merge changeset'))
192 parent = p1
192 parent = p1
193 hg.clean(repo, node, show_stats=False)
193 hg.clean(repo, node, show_stats=False)
194 revert_opts = opts.copy()
194 revert_opts = opts.copy()
195 revert_opts['date'] = None
195 revert_opts['date'] = None
196 revert_opts['all'] = True
196 revert_opts['all'] = True
197 revert_opts['rev'] = hex(parent)
197 revert_opts['rev'] = hex(parent)
198 revert(ui, repo, **revert_opts)
198 revert(ui, repo, **revert_opts)
199 commit_opts = opts.copy()
199 commit_opts = opts.copy()
200 commit_opts['addremove'] = False
200 commit_opts['addremove'] = False
201 if not commit_opts['message'] and not commit_opts['logfile']:
201 if not commit_opts['message'] and not commit_opts['logfile']:
202 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
202 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
203 commit_opts['force_editor'] = True
203 commit_opts['force_editor'] = True
204 commit(ui, repo, **commit_opts)
204 commit(ui, repo, **commit_opts)
205 def nice(node):
205 def nice(node):
206 return '%d:%s' % (repo.changelog.rev(node), short(node))
206 return '%d:%s' % (repo.changelog.rev(node), short(node))
207 ui.status(_('changeset %s backs out changeset %s\n') %
207 ui.status(_('changeset %s backs out changeset %s\n') %
208 (nice(repo.changelog.tip()), nice(node)))
208 (nice(repo.changelog.tip()), nice(node)))
209 if op1 != node:
209 if op1 != node:
210 if opts['merge']:
210 if opts['merge']:
211 ui.status(_('merging with changeset %s\n') % nice(op1))
211 ui.status(_('merging with changeset %s\n') % nice(op1))
212 hg.merge(repo, hex(op1))
212 hg.merge(repo, hex(op1))
213 else:
213 else:
214 ui.status(_('the backout changeset is a new head - '
214 ui.status(_('the backout changeset is a new head - '
215 'do not forget to merge\n'))
215 'do not forget to merge\n'))
216 ui.status(_('(use "backout --merge" '
216 ui.status(_('(use "backout --merge" '
217 'if you want to auto-merge)\n'))
217 'if you want to auto-merge)\n'))
218
218
219 def branch(ui, repo, label=None, **opts):
219 def branch(ui, repo, label=None, **opts):
220 """set or show the current branch name
220 """set or show the current branch name
221
221
222 With no argument, show the current branch name. With one argument,
222 With no argument, show the current branch name. With one argument,
223 set the working directory branch name (the branch does not exist in
223 set the working directory branch name (the branch does not exist in
224 the repository until the next commit).
224 the repository until the next commit).
225
225
226 Unless --force is specified, branch will not let you set a
226 Unless --force is specified, branch will not let you set a
227 branch name that shadows an existing branch.
227 branch name that shadows an existing branch.
228 """
228 """
229
229
230 if label:
230 if label:
231 if not opts.get('force') and label in repo.branchtags():
231 if not opts.get('force') and label in repo.branchtags():
232 if label not in [p.branch() for p in repo.workingctx().parents()]:
232 if label not in [p.branch() for p in repo.workingctx().parents()]:
233 raise util.Abort(_('a branch of the same name already exists'
233 raise util.Abort(_('a branch of the same name already exists'
234 ' (use --force to override)'))
234 ' (use --force to override)'))
235 repo.dirstate.setbranch(util.fromlocal(label))
235 repo.dirstate.setbranch(util.fromlocal(label))
236 ui.status(_('marked working directory as branch %s\n') % label)
236 ui.status(_('marked working directory as branch %s\n') % label)
237 else:
237 else:
238 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
238 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
239
239
240 def branches(ui, repo):
240 def branches(ui, repo):
241 """list repository named branches
241 """list repository named branches
242
242
243 List the repository's named branches.
243 List the repository's named branches.
244 """
244 """
245 b = repo.branchtags()
245 b = repo.branchtags()
246 l = [(-repo.changelog.rev(n), n, t) for t, n in b.items()]
246 l = [(-repo.changelog.rev(n), n, t) for t, n in b.items()]
247 l.sort()
247 l.sort()
248 for r, n, t in l:
248 for r, n, t in l:
249 hexfunc = ui.debugflag and hex or short
249 hexfunc = ui.debugflag and hex or short
250 if ui.quiet:
250 if ui.quiet:
251 ui.write("%s\n" % t)
251 ui.write("%s\n" % t)
252 else:
252 else:
253 spaces = " " * (30 - util.locallen(t))
253 spaces = " " * (30 - util.locallen(t))
254 ui.write("%s%s %s:%s\n" % (t, spaces, -r, hexfunc(n)))
254 ui.write("%s%s %s:%s\n" % (t, spaces, -r, hexfunc(n)))
255
255
256 def bundle(ui, repo, fname, dest=None, **opts):
256 def bundle(ui, repo, fname, dest=None, **opts):
257 """create a changegroup file
257 """create a changegroup file
258
258
259 Generate a compressed changegroup file collecting changesets not
259 Generate a compressed changegroup file collecting changesets not
260 found in the other repository.
260 found in the other repository.
261
261
262 If no destination repository is specified the destination is assumed
262 If no destination repository is specified the destination is assumed
263 to have all the nodes specified by one or more --base parameters.
263 to have all the nodes specified by one or more --base parameters.
264
264
265 The bundle file can then be transferred using conventional means and
265 The bundle file can then be transferred using conventional means and
266 applied to another repository with the unbundle or pull command.
266 applied to another repository with the unbundle or pull command.
267 This is useful when direct push and pull are not available or when
267 This is useful when direct push and pull are not available or when
268 exporting an entire repository is undesirable.
268 exporting an entire repository is undesirable.
269
269
270 Applying bundles preserves all changeset contents including
270 Applying bundles preserves all changeset contents including
271 permissions, copy/rename information, and revision history.
271 permissions, copy/rename information, and revision history.
272 """
272 """
273 revs = opts.get('rev') or None
273 revs = opts.get('rev') or None
274 if revs:
274 if revs:
275 revs = [repo.lookup(rev) for rev in revs]
275 revs = [repo.lookup(rev) for rev in revs]
276 base = opts.get('base')
276 base = opts.get('base')
277 if base:
277 if base:
278 if dest:
278 if dest:
279 raise util.Abort(_("--base is incompatible with specifiying "
279 raise util.Abort(_("--base is incompatible with specifiying "
280 "a destination"))
280 "a destination"))
281 base = [repo.lookup(rev) for rev in base]
281 base = [repo.lookup(rev) for rev in base]
282 # create the right base
282 # create the right base
283 # XXX: nodesbetween / changegroup* should be "fixed" instead
283 # XXX: nodesbetween / changegroup* should be "fixed" instead
284 o = []
284 o = []
285 has = {nullid: None}
285 has = {nullid: None}
286 for n in base:
286 for n in base:
287 has.update(repo.changelog.reachable(n))
287 has.update(repo.changelog.reachable(n))
288 if revs:
288 if revs:
289 visit = list(revs)
289 visit = list(revs)
290 else:
290 else:
291 visit = repo.changelog.heads()
291 visit = repo.changelog.heads()
292 seen = {}
292 seen = {}
293 while visit:
293 while visit:
294 n = visit.pop(0)
294 n = visit.pop(0)
295 parents = [p for p in repo.changelog.parents(n) if p not in has]
295 parents = [p for p in repo.changelog.parents(n) if p not in has]
296 if len(parents) == 0:
296 if len(parents) == 0:
297 o.insert(0, n)
297 o.insert(0, n)
298 else:
298 else:
299 for p in parents:
299 for p in parents:
300 if p not in seen:
300 if p not in seen:
301 seen[p] = 1
301 seen[p] = 1
302 visit.append(p)
302 visit.append(p)
303 else:
303 else:
304 cmdutil.setremoteconfig(ui, opts)
304 cmdutil.setremoteconfig(ui, opts)
305 dest, revs = cmdutil.parseurl(
305 dest, revs = cmdutil.parseurl(
306 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
306 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
307 other = hg.repository(ui, dest)
307 other = hg.repository(ui, dest)
308 o = repo.findoutgoing(other, force=opts['force'])
308 o = repo.findoutgoing(other, force=opts['force'])
309
309
310 if revs:
310 if revs:
311 cg = repo.changegroupsubset(o, revs, 'bundle')
311 cg = repo.changegroupsubset(o, revs, 'bundle')
312 else:
312 else:
313 cg = repo.changegroup(o, 'bundle')
313 cg = repo.changegroup(o, 'bundle')
314 changegroup.writebundle(cg, fname, "HG10BZ")
314 changegroup.writebundle(cg, fname, "HG10BZ")
315
315
316 def cat(ui, repo, file1, *pats, **opts):
316 def cat(ui, repo, file1, *pats, **opts):
317 """output the current or given revision of files
317 """output the current or given revision of files
318
318
319 Print the specified files as they were at the given revision.
319 Print the specified files as they were at the given revision.
320 If no revision is given, the parent of the working directory is used,
320 If no revision is given, the parent of the working directory is used,
321 or tip if no revision is checked out.
321 or tip if no revision is checked out.
322
322
323 Output may be to a file, in which case the name of the file is
323 Output may be to a file, in which case the name of the file is
324 given using a format string. The formatting rules are the same as
324 given using a format string. The formatting rules are the same as
325 for the export command, with the following additions:
325 for the export command, with the following additions:
326
326
327 %s basename of file being printed
327 %s basename of file being printed
328 %d dirname of file being printed, or '.' if in repo root
328 %d dirname of file being printed, or '.' if in repo root
329 %p root-relative path name of file being printed
329 %p root-relative path name of file being printed
330 """
330 """
331 ctx = repo.changectx(opts['rev'])
331 ctx = repo.changectx(opts['rev'])
332 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
332 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
333 ctx.node()):
333 ctx.node()):
334 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
334 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
335 fp.write(ctx.filectx(abs).data())
335 fp.write(ctx.filectx(abs).data())
336
336
337 def clone(ui, source, dest=None, **opts):
337 def clone(ui, source, dest=None, **opts):
338 """make a copy of an existing repository
338 """make a copy of an existing repository
339
339
340 Create a copy of an existing repository in a new directory.
340 Create a copy of an existing repository in a new directory.
341
341
342 If no destination directory name is specified, it defaults to the
342 If no destination directory name is specified, it defaults to the
343 basename of the source.
343 basename of the source.
344
344
345 The location of the source is added to the new repository's
345 The location of the source is added to the new repository's
346 .hg/hgrc file, as the default to be used for future pulls.
346 .hg/hgrc file, as the default to be used for future pulls.
347
347
348 For efficiency, hardlinks are used for cloning whenever the source
348 For efficiency, hardlinks are used for cloning whenever the source
349 and destination are on the same filesystem (note this applies only
349 and destination are on the same filesystem (note this applies only
350 to the repository data, not to the checked out files). Some
350 to the repository data, not to the checked out files). Some
351 filesystems, such as AFS, implement hardlinking incorrectly, but
351 filesystems, such as AFS, implement hardlinking incorrectly, but
352 do not report errors. In these cases, use the --pull option to
352 do not report errors. In these cases, use the --pull option to
353 avoid hardlinking.
353 avoid hardlinking.
354
354
355 You can safely clone repositories and checked out files using full
355 You can safely clone repositories and checked out files using full
356 hardlinks with
356 hardlinks with
357
357
358 $ cp -al REPO REPOCLONE
358 $ cp -al REPO REPOCLONE
359
359
360 which is the fastest way to clone. However, the operation is not
360 which is the fastest way to clone. However, the operation is not
361 atomic (making sure REPO is not modified during the operation is
361 atomic (making sure REPO is not modified during the operation is
362 up to you) and you have to make sure your editor breaks hardlinks
362 up to you) and you have to make sure your editor breaks hardlinks
363 (Emacs and most Linux Kernel tools do so).
363 (Emacs and most Linux Kernel tools do so).
364
364
365 If you use the -r option to clone up to a specific revision, no
365 If you use the -r option to clone up to a specific revision, no
366 subsequent revisions will be present in the cloned repository.
366 subsequent revisions will be present in the cloned repository.
367 This option implies --pull, even on local repositories.
367 This option implies --pull, even on local repositories.
368
368
369 See pull for valid source format details.
369 See pull for valid source format details.
370
370
371 It is possible to specify an ssh:// URL as the destination, but no
371 It is possible to specify an ssh:// URL as the destination, but no
372 .hg/hgrc and working directory will be created on the remote side.
372 .hg/hgrc and working directory will be created on the remote side.
373 Look at the help text for the pull command for important details
373 Look at the help text for the pull command for important details
374 about ssh:// URLs.
374 about ssh:// URLs.
375 """
375 """
376 cmdutil.setremoteconfig(ui, opts)
376 cmdutil.setremoteconfig(ui, opts)
377 hg.clone(ui, source, dest,
377 hg.clone(ui, source, dest,
378 pull=opts['pull'],
378 pull=opts['pull'],
379 stream=opts['uncompressed'],
379 stream=opts['uncompressed'],
380 rev=opts['rev'],
380 rev=opts['rev'],
381 update=not opts['noupdate'])
381 update=not opts['noupdate'])
382
382
383 def commit(ui, repo, *pats, **opts):
383 def commit(ui, repo, *pats, **opts):
384 """commit the specified files or all outstanding changes
384 """commit the specified files or all outstanding changes
385
385
386 Commit changes to the given files into the repository.
386 Commit changes to the given files into the repository.
387
387
388 If a list of files is omitted, all changes reported by "hg status"
388 If a list of files is omitted, all changes reported by "hg status"
389 will be committed.
389 will be committed.
390
390
391 If no commit message is specified, the editor configured in your hgrc
391 If no commit message is specified, the editor configured in your hgrc
392 or in the EDITOR environment variable is started to enter a message.
392 or in the EDITOR environment variable is started to enter a message.
393 """
393 """
394 message = cmdutil.logmessage(opts)
394 message = cmdutil.logmessage(opts)
395
395
396 if opts['addremove']:
396 if opts['addremove']:
397 cmdutil.addremove(repo, pats, opts)
397 cmdutil.addremove(repo, pats, opts)
398 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
398 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
399 if pats:
399 if pats:
400 status = repo.status(files=fns, match=match)
400 status = repo.status(files=fns, match=match)
401 modified, added, removed, deleted, unknown = status[:5]
401 modified, added, removed, deleted, unknown = status[:5]
402 files = modified + added + removed
402 files = modified + added + removed
403 slist = None
403 slist = None
404 for f in fns:
404 for f in fns:
405 if f == '.':
405 if f == '.':
406 continue
406 continue
407 if f not in files:
407 if f not in files:
408 rf = repo.wjoin(f)
408 rf = repo.wjoin(f)
409 try:
409 try:
410 mode = os.lstat(rf)[stat.ST_MODE]
410 mode = os.lstat(rf)[stat.ST_MODE]
411 except OSError:
411 except OSError:
412 raise util.Abort(_("file %s not found!") % rf)
412 raise util.Abort(_("file %s not found!") % rf)
413 if stat.S_ISDIR(mode):
413 if stat.S_ISDIR(mode):
414 name = f + '/'
414 name = f + '/'
415 if slist is None:
415 if slist is None:
416 slist = list(files)
416 slist = list(files)
417 slist.sort()
417 slist.sort()
418 i = bisect.bisect(slist, name)
418 i = bisect.bisect(slist, name)
419 if i >= len(slist) or not slist[i].startswith(name):
419 if i >= len(slist) or not slist[i].startswith(name):
420 raise util.Abort(_("no match under directory %s!")
420 raise util.Abort(_("no match under directory %s!")
421 % rf)
421 % rf)
422 elif not (stat.S_ISREG(mode) or stat.S_ISLNK(mode)):
422 elif not (stat.S_ISREG(mode) or stat.S_ISLNK(mode)):
423 raise util.Abort(_("can't commit %s: "
423 raise util.Abort(_("can't commit %s: "
424 "unsupported file type!") % rf)
424 "unsupported file type!") % rf)
425 elif repo.dirstate.state(f) == '?':
425 elif repo.dirstate.state(f) == '?':
426 raise util.Abort(_("file %s not tracked!") % rf)
426 raise util.Abort(_("file %s not tracked!") % rf)
427 else:
427 else:
428 files = []
428 files = []
429 try:
429 try:
430 repo.commit(files, message, opts['user'], opts['date'], match,
430 repo.commit(files, message, opts['user'], opts['date'], match,
431 force_editor=opts.get('force_editor'))
431 force_editor=opts.get('force_editor'))
432 except ValueError, inst:
432 except ValueError, inst:
433 raise util.Abort(str(inst))
433 raise util.Abort(str(inst))
434
434
435 def docopy(ui, repo, pats, opts, wlock):
435 def docopy(ui, repo, pats, opts, wlock):
436 # called with the repo lock held
436 # called with the repo lock held
437 #
437 #
438 # hgsep => pathname that uses "/" to separate directories
438 # hgsep => pathname that uses "/" to separate directories
439 # ossep => pathname that uses os.sep to separate directories
439 # ossep => pathname that uses os.sep to separate directories
440 cwd = repo.getcwd()
440 cwd = repo.getcwd()
441 errors = 0
441 errors = 0
442 copied = []
442 copied = []
443 targets = {}
443 targets = {}
444
444
445 # abs: hgsep
445 # abs: hgsep
446 # rel: ossep
446 # rel: ossep
447 # return: hgsep
447 # return: hgsep
448 def okaytocopy(abs, rel, exact):
448 def okaytocopy(abs, rel, exact):
449 reasons = {'?': _('is not managed'),
449 reasons = {'?': _('is not managed'),
450 'a': _('has been marked for add'),
450 'a': _('has been marked for add'),
451 'r': _('has been marked for remove')}
451 'r': _('has been marked for remove')}
452 state = repo.dirstate.state(abs)
452 state = repo.dirstate.state(abs)
453 reason = reasons.get(state)
453 reason = reasons.get(state)
454 if reason:
454 if reason:
455 if state == 'a':
455 if state == 'a':
456 origsrc = repo.dirstate.copied(abs)
456 origsrc = repo.dirstate.copied(abs)
457 if origsrc is not None:
457 if origsrc is not None:
458 return origsrc
458 return origsrc
459 if exact:
459 if exact:
460 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
460 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
461 else:
461 else:
462 return abs
462 return abs
463
463
464 # origsrc: hgsep
464 # origsrc: hgsep
465 # abssrc: hgsep
465 # abssrc: hgsep
466 # relsrc: ossep
466 # relsrc: ossep
467 # otarget: ossep
467 # otarget: ossep
468 def copy(origsrc, abssrc, relsrc, otarget, exact):
468 def copy(origsrc, abssrc, relsrc, otarget, exact):
469 abstarget = util.canonpath(repo.root, cwd, otarget)
469 abstarget = util.canonpath(repo.root, cwd, otarget)
470 reltarget = repo.pathto(abstarget, cwd)
470 reltarget = repo.pathto(abstarget, cwd)
471 prevsrc = targets.get(abstarget)
471 prevsrc = targets.get(abstarget)
472 src = repo.wjoin(abssrc)
472 src = repo.wjoin(abssrc)
473 target = repo.wjoin(abstarget)
473 target = repo.wjoin(abstarget)
474 if prevsrc is not None:
474 if prevsrc is not None:
475 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
475 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
476 (reltarget, repo.pathto(abssrc, cwd),
476 (reltarget, repo.pathto(abssrc, cwd),
477 repo.pathto(prevsrc, cwd)))
477 repo.pathto(prevsrc, cwd)))
478 return
478 return
479 if (not opts['after'] and os.path.exists(target) or
479 if (not opts['after'] and os.path.exists(target) or
480 opts['after'] and repo.dirstate.state(abstarget) not in '?ar'):
480 opts['after'] and repo.dirstate.state(abstarget) not in '?ar'):
481 if not opts['force']:
481 if not opts['force']:
482 ui.warn(_('%s: not overwriting - file exists\n') %
482 ui.warn(_('%s: not overwriting - file exists\n') %
483 reltarget)
483 reltarget)
484 return
484 return
485 if not opts['after'] and not opts.get('dry_run'):
485 if not opts['after'] and not opts.get('dry_run'):
486 os.unlink(target)
486 os.unlink(target)
487 if opts['after']:
487 if opts['after']:
488 if not os.path.exists(target):
488 if not os.path.exists(target):
489 return
489 return
490 else:
490 else:
491 targetdir = os.path.dirname(target) or '.'
491 targetdir = os.path.dirname(target) or '.'
492 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
492 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
493 os.makedirs(targetdir)
493 os.makedirs(targetdir)
494 try:
494 try:
495 restore = repo.dirstate.state(abstarget) == 'r'
495 restore = repo.dirstate.state(abstarget) == 'r'
496 if restore and not opts.get('dry_run'):
496 if restore and not opts.get('dry_run'):
497 repo.undelete([abstarget], wlock)
497 repo.undelete([abstarget], wlock)
498 try:
498 try:
499 if not opts.get('dry_run'):
499 if not opts.get('dry_run'):
500 util.copyfile(src, target)
500 util.copyfile(src, target)
501 restore = False
501 restore = False
502 finally:
502 finally:
503 if restore:
503 if restore:
504 repo.remove([abstarget], wlock=wlock)
504 repo.remove([abstarget], wlock=wlock)
505 except IOError, inst:
505 except IOError, inst:
506 if inst.errno == errno.ENOENT:
506 if inst.errno == errno.ENOENT:
507 ui.warn(_('%s: deleted in working copy\n') % relsrc)
507 ui.warn(_('%s: deleted in working copy\n') % relsrc)
508 else:
508 else:
509 ui.warn(_('%s: cannot copy - %s\n') %
509 ui.warn(_('%s: cannot copy - %s\n') %
510 (relsrc, inst.strerror))
510 (relsrc, inst.strerror))
511 errors += 1
511 errors += 1
512 return
512 return
513 if ui.verbose or not exact:
513 if ui.verbose or not exact:
514 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
514 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
515 targets[abstarget] = abssrc
515 targets[abstarget] = abssrc
516 if abstarget != origsrc and not opts.get('dry_run'):
516 if abstarget != origsrc and not opts.get('dry_run'):
517 repo.copy(origsrc, abstarget, wlock)
517 repo.copy(origsrc, abstarget, wlock)
518 copied.append((abssrc, relsrc, exact))
518 copied.append((abssrc, relsrc, exact))
519
519
520 # pat: ossep
520 # pat: ossep
521 # dest ossep
521 # dest ossep
522 # srcs: list of (hgsep, hgsep, ossep, bool)
522 # srcs: list of (hgsep, hgsep, ossep, bool)
523 # return: function that takes hgsep and returns ossep
523 # return: function that takes hgsep and returns ossep
524 def targetpathfn(pat, dest, srcs):
524 def targetpathfn(pat, dest, srcs):
525 if os.path.isdir(pat):
525 if os.path.isdir(pat):
526 abspfx = util.canonpath(repo.root, cwd, pat)
526 abspfx = util.canonpath(repo.root, cwd, pat)
527 abspfx = util.localpath(abspfx)
527 abspfx = util.localpath(abspfx)
528 if destdirexists:
528 if destdirexists:
529 striplen = len(os.path.split(abspfx)[0])
529 striplen = len(os.path.split(abspfx)[0])
530 else:
530 else:
531 striplen = len(abspfx)
531 striplen = len(abspfx)
532 if striplen:
532 if striplen:
533 striplen += len(os.sep)
533 striplen += len(os.sep)
534 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
534 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
535 elif destdirexists:
535 elif destdirexists:
536 res = lambda p: os.path.join(dest,
536 res = lambda p: os.path.join(dest,
537 os.path.basename(util.localpath(p)))
537 os.path.basename(util.localpath(p)))
538 else:
538 else:
539 res = lambda p: dest
539 res = lambda p: dest
540 return res
540 return res
541
541
542 # pat: ossep
542 # pat: ossep
543 # dest ossep
543 # dest ossep
544 # srcs: list of (hgsep, hgsep, ossep, bool)
544 # srcs: list of (hgsep, hgsep, ossep, bool)
545 # return: function that takes hgsep and returns ossep
545 # return: function that takes hgsep and returns ossep
546 def targetpathafterfn(pat, dest, srcs):
546 def targetpathafterfn(pat, dest, srcs):
547 if util.patkind(pat, None)[0]:
547 if util.patkind(pat, None)[0]:
548 # a mercurial pattern
548 # a mercurial pattern
549 res = lambda p: os.path.join(dest,
549 res = lambda p: os.path.join(dest,
550 os.path.basename(util.localpath(p)))
550 os.path.basename(util.localpath(p)))
551 else:
551 else:
552 abspfx = util.canonpath(repo.root, cwd, pat)
552 abspfx = util.canonpath(repo.root, cwd, pat)
553 if len(abspfx) < len(srcs[0][0]):
553 if len(abspfx) < len(srcs[0][0]):
554 # A directory. Either the target path contains the last
554 # A directory. Either the target path contains the last
555 # component of the source path or it does not.
555 # component of the source path or it does not.
556 def evalpath(striplen):
556 def evalpath(striplen):
557 score = 0
557 score = 0
558 for s in srcs:
558 for s in srcs:
559 t = os.path.join(dest, util.localpath(s[0])[striplen:])
559 t = os.path.join(dest, util.localpath(s[0])[striplen:])
560 if os.path.exists(t):
560 if os.path.exists(t):
561 score += 1
561 score += 1
562 return score
562 return score
563
563
564 abspfx = util.localpath(abspfx)
564 abspfx = util.localpath(abspfx)
565 striplen = len(abspfx)
565 striplen = len(abspfx)
566 if striplen:
566 if striplen:
567 striplen += len(os.sep)
567 striplen += len(os.sep)
568 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
568 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
569 score = evalpath(striplen)
569 score = evalpath(striplen)
570 striplen1 = len(os.path.split(abspfx)[0])
570 striplen1 = len(os.path.split(abspfx)[0])
571 if striplen1:
571 if striplen1:
572 striplen1 += len(os.sep)
572 striplen1 += len(os.sep)
573 if evalpath(striplen1) > score:
573 if evalpath(striplen1) > score:
574 striplen = striplen1
574 striplen = striplen1
575 res = lambda p: os.path.join(dest,
575 res = lambda p: os.path.join(dest,
576 util.localpath(p)[striplen:])
576 util.localpath(p)[striplen:])
577 else:
577 else:
578 # a file
578 # a file
579 if destdirexists:
579 if destdirexists:
580 res = lambda p: os.path.join(dest,
580 res = lambda p: os.path.join(dest,
581 os.path.basename(util.localpath(p)))
581 os.path.basename(util.localpath(p)))
582 else:
582 else:
583 res = lambda p: dest
583 res = lambda p: dest
584 return res
584 return res
585
585
586
586
587 pats = util.expand_glob(pats)
587 pats = util.expand_glob(pats)
588 if not pats:
588 if not pats:
589 raise util.Abort(_('no source or destination specified'))
589 raise util.Abort(_('no source or destination specified'))
590 if len(pats) == 1:
590 if len(pats) == 1:
591 raise util.Abort(_('no destination specified'))
591 raise util.Abort(_('no destination specified'))
592 dest = pats.pop()
592 dest = pats.pop()
593 destdirexists = os.path.isdir(dest)
593 destdirexists = os.path.isdir(dest)
594 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
594 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
595 raise util.Abort(_('with multiple sources, destination must be an '
595 raise util.Abort(_('with multiple sources, destination must be an '
596 'existing directory'))
596 'existing directory'))
597 if opts['after']:
597 if opts['after']:
598 tfn = targetpathafterfn
598 tfn = targetpathafterfn
599 else:
599 else:
600 tfn = targetpathfn
600 tfn = targetpathfn
601 copylist = []
601 copylist = []
602 for pat in pats:
602 for pat in pats:
603 srcs = []
603 srcs = []
604 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts,
604 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts,
605 globbed=True):
605 globbed=True):
606 origsrc = okaytocopy(abssrc, relsrc, exact)
606 origsrc = okaytocopy(abssrc, relsrc, exact)
607 if origsrc:
607 if origsrc:
608 srcs.append((origsrc, abssrc, relsrc, exact))
608 srcs.append((origsrc, abssrc, relsrc, exact))
609 if not srcs:
609 if not srcs:
610 continue
610 continue
611 copylist.append((tfn(pat, dest, srcs), srcs))
611 copylist.append((tfn(pat, dest, srcs), srcs))
612 if not copylist:
612 if not copylist:
613 raise util.Abort(_('no files to copy'))
613 raise util.Abort(_('no files to copy'))
614
614
615 for targetpath, srcs in copylist:
615 for targetpath, srcs in copylist:
616 for origsrc, abssrc, relsrc, exact in srcs:
616 for origsrc, abssrc, relsrc, exact in srcs:
617 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
617 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
618
618
619 if errors:
619 if errors:
620 ui.warn(_('(consider using --after)\n'))
620 ui.warn(_('(consider using --after)\n'))
621 return errors, copied
621 return errors, copied
622
622
623 def copy(ui, repo, *pats, **opts):
623 def copy(ui, repo, *pats, **opts):
624 """mark files as copied for the next commit
624 """mark files as copied for the next commit
625
625
626 Mark dest as having copies of source files. If dest is a
626 Mark dest as having copies of source files. If dest is a
627 directory, copies are put in that directory. If dest is a file,
627 directory, copies are put in that directory. If dest is a file,
628 there can only be one source.
628 there can only be one source.
629
629
630 By default, this command copies the contents of files as they
630 By default, this command copies the contents of files as they
631 stand in the working directory. If invoked with --after, the
631 stand in the working directory. If invoked with --after, the
632 operation is recorded, but no copying is performed.
632 operation is recorded, but no copying is performed.
633
633
634 This command takes effect in the next commit. To undo a copy
634 This command takes effect in the next commit. To undo a copy
635 before that, see hg revert.
635 before that, see hg revert.
636 """
636 """
637 wlock = repo.wlock(0)
637 wlock = repo.wlock(0)
638 errs, copied = docopy(ui, repo, pats, opts, wlock)
638 errs, copied = docopy(ui, repo, pats, opts, wlock)
639 return errs
639 return errs
640
640
641 def debugancestor(ui, index, rev1, rev2):
641 def debugancestor(ui, index, rev1, rev2):
642 """find the ancestor revision of two revisions in a given index"""
642 """find the ancestor revision of two revisions in a given index"""
643 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
643 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
644 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
644 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
645 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
645 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
646
646
647 def debugcomplete(ui, cmd='', **opts):
647 def debugcomplete(ui, cmd='', **opts):
648 """returns the completion list associated with the given command"""
648 """returns the completion list associated with the given command"""
649
649
650 if opts['options']:
650 if opts['options']:
651 options = []
651 options = []
652 otables = [globalopts]
652 otables = [globalopts]
653 if cmd:
653 if cmd:
654 aliases, entry = cmdutil.findcmd(ui, cmd)
654 aliases, entry = cmdutil.findcmd(ui, cmd)
655 otables.append(entry[1])
655 otables.append(entry[1])
656 for t in otables:
656 for t in otables:
657 for o in t:
657 for o in t:
658 if o[0]:
658 if o[0]:
659 options.append('-%s' % o[0])
659 options.append('-%s' % o[0])
660 options.append('--%s' % o[1])
660 options.append('--%s' % o[1])
661 ui.write("%s\n" % "\n".join(options))
661 ui.write("%s\n" % "\n".join(options))
662 return
662 return
663
663
664 clist = cmdutil.findpossible(ui, cmd).keys()
664 clist = cmdutil.findpossible(ui, cmd).keys()
665 clist.sort()
665 clist.sort()
666 ui.write("%s\n" % "\n".join(clist))
666 ui.write("%s\n" % "\n".join(clist))
667
667
668 def debugrebuildstate(ui, repo, rev=""):
668 def debugrebuildstate(ui, repo, rev=""):
669 """rebuild the dirstate as it would look like for the given revision"""
669 """rebuild the dirstate as it would look like for the given revision"""
670 if rev == "":
670 if rev == "":
671 rev = repo.changelog.tip()
671 rev = repo.changelog.tip()
672 ctx = repo.changectx(rev)
672 ctx = repo.changectx(rev)
673 files = ctx.manifest()
673 files = ctx.manifest()
674 wlock = repo.wlock()
674 wlock = repo.wlock()
675 repo.dirstate.rebuild(rev, files)
675 repo.dirstate.rebuild(rev, files)
676
676
677 def debugcheckstate(ui, repo):
677 def debugcheckstate(ui, repo):
678 """validate the correctness of the current dirstate"""
678 """validate the correctness of the current dirstate"""
679 parent1, parent2 = repo.dirstate.parents()
679 parent1, parent2 = repo.dirstate.parents()
680 dc = repo.dirstate
680 dc = repo.dirstate
681 m1 = repo.changectx(parent1).manifest()
681 m1 = repo.changectx(parent1).manifest()
682 m2 = repo.changectx(parent2).manifest()
682 m2 = repo.changectx(parent2).manifest()
683 errors = 0
683 errors = 0
684 for f in dc:
684 for f in dc:
685 state = repo.dirstate.state(f)
685 state = repo.dirstate.state(f)
686 if state in "nr" and f not in m1:
686 if state in "nr" and f not in m1:
687 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
687 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
688 errors += 1
688 errors += 1
689 if state in "a" and f in m1:
689 if state in "a" and f in m1:
690 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
690 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
691 errors += 1
691 errors += 1
692 if state in "m" and f not in m1 and f not in m2:
692 if state in "m" and f not in m1 and f not in m2:
693 ui.warn(_("%s in state %s, but not in either manifest\n") %
693 ui.warn(_("%s in state %s, but not in either manifest\n") %
694 (f, state))
694 (f, state))
695 errors += 1
695 errors += 1
696 for f in m1:
696 for f in m1:
697 state = repo.dirstate.state(f)
697 state = repo.dirstate.state(f)
698 if state not in "nrm":
698 if state not in "nrm":
699 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
699 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
700 errors += 1
700 errors += 1
701 if errors:
701 if errors:
702 error = _(".hg/dirstate inconsistent with current parent's manifest")
702 error = _(".hg/dirstate inconsistent with current parent's manifest")
703 raise util.Abort(error)
703 raise util.Abort(error)
704
704
705 def showconfig(ui, repo, *values, **opts):
705 def showconfig(ui, repo, *values, **opts):
706 """show combined config settings from all hgrc files
706 """show combined config settings from all hgrc files
707
707
708 With no args, print names and values of all config items.
708 With no args, print names and values of all config items.
709
709
710 With one arg of the form section.name, print just the value of
710 With one arg of the form section.name, print just the value of
711 that config item.
711 that config item.
712
712
713 With multiple args, print names and values of all config items
713 With multiple args, print names and values of all config items
714 with matching section names."""
714 with matching section names."""
715
715
716 untrusted = bool(opts.get('untrusted'))
716 untrusted = bool(opts.get('untrusted'))
717 if values:
717 if values:
718 if len([v for v in values if '.' in v]) > 1:
718 if len([v for v in values if '.' in v]) > 1:
719 raise util.Abort(_('only one config item permitted'))
719 raise util.Abort(_('only one config item permitted'))
720 for section, name, value in ui.walkconfig(untrusted=untrusted):
720 for section, name, value in ui.walkconfig(untrusted=untrusted):
721 sectname = section + '.' + name
721 sectname = section + '.' + name
722 if values:
722 if values:
723 for v in values:
723 for v in values:
724 if v == section:
724 if v == section:
725 ui.write('%s=%s\n' % (sectname, value))
725 ui.write('%s=%s\n' % (sectname, value))
726 elif v == sectname:
726 elif v == sectname:
727 ui.write(value, '\n')
727 ui.write(value, '\n')
728 else:
728 else:
729 ui.write('%s=%s\n' % (sectname, value))
729 ui.write('%s=%s\n' % (sectname, value))
730
730
731 def debugsetparents(ui, repo, rev1, rev2=None):
731 def debugsetparents(ui, repo, rev1, rev2=None):
732 """manually set the parents of the current working directory
732 """manually set the parents of the current working directory
733
733
734 This is useful for writing repository conversion tools, but should
734 This is useful for writing repository conversion tools, but should
735 be used with care.
735 be used with care.
736 """
736 """
737
737
738 if not rev2:
738 if not rev2:
739 rev2 = hex(nullid)
739 rev2 = hex(nullid)
740
740
741 wlock = repo.wlock()
741 wlock = repo.wlock()
742 try:
742 try:
743 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
743 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
744 finally:
744 finally:
745 wlock.release()
745 wlock.release()
746
746
747 def debugstate(ui, repo):
747 def debugstate(ui, repo):
748 """show the contents of the current dirstate"""
748 """show the contents of the current dirstate"""
749 dc = repo.dirstate
749 dc = repo.dirstate
750 for file_ in dc:
750 for file_ in dc:
751 if dc[file_][3] == -1:
751 if dc[file_][3] == -1:
752 # Pad or slice to locale representation
752 # Pad or slice to locale representation
753 locale_len = len(time.strftime("%x %X", time.localtime(0)))
753 locale_len = len(time.strftime("%x %X", time.localtime(0)))
754 timestr = 'unset'
754 timestr = 'unset'
755 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
755 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
756 else:
756 else:
757 timestr = time.strftime("%x %X", time.localtime(dc[file_][3]))
757 timestr = time.strftime("%x %X", time.localtime(dc[file_][3]))
758 ui.write("%c %3o %10d %s %s\n"
758 ui.write("%c %3o %10d %s %s\n"
759 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
759 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
760 timestr, file_))
760 timestr, file_))
761 for f in repo.dirstate.copies():
761 for f in repo.dirstate.copies():
762 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
762 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
763
763
764 def debugdata(ui, file_, rev):
764 def debugdata(ui, file_, rev):
765 """dump the contents of a data file revision"""
765 """dump the contents of a data file revision"""
766 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
766 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
767 try:
767 try:
768 ui.write(r.revision(r.lookup(rev)))
768 ui.write(r.revision(r.lookup(rev)))
769 except KeyError:
769 except KeyError:
770 raise util.Abort(_('invalid revision identifier %s') % rev)
770 raise util.Abort(_('invalid revision identifier %s') % rev)
771
771
772 def debugdate(ui, date, range=None, **opts):
772 def debugdate(ui, date, range=None, **opts):
773 """parse and display a date"""
773 """parse and display a date"""
774 if opts["extended"]:
774 if opts["extended"]:
775 d = util.parsedate(date, util.extendeddateformats)
775 d = util.parsedate(date, util.extendeddateformats)
776 else:
776 else:
777 d = util.parsedate(date)
777 d = util.parsedate(date)
778 ui.write("internal: %s %s\n" % d)
778 ui.write("internal: %s %s\n" % d)
779 ui.write("standard: %s\n" % util.datestr(d))
779 ui.write("standard: %s\n" % util.datestr(d))
780 if range:
780 if range:
781 m = util.matchdate(range)
781 m = util.matchdate(range)
782 ui.write("match: %s\n" % m(d[0]))
782 ui.write("match: %s\n" % m(d[0]))
783
783
784 def debugindex(ui, file_):
784 def debugindex(ui, file_):
785 """dump the contents of an index file"""
785 """dump the contents of an index file"""
786 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
786 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
787 ui.write(" rev offset length base linkrev" +
787 ui.write(" rev offset length base linkrev" +
788 " nodeid p1 p2\n")
788 " nodeid p1 p2\n")
789 for i in xrange(r.count()):
789 for i in xrange(r.count()):
790 node = r.node(i)
790 node = r.node(i)
791 pp = r.parents(node)
791 pp = r.parents(node)
792 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
792 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
793 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
793 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
794 short(node), short(pp[0]), short(pp[1])))
794 short(node), short(pp[0]), short(pp[1])))
795
795
796 def debugindexdot(ui, file_):
796 def debugindexdot(ui, file_):
797 """dump an index DAG as a .dot file"""
797 """dump an index DAG as a .dot file"""
798 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
798 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
799 ui.write("digraph G {\n")
799 ui.write("digraph G {\n")
800 for i in xrange(r.count()):
800 for i in xrange(r.count()):
801 node = r.node(i)
801 node = r.node(i)
802 pp = r.parents(node)
802 pp = r.parents(node)
803 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
803 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
804 if pp[1] != nullid:
804 if pp[1] != nullid:
805 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
805 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
806 ui.write("}\n")
806 ui.write("}\n")
807
807
808 def debuginstall(ui):
808 def debuginstall(ui):
809 '''test Mercurial installation'''
809 '''test Mercurial installation'''
810
810
811 def writetemp(contents):
811 def writetemp(contents):
812 (fd, name) = tempfile.mkstemp()
812 (fd, name) = tempfile.mkstemp()
813 f = os.fdopen(fd, "wb")
813 f = os.fdopen(fd, "wb")
814 f.write(contents)
814 f.write(contents)
815 f.close()
815 f.close()
816 return name
816 return name
817
817
818 problems = 0
818 problems = 0
819
819
820 # encoding
820 # encoding
821 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
821 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
822 try:
822 try:
823 util.fromlocal("test")
823 util.fromlocal("test")
824 except util.Abort, inst:
824 except util.Abort, inst:
825 ui.write(" %s\n" % inst)
825 ui.write(" %s\n" % inst)
826 ui.write(_(" (check that your locale is properly set)\n"))
826 ui.write(_(" (check that your locale is properly set)\n"))
827 problems += 1
827 problems += 1
828
828
829 # compiled modules
829 # compiled modules
830 ui.status(_("Checking extensions...\n"))
830 ui.status(_("Checking extensions...\n"))
831 try:
831 try:
832 import bdiff, mpatch, base85
832 import bdiff, mpatch, base85
833 except Exception, inst:
833 except Exception, inst:
834 ui.write(" %s\n" % inst)
834 ui.write(" %s\n" % inst)
835 ui.write(_(" One or more extensions could not be found"))
835 ui.write(_(" One or more extensions could not be found"))
836 ui.write(_(" (check that you compiled the extensions)\n"))
836 ui.write(_(" (check that you compiled the extensions)\n"))
837 problems += 1
837 problems += 1
838
838
839 # templates
839 # templates
840 ui.status(_("Checking templates...\n"))
840 ui.status(_("Checking templates...\n"))
841 try:
841 try:
842 import templater
842 import templater
843 t = templater.templater(templater.templatepath("map-cmdline.default"))
843 t = templater.templater(templater.templatepath("map-cmdline.default"))
844 except Exception, inst:
844 except Exception, inst:
845 ui.write(" %s\n" % inst)
845 ui.write(" %s\n" % inst)
846 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
846 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
847 problems += 1
847 problems += 1
848
848
849 # patch
849 # patch
850 ui.status(_("Checking patch...\n"))
850 ui.status(_("Checking patch...\n"))
851 patcher = ui.config('ui', 'patch')
851 patcher = ui.config('ui', 'patch')
852 patcher = ((patcher and util.find_exe(patcher)) or
852 patcher = ((patcher and util.find_exe(patcher)) or
853 util.find_exe('gpatch') or
853 util.find_exe('gpatch') or
854 util.find_exe('patch'))
854 util.find_exe('patch'))
855 if not patcher:
855 if not patcher:
856 ui.write(_(" Can't find patch or gpatch in PATH\n"))
856 ui.write(_(" Can't find patch or gpatch in PATH\n"))
857 ui.write(_(" (specify a patch utility in your .hgrc file)\n"))
857 ui.write(_(" (specify a patch utility in your .hgrc file)\n"))
858 problems += 1
858 problems += 1
859 else:
859 else:
860 # actually attempt a patch here
860 # actually attempt a patch here
861 a = "1\n2\n3\n4\n"
861 a = "1\n2\n3\n4\n"
862 b = "1\n2\n3\ninsert\n4\n"
862 b = "1\n2\n3\ninsert\n4\n"
863 fa = writetemp(a)
863 fa = writetemp(a)
864 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa))
864 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa))
865 fd = writetemp(d)
865 fd = writetemp(d)
866
866
867 files = {}
867 files = {}
868 try:
868 try:
869 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
869 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
870 except util.Abort, e:
870 except util.Abort, e:
871 ui.write(_(" patch call failed:\n"))
871 ui.write(_(" patch call failed:\n"))
872 ui.write(" " + str(e) + "\n")
872 ui.write(" " + str(e) + "\n")
873 problems += 1
873 problems += 1
874 else:
874 else:
875 if list(files) != [os.path.basename(fa)]:
875 if list(files) != [os.path.basename(fa)]:
876 ui.write(_(" unexpected patch output!"))
876 ui.write(_(" unexpected patch output!"))
877 ui.write(_(" (you may have an incompatible version of patch)\n"))
877 ui.write(_(" (you may have an incompatible version of patch)\n"))
878 problems += 1
878 problems += 1
879 a = file(fa).read()
879 a = file(fa).read()
880 if a != b:
880 if a != b:
881 ui.write(_(" patch test failed!"))
881 ui.write(_(" patch test failed!"))
882 ui.write(_(" (you may have an incompatible version of patch)\n"))
882 ui.write(_(" (you may have an incompatible version of patch)\n"))
883 problems += 1
883 problems += 1
884
884
885 os.unlink(fa)
885 os.unlink(fa)
886 os.unlink(fd)
886 os.unlink(fd)
887
887
888 # merge helper
888 # merge helper
889 ui.status(_("Checking merge helper...\n"))
889 ui.status(_("Checking merge helper...\n"))
890 cmd = (os.environ.get("HGMERGE") or ui.config("ui", "merge")
890 cmd = (os.environ.get("HGMERGE") or ui.config("ui", "merge")
891 or "hgmerge")
891 or "hgmerge")
892 cmdpath = util.find_exe(cmd) or util.find_exe(cmd.split()[0])
892 cmdpath = util.find_exe(cmd) or util.find_exe(cmd.split()[0])
893 if not cmdpath:
893 if not cmdpath:
894 if cmd == 'hgmerge':
894 if cmd == 'hgmerge':
895 ui.write(_(" No merge helper set and can't find default"
895 ui.write(_(" No merge helper set and can't find default"
896 " hgmerge script in PATH\n"))
896 " hgmerge script in PATH\n"))
897 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
897 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
898 else:
898 else:
899 ui.write(_(" Can't find merge helper '%s' in PATH\n") % cmd)
899 ui.write(_(" Can't find merge helper '%s' in PATH\n") % cmd)
900 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
900 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
901 problems += 1
901 problems += 1
902 else:
902 else:
903 # actually attempt a patch here
903 # actually attempt a patch here
904 fa = writetemp("1\n2\n3\n4\n")
904 fa = writetemp("1\n2\n3\n4\n")
905 fl = writetemp("1\n2\n3\ninsert\n4\n")
905 fl = writetemp("1\n2\n3\ninsert\n4\n")
906 fr = writetemp("begin\n1\n2\n3\n4\n")
906 fr = writetemp("begin\n1\n2\n3\n4\n")
907 r = os.system('%s %s %s %s' % (cmd, fl, fa, fr))
907 r = os.system('%s %s %s %s' % (cmd, fl, fa, fr))
908 if r:
908 if r:
909 ui.write(_(" got unexpected merge error %d!") % r)
909 ui.write(_(" got unexpected merge error %d!") % r)
910 problems += 1
910 problems += 1
911 m = file(fl).read()
911 m = file(fl).read()
912 if m != "begin\n1\n2\n3\ninsert\n4\n":
912 if m != "begin\n1\n2\n3\ninsert\n4\n":
913 ui.write(_(" got unexpected merge results!") % r)
913 ui.write(_(" got unexpected merge results!") % r)
914 ui.write(_(" (your merge helper may have the"
914 ui.write(_(" (your merge helper may have the"
915 " wrong argument order)\n"))
915 " wrong argument order)\n"))
916 ui.write(m)
916 ui.write(m)
917 os.unlink(fa)
917 os.unlink(fa)
918 os.unlink(fl)
918 os.unlink(fl)
919 os.unlink(fr)
919 os.unlink(fr)
920
920
921 # editor
921 # editor
922 ui.status(_("Checking commit editor...\n"))
922 ui.status(_("Checking commit editor...\n"))
923 editor = (os.environ.get("HGEDITOR") or
923 editor = (os.environ.get("HGEDITOR") or
924 ui.config("ui", "editor") or
924 ui.config("ui", "editor") or
925 os.environ.get("EDITOR", "vi"))
925 os.environ.get("EDITOR", "vi"))
926 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
926 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
927 if not cmdpath:
927 if not cmdpath:
928 if editor == 'vi':
928 if editor == 'vi':
929 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
929 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
930 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
930 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
931 else:
931 else:
932 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
932 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
933 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
933 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
934 problems += 1
934 problems += 1
935
935
936 # check username
936 # check username
937 ui.status(_("Checking username...\n"))
937 ui.status(_("Checking username...\n"))
938 user = os.environ.get("HGUSER")
938 user = os.environ.get("HGUSER")
939 if user is None:
939 if user is None:
940 user = ui.config("ui", "username")
940 user = ui.config("ui", "username")
941 if user is None:
941 if user is None:
942 user = os.environ.get("EMAIL")
942 user = os.environ.get("EMAIL")
943 if not user:
943 if not user:
944 ui.warn(" ")
944 ui.warn(" ")
945 ui.username()
945 ui.username()
946 ui.write(_(" (specify a username in your .hgrc file)\n"))
946 ui.write(_(" (specify a username in your .hgrc file)\n"))
947
947
948 if not problems:
948 if not problems:
949 ui.status(_("No problems detected\n"))
949 ui.status(_("No problems detected\n"))
950 else:
950 else:
951 ui.write(_("%s problems detected,"
951 ui.write(_("%s problems detected,"
952 " please check your install!\n") % problems)
952 " please check your install!\n") % problems)
953
953
954 return problems
954 return problems
955
955
956 def debugrename(ui, repo, file1, *pats, **opts):
956 def debugrename(ui, repo, file1, *pats, **opts):
957 """dump rename information"""
957 """dump rename information"""
958
958
959 ctx = repo.changectx(opts.get('rev', 'tip'))
959 ctx = repo.changectx(opts.get('rev', 'tip'))
960 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
960 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
961 ctx.node()):
961 ctx.node()):
962 m = ctx.filectx(abs).renamed()
962 m = ctx.filectx(abs).renamed()
963 if m:
963 if m:
964 ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1])))
964 ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1])))
965 else:
965 else:
966 ui.write(_("%s not renamed\n") % rel)
966 ui.write(_("%s not renamed\n") % rel)
967
967
968 def debugwalk(ui, repo, *pats, **opts):
968 def debugwalk(ui, repo, *pats, **opts):
969 """show how files match on given patterns"""
969 """show how files match on given patterns"""
970 items = list(cmdutil.walk(repo, pats, opts))
970 items = list(cmdutil.walk(repo, pats, opts))
971 if not items:
971 if not items:
972 return
972 return
973 fmt = '%%s %%-%ds %%-%ds %%s' % (
973 fmt = '%%s %%-%ds %%-%ds %%s' % (
974 max([len(abs) for (src, abs, rel, exact) in items]),
974 max([len(abs) for (src, abs, rel, exact) in items]),
975 max([len(rel) for (src, abs, rel, exact) in items]))
975 max([len(rel) for (src, abs, rel, exact) in items]))
976 for src, abs, rel, exact in items:
976 for src, abs, rel, exact in items:
977 line = fmt % (src, abs, rel, exact and 'exact' or '')
977 line = fmt % (src, abs, rel, exact and 'exact' or '')
978 ui.write("%s\n" % line.rstrip())
978 ui.write("%s\n" % line.rstrip())
979
979
980 def diff(ui, repo, *pats, **opts):
980 def diff(ui, repo, *pats, **opts):
981 """diff repository (or selected files)
981 """diff repository (or selected files)
982
982
983 Show differences between revisions for the specified files.
983 Show differences between revisions for the specified files.
984
984
985 Differences between files are shown using the unified diff format.
985 Differences between files are shown using the unified diff format.
986
986
987 NOTE: diff may generate unexpected results for merges, as it will
987 NOTE: diff may generate unexpected results for merges, as it will
988 default to comparing against the working directory's first parent
988 default to comparing against the working directory's first parent
989 changeset if no revisions are specified.
989 changeset if no revisions are specified.
990
990
991 When two revision arguments are given, then changes are shown
991 When two revision arguments are given, then changes are shown
992 between those revisions. If only one revision is specified then
992 between those revisions. If only one revision is specified then
993 that revision is compared to the working directory, and, when no
993 that revision is compared to the working directory, and, when no
994 revisions are specified, the working directory files are compared
994 revisions are specified, the working directory files are compared
995 to its parent.
995 to its parent.
996
996
997 Without the -a option, diff will avoid generating diffs of files
997 Without the -a option, diff will avoid generating diffs of files
998 it detects as binary. With -a, diff will generate a diff anyway,
998 it detects as binary. With -a, diff will generate a diff anyway,
999 probably with undesirable results.
999 probably with undesirable results.
1000 """
1000 """
1001 node1, node2 = cmdutil.revpair(repo, opts['rev'])
1001 node1, node2 = cmdutil.revpair(repo, opts['rev'])
1002
1002
1003 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1003 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1004
1004
1005 patch.diff(repo, node1, node2, fns, match=matchfn,
1005 patch.diff(repo, node1, node2, fns, match=matchfn,
1006 opts=patch.diffopts(ui, opts))
1006 opts=patch.diffopts(ui, opts))
1007
1007
1008 def export(ui, repo, *changesets, **opts):
1008 def export(ui, repo, *changesets, **opts):
1009 """dump the header and diffs for one or more changesets
1009 """dump the header and diffs for one or more changesets
1010
1010
1011 Print the changeset header and diffs for one or more revisions.
1011 Print the changeset header and diffs for one or more revisions.
1012
1012
1013 The information shown in the changeset header is: author,
1013 The information shown in the changeset header is: author,
1014 changeset hash, parent(s) and commit comment.
1014 changeset hash, parent(s) and commit comment.
1015
1015
1016 NOTE: export may generate unexpected diff output for merge changesets,
1016 NOTE: export may generate unexpected diff output for merge changesets,
1017 as it will compare the merge changeset against its first parent only.
1017 as it will compare the merge changeset against its first parent only.
1018
1018
1019 Output may be to a file, in which case the name of the file is
1019 Output may be to a file, in which case the name of the file is
1020 given using a format string. The formatting rules are as follows:
1020 given using a format string. The formatting rules are as follows:
1021
1021
1022 %% literal "%" character
1022 %% literal "%" character
1023 %H changeset hash (40 bytes of hexadecimal)
1023 %H changeset hash (40 bytes of hexadecimal)
1024 %N number of patches being generated
1024 %N number of patches being generated
1025 %R changeset revision number
1025 %R changeset revision number
1026 %b basename of the exporting repository
1026 %b basename of the exporting repository
1027 %h short-form changeset hash (12 bytes of hexadecimal)
1027 %h short-form changeset hash (12 bytes of hexadecimal)
1028 %n zero-padded sequence number, starting at 1
1028 %n zero-padded sequence number, starting at 1
1029 %r zero-padded changeset revision number
1029 %r zero-padded changeset revision number
1030
1030
1031 Without the -a option, export will avoid generating diffs of files
1031 Without the -a option, export will avoid generating diffs of files
1032 it detects as binary. With -a, export will generate a diff anyway,
1032 it detects as binary. With -a, export will generate a diff anyway,
1033 probably with undesirable results.
1033 probably with undesirable results.
1034
1034
1035 With the --switch-parent option, the diff will be against the second
1035 With the --switch-parent option, the diff will be against the second
1036 parent. It can be useful to review a merge.
1036 parent. It can be useful to review a merge.
1037 """
1037 """
1038 if not changesets:
1038 if not changesets:
1039 raise util.Abort(_("export requires at least one changeset"))
1039 raise util.Abort(_("export requires at least one changeset"))
1040 revs = cmdutil.revrange(repo, changesets)
1040 revs = cmdutil.revrange(repo, changesets)
1041 if len(revs) > 1:
1041 if len(revs) > 1:
1042 ui.note(_('exporting patches:\n'))
1042 ui.note(_('exporting patches:\n'))
1043 else:
1043 else:
1044 ui.note(_('exporting patch:\n'))
1044 ui.note(_('exporting patch:\n'))
1045 patch.export(repo, revs, template=opts['output'],
1045 patch.export(repo, revs, template=opts['output'],
1046 switch_parent=opts['switch_parent'],
1046 switch_parent=opts['switch_parent'],
1047 opts=patch.diffopts(ui, opts))
1047 opts=patch.diffopts(ui, opts))
1048
1048
1049 def grep(ui, repo, pattern, *pats, **opts):
1049 def grep(ui, repo, pattern, *pats, **opts):
1050 """search for a pattern in specified files and revisions
1050 """search for a pattern in specified files and revisions
1051
1051
1052 Search revisions of files for a regular expression.
1052 Search revisions of files for a regular expression.
1053
1053
1054 This command behaves differently than Unix grep. It only accepts
1054 This command behaves differently than Unix grep. It only accepts
1055 Python/Perl regexps. It searches repository history, not the
1055 Python/Perl regexps. It searches repository history, not the
1056 working directory. It always prints the revision number in which
1056 working directory. It always prints the revision number in which
1057 a match appears.
1057 a match appears.
1058
1058
1059 By default, grep only prints output for the first revision of a
1059 By default, grep only prints output for the first revision of a
1060 file in which it finds a match. To get it to print every revision
1060 file in which it finds a match. To get it to print every revision
1061 that contains a change in match status ("-" for a match that
1061 that contains a change in match status ("-" for a match that
1062 becomes a non-match, or "+" for a non-match that becomes a match),
1062 becomes a non-match, or "+" for a non-match that becomes a match),
1063 use the --all flag.
1063 use the --all flag.
1064 """
1064 """
1065 reflags = 0
1065 reflags = 0
1066 if opts['ignore_case']:
1066 if opts['ignore_case']:
1067 reflags |= re.I
1067 reflags |= re.I
1068 regexp = re.compile(pattern, reflags)
1068 regexp = re.compile(pattern, reflags)
1069 sep, eol = ':', '\n'
1069 sep, eol = ':', '\n'
1070 if opts['print0']:
1070 if opts['print0']:
1071 sep = eol = '\0'
1071 sep = eol = '\0'
1072
1072
1073 fcache = {}
1073 fcache = {}
1074 def getfile(fn):
1074 def getfile(fn):
1075 if fn not in fcache:
1075 if fn not in fcache:
1076 fcache[fn] = repo.file(fn)
1076 fcache[fn] = repo.file(fn)
1077 return fcache[fn]
1077 return fcache[fn]
1078
1078
1079 def matchlines(body):
1079 def matchlines(body):
1080 begin = 0
1080 begin = 0
1081 linenum = 0
1081 linenum = 0
1082 while True:
1082 while True:
1083 match = regexp.search(body, begin)
1083 match = regexp.search(body, begin)
1084 if not match:
1084 if not match:
1085 break
1085 break
1086 mstart, mend = match.span()
1086 mstart, mend = match.span()
1087 linenum += body.count('\n', begin, mstart) + 1
1087 linenum += body.count('\n', begin, mstart) + 1
1088 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1088 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1089 lend = body.find('\n', mend)
1089 lend = body.find('\n', mend)
1090 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1090 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1091 begin = lend + 1
1091 begin = lend + 1
1092
1092
1093 class linestate(object):
1093 class linestate(object):
1094 def __init__(self, line, linenum, colstart, colend):
1094 def __init__(self, line, linenum, colstart, colend):
1095 self.line = line
1095 self.line = line
1096 self.linenum = linenum
1096 self.linenum = linenum
1097 self.colstart = colstart
1097 self.colstart = colstart
1098 self.colend = colend
1098 self.colend = colend
1099
1099
1100 def __eq__(self, other):
1100 def __eq__(self, other):
1101 return self.line == other.line
1101 return self.line == other.line
1102
1102
1103 matches = {}
1103 matches = {}
1104 copies = {}
1104 copies = {}
1105 def grepbody(fn, rev, body):
1105 def grepbody(fn, rev, body):
1106 matches[rev].setdefault(fn, [])
1106 matches[rev].setdefault(fn, [])
1107 m = matches[rev][fn]
1107 m = matches[rev][fn]
1108 for lnum, cstart, cend, line in matchlines(body):
1108 for lnum, cstart, cend, line in matchlines(body):
1109 s = linestate(line, lnum, cstart, cend)
1109 s = linestate(line, lnum, cstart, cend)
1110 m.append(s)
1110 m.append(s)
1111
1111
1112 def difflinestates(a, b):
1112 def difflinestates(a, b):
1113 sm = difflib.SequenceMatcher(None, a, b)
1113 sm = difflib.SequenceMatcher(None, a, b)
1114 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1114 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1115 if tag == 'insert':
1115 if tag == 'insert':
1116 for i in xrange(blo, bhi):
1116 for i in xrange(blo, bhi):
1117 yield ('+', b[i])
1117 yield ('+', b[i])
1118 elif tag == 'delete':
1118 elif tag == 'delete':
1119 for i in xrange(alo, ahi):
1119 for i in xrange(alo, ahi):
1120 yield ('-', a[i])
1120 yield ('-', a[i])
1121 elif tag == 'replace':
1121 elif tag == 'replace':
1122 for i in xrange(alo, ahi):
1122 for i in xrange(alo, ahi):
1123 yield ('-', a[i])
1123 yield ('-', a[i])
1124 for i in xrange(blo, bhi):
1124 for i in xrange(blo, bhi):
1125 yield ('+', b[i])
1125 yield ('+', b[i])
1126
1126
1127 prev = {}
1127 prev = {}
1128 def display(fn, rev, states, prevstates):
1128 def display(fn, rev, states, prevstates):
1129 found = False
1129 found = False
1130 filerevmatches = {}
1130 filerevmatches = {}
1131 r = prev.get(fn, -1)
1131 r = prev.get(fn, -1)
1132 if opts['all']:
1132 if opts['all']:
1133 iter = difflinestates(states, prevstates)
1133 iter = difflinestates(states, prevstates)
1134 else:
1134 else:
1135 iter = [('', l) for l in prevstates]
1135 iter = [('', l) for l in prevstates]
1136 for change, l in iter:
1136 for change, l in iter:
1137 cols = [fn, str(r)]
1137 cols = [fn, str(r)]
1138 if opts['line_number']:
1138 if opts['line_number']:
1139 cols.append(str(l.linenum))
1139 cols.append(str(l.linenum))
1140 if opts['all']:
1140 if opts['all']:
1141 cols.append(change)
1141 cols.append(change)
1142 if opts['user']:
1142 if opts['user']:
1143 cols.append(ui.shortuser(get(r)[1]))
1143 cols.append(ui.shortuser(get(r)[1]))
1144 if opts['files_with_matches']:
1144 if opts['files_with_matches']:
1145 c = (fn, r)
1145 c = (fn, r)
1146 if c in filerevmatches:
1146 if c in filerevmatches:
1147 continue
1147 continue
1148 filerevmatches[c] = 1
1148 filerevmatches[c] = 1
1149 else:
1149 else:
1150 cols.append(l.line)
1150 cols.append(l.line)
1151 ui.write(sep.join(cols), eol)
1151 ui.write(sep.join(cols), eol)
1152 found = True
1152 found = True
1153 return found
1153 return found
1154
1154
1155 fstate = {}
1155 fstate = {}
1156 skip = {}
1156 skip = {}
1157 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1157 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1158 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1158 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1159 found = False
1159 found = False
1160 follow = opts.get('follow')
1160 follow = opts.get('follow')
1161 for st, rev, fns in changeiter:
1161 for st, rev, fns in changeiter:
1162 if st == 'window':
1162 if st == 'window':
1163 matches.clear()
1163 matches.clear()
1164 elif st == 'add':
1164 elif st == 'add':
1165 mf = repo.changectx(rev).manifest()
1165 mf = repo.changectx(rev).manifest()
1166 matches[rev] = {}
1166 matches[rev] = {}
1167 for fn in fns:
1167 for fn in fns:
1168 if fn in skip:
1168 if fn in skip:
1169 continue
1169 continue
1170 fstate.setdefault(fn, {})
1170 fstate.setdefault(fn, {})
1171 try:
1171 try:
1172 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1172 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1173 if follow:
1173 if follow:
1174 copied = getfile(fn).renamed(mf[fn])
1174 copied = getfile(fn).renamed(mf[fn])
1175 if copied:
1175 if copied:
1176 copies.setdefault(rev, {})[fn] = copied[0]
1176 copies.setdefault(rev, {})[fn] = copied[0]
1177 except KeyError:
1177 except KeyError:
1178 pass
1178 pass
1179 elif st == 'iter':
1179 elif st == 'iter':
1180 states = matches[rev].items()
1180 states = matches[rev].items()
1181 states.sort()
1181 states.sort()
1182 for fn, m in states:
1182 for fn, m in states:
1183 copy = copies.get(rev, {}).get(fn)
1183 copy = copies.get(rev, {}).get(fn)
1184 if fn in skip:
1184 if fn in skip:
1185 if copy:
1185 if copy:
1186 skip[copy] = True
1186 skip[copy] = True
1187 continue
1187 continue
1188 if fn in prev or fstate[fn]:
1188 if fn in prev or fstate[fn]:
1189 r = display(fn, rev, m, fstate[fn])
1189 r = display(fn, rev, m, fstate[fn])
1190 found = found or r
1190 found = found or r
1191 if r and not opts['all']:
1191 if r and not opts['all']:
1192 skip[fn] = True
1192 skip[fn] = True
1193 if copy:
1193 if copy:
1194 skip[copy] = True
1194 skip[copy] = True
1195 fstate[fn] = m
1195 fstate[fn] = m
1196 if copy:
1196 if copy:
1197 fstate[copy] = m
1197 fstate[copy] = m
1198 prev[fn] = rev
1198 prev[fn] = rev
1199
1199
1200 fstate = fstate.items()
1200 fstate = fstate.items()
1201 fstate.sort()
1201 fstate.sort()
1202 for fn, state in fstate:
1202 for fn, state in fstate:
1203 if fn in skip:
1203 if fn in skip:
1204 continue
1204 continue
1205 if fn not in copies.get(prev[fn], {}):
1205 if fn not in copies.get(prev[fn], {}):
1206 found = display(fn, rev, {}, state) or found
1206 found = display(fn, rev, {}, state) or found
1207 return (not found and 1) or 0
1207 return (not found and 1) or 0
1208
1208
1209 def heads(ui, repo, *branchrevs, **opts):
1209 def heads(ui, repo, *branchrevs, **opts):
1210 """show current repository heads or show branch heads
1210 """show current repository heads or show branch heads
1211
1211
1212 With no arguments, show all repository head changesets.
1212 With no arguments, show all repository head changesets.
1213
1213
1214 If branch or revisions names are given this will show the heads of
1214 If branch or revisions names are given this will show the heads of
1215 the specified branches or the branches those revisions are tagged
1215 the specified branches or the branches those revisions are tagged
1216 with.
1216 with.
1217
1217
1218 Repository "heads" are changesets that don't have child
1218 Repository "heads" are changesets that don't have child
1219 changesets. They are where development generally takes place and
1219 changesets. They are where development generally takes place and
1220 are the usual targets for update and merge operations.
1220 are the usual targets for update and merge operations.
1221
1221
1222 Branch heads are changesets that have a given branch tag, but have
1222 Branch heads are changesets that have a given branch tag, but have
1223 no child changesets with that tag. They are usually where
1223 no child changesets with that tag. They are usually where
1224 development on the given branch takes place.
1224 development on the given branch takes place.
1225 """
1225 """
1226 if opts['rev']:
1226 if opts['rev']:
1227 start = repo.lookup(opts['rev'])
1227 start = repo.lookup(opts['rev'])
1228 else:
1228 else:
1229 start = None
1229 start = None
1230 if not branchrevs:
1230 if not branchrevs:
1231 # Assume we're looking repo-wide heads if no revs were specified.
1231 # Assume we're looking repo-wide heads if no revs were specified.
1232 heads = repo.heads(start)
1232 heads = repo.heads(start)
1233 else:
1233 else:
1234 heads = []
1234 heads = []
1235 visitedset = util.set()
1235 visitedset = util.set()
1236 for branchrev in branchrevs:
1236 for branchrev in branchrevs:
1237 branch = repo.changectx(branchrev).branch()
1237 branch = repo.changectx(branchrev).branch()
1238 if branch in visitedset:
1238 if branch in visitedset:
1239 continue
1239 continue
1240 visitedset.add(branch)
1240 visitedset.add(branch)
1241 bheads = repo.branchheads(branch, start)
1241 bheads = repo.branchheads(branch, start)
1242 if not bheads:
1242 if not bheads:
1243 if branch != branchrev:
1243 if branch != branchrev:
1244 ui.warn(_("no changes on branch %s containing %s are "
1244 ui.warn(_("no changes on branch %s containing %s are "
1245 "reachable from %s\n")
1245 "reachable from %s\n")
1246 % (branch, branchrev, opts['rev']))
1246 % (branch, branchrev, opts['rev']))
1247 else:
1247 else:
1248 ui.warn(_("no changes on branch %s are reachable from %s\n")
1248 ui.warn(_("no changes on branch %s are reachable from %s\n")
1249 % (branch, opts['rev']))
1249 % (branch, opts['rev']))
1250 heads.extend(bheads)
1250 heads.extend(bheads)
1251 if not heads:
1251 if not heads:
1252 return 1
1252 return 1
1253 displayer = cmdutil.show_changeset(ui, repo, opts)
1253 displayer = cmdutil.show_changeset(ui, repo, opts)
1254 for n in heads:
1254 for n in heads:
1255 displayer.show(changenode=n)
1255 displayer.show(changenode=n)
1256
1256
1257 def help_(ui, name=None, with_version=False):
1257 def help_(ui, name=None, with_version=False):
1258 """show help for a command, extension, or list of commands
1258 """show help for a command, extension, or list of commands
1259
1259
1260 With no arguments, print a list of commands and short help.
1260 With no arguments, print a list of commands and short help.
1261
1261
1262 Given a command name, print help for that command.
1262 Given a command name, print help for that command.
1263
1263
1264 Given an extension name, print help for that extension, and the
1264 Given an extension name, print help for that extension, and the
1265 commands it provides."""
1265 commands it provides."""
1266 option_lists = []
1266 option_lists = []
1267
1267
1268 def addglobalopts(aliases):
1268 def addglobalopts(aliases):
1269 if ui.verbose:
1269 if ui.verbose:
1270 option_lists.append((_("global options:"), globalopts))
1270 option_lists.append((_("global options:"), globalopts))
1271 if name == 'shortlist':
1271 if name == 'shortlist':
1272 option_lists.append((_('use "hg help" for the full list '
1272 option_lists.append((_('use "hg help" for the full list '
1273 'of commands'), ()))
1273 'of commands'), ()))
1274 else:
1274 else:
1275 if name == 'shortlist':
1275 if name == 'shortlist':
1276 msg = _('use "hg help" for the full list of commands '
1276 msg = _('use "hg help" for the full list of commands '
1277 'or "hg -v" for details')
1277 'or "hg -v" for details')
1278 elif aliases:
1278 elif aliases:
1279 msg = _('use "hg -v help%s" to show aliases and '
1279 msg = _('use "hg -v help%s" to show aliases and '
1280 'global options') % (name and " " + name or "")
1280 'global options') % (name and " " + name or "")
1281 else:
1281 else:
1282 msg = _('use "hg -v help %s" to show global options') % name
1282 msg = _('use "hg -v help %s" to show global options') % name
1283 option_lists.append((msg, ()))
1283 option_lists.append((msg, ()))
1284
1284
1285 def helpcmd(name):
1285 def helpcmd(name):
1286 if with_version:
1286 if with_version:
1287 version_(ui)
1287 version_(ui)
1288 ui.write('\n')
1288 ui.write('\n')
1289 aliases, i = cmdutil.findcmd(ui, name)
1289 aliases, i = cmdutil.findcmd(ui, name)
1290 # synopsis
1290 # synopsis
1291 ui.write("%s\n\n" % i[2])
1291 ui.write("%s\n\n" % i[2])
1292
1292
1293 # description
1293 # description
1294 doc = i[0].__doc__
1294 doc = i[0].__doc__
1295 if not doc:
1295 if not doc:
1296 doc = _("(No help text available)")
1296 doc = _("(No help text available)")
1297 if ui.quiet:
1297 if ui.quiet:
1298 doc = doc.splitlines(0)[0]
1298 doc = doc.splitlines(0)[0]
1299 ui.write("%s\n" % doc.rstrip())
1299 ui.write("%s\n" % doc.rstrip())
1300
1300
1301 if not ui.quiet:
1301 if not ui.quiet:
1302 # aliases
1302 # aliases
1303 if len(aliases) > 1:
1303 if len(aliases) > 1:
1304 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1304 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1305
1305
1306 # options
1306 # options
1307 if i[1]:
1307 if i[1]:
1308 option_lists.append((_("options:\n"), i[1]))
1308 option_lists.append((_("options:\n"), i[1]))
1309
1309
1310 addglobalopts(False)
1310 addglobalopts(False)
1311
1311
1312 def helplist(select=None):
1312 def helplist(select=None):
1313 h = {}
1313 h = {}
1314 cmds = {}
1314 cmds = {}
1315 for c, e in table.items():
1315 for c, e in table.items():
1316 f = c.split("|", 1)[0]
1316 f = c.split("|", 1)[0]
1317 if select and not select(f):
1317 if select and not select(f):
1318 continue
1318 continue
1319 if name == "shortlist" and not f.startswith("^"):
1319 if name == "shortlist" and not f.startswith("^"):
1320 continue
1320 continue
1321 f = f.lstrip("^")
1321 f = f.lstrip("^")
1322 if not ui.debugflag and f.startswith("debug"):
1322 if not ui.debugflag and f.startswith("debug"):
1323 continue
1323 continue
1324 doc = e[0].__doc__
1324 doc = e[0].__doc__
1325 if not doc:
1325 if not doc:
1326 doc = _("(No help text available)")
1326 doc = _("(No help text available)")
1327 h[f] = doc.splitlines(0)[0].rstrip()
1327 h[f] = doc.splitlines(0)[0].rstrip()
1328 cmds[f] = c.lstrip("^")
1328 cmds[f] = c.lstrip("^")
1329
1329
1330 fns = h.keys()
1330 fns = h.keys()
1331 fns.sort()
1331 fns.sort()
1332 m = max(map(len, fns))
1332 m = max(map(len, fns))
1333 for f in fns:
1333 for f in fns:
1334 if ui.verbose:
1334 if ui.verbose:
1335 commands = cmds[f].replace("|",", ")
1335 commands = cmds[f].replace("|",", ")
1336 ui.write(" %s:\n %s\n"%(commands, h[f]))
1336 ui.write(" %s:\n %s\n"%(commands, h[f]))
1337 else:
1337 else:
1338 ui.write(' %-*s %s\n' % (m, f, h[f]))
1338 ui.write(' %-*s %s\n' % (m, f, h[f]))
1339
1339
1340 if not ui.quiet:
1340 if not ui.quiet:
1341 addglobalopts(True)
1341 addglobalopts(True)
1342
1342
1343 def helptopic(name):
1343 def helptopic(name):
1344 v = None
1344 v = None
1345 for i in help.helptable:
1345 for i in help.helptable:
1346 l = i.split('|')
1346 l = i.split('|')
1347 if name in l:
1347 if name in l:
1348 v = i
1348 v = i
1349 header = l[-1]
1349 header = l[-1]
1350 if not v:
1350 if not v:
1351 raise cmdutil.UnknownCommand(name)
1351 raise cmdutil.UnknownCommand(name)
1352
1352
1353 # description
1353 # description
1354 doc = help.helptable[v]
1354 doc = help.helptable[v]
1355 if not doc:
1355 if not doc:
1356 doc = _("(No help text available)")
1356 doc = _("(No help text available)")
1357 if callable(doc):
1357 if callable(doc):
1358 doc = doc()
1358 doc = doc()
1359
1359
1360 ui.write("%s\n" % header)
1360 ui.write("%s\n" % header)
1361 ui.write("%s\n" % doc.rstrip())
1361 ui.write("%s\n" % doc.rstrip())
1362
1362
1363 def helpext(name):
1363 def helpext(name):
1364 try:
1364 try:
1365 mod = extensions.find(name)
1365 mod = extensions.find(name)
1366 except KeyError:
1366 except KeyError:
1367 raise cmdutil.UnknownCommand(name)
1367 raise cmdutil.UnknownCommand(name)
1368
1368
1369 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1369 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1370 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1370 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1371 for d in doc[1:]:
1371 for d in doc[1:]:
1372 ui.write(d, '\n')
1372 ui.write(d, '\n')
1373
1373
1374 ui.status('\n')
1374 ui.status('\n')
1375
1375
1376 try:
1376 try:
1377 ct = mod.cmdtable
1377 ct = mod.cmdtable
1378 except AttributeError:
1378 except AttributeError:
1379 ui.status(_('no commands defined\n'))
1379 ui.status(_('no commands defined\n'))
1380 return
1380 return
1381
1381
1382 ui.status(_('list of commands:\n\n'))
1382 ui.status(_('list of commands:\n\n'))
1383 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1383 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1384 helplist(modcmds.has_key)
1384 helplist(modcmds.has_key)
1385
1385
1386 if name and name != 'shortlist':
1386 if name and name != 'shortlist':
1387 i = None
1387 i = None
1388 for f in (helpcmd, helptopic, helpext):
1388 for f in (helpcmd, helptopic, helpext):
1389 try:
1389 try:
1390 f(name)
1390 f(name)
1391 i = None
1391 i = None
1392 break
1392 break
1393 except cmdutil.UnknownCommand, inst:
1393 except cmdutil.UnknownCommand, inst:
1394 i = inst
1394 i = inst
1395 if i:
1395 if i:
1396 raise i
1396 raise i
1397
1397
1398 else:
1398 else:
1399 # program name
1399 # program name
1400 if ui.verbose or with_version:
1400 if ui.verbose or with_version:
1401 version_(ui)
1401 version_(ui)
1402 else:
1402 else:
1403 ui.status(_("Mercurial Distributed SCM\n"))
1403 ui.status(_("Mercurial Distributed SCM\n"))
1404 ui.status('\n')
1404 ui.status('\n')
1405
1405
1406 # list of commands
1406 # list of commands
1407 if name == "shortlist":
1407 if name == "shortlist":
1408 ui.status(_('basic commands:\n\n'))
1408 ui.status(_('basic commands:\n\n'))
1409 else:
1409 else:
1410 ui.status(_('list of commands:\n\n'))
1410 ui.status(_('list of commands:\n\n'))
1411
1411
1412 helplist()
1412 helplist()
1413
1413
1414 # list all option lists
1414 # list all option lists
1415 opt_output = []
1415 opt_output = []
1416 for title, options in option_lists:
1416 for title, options in option_lists:
1417 opt_output.append(("\n%s" % title, None))
1417 opt_output.append(("\n%s" % title, None))
1418 for shortopt, longopt, default, desc in options:
1418 for shortopt, longopt, default, desc in options:
1419 if "DEPRECATED" in desc and not ui.verbose: continue
1419 if "DEPRECATED" in desc and not ui.verbose: continue
1420 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1420 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1421 longopt and " --%s" % longopt),
1421 longopt and " --%s" % longopt),
1422 "%s%s" % (desc,
1422 "%s%s" % (desc,
1423 default
1423 default
1424 and _(" (default: %s)") % default
1424 and _(" (default: %s)") % default
1425 or "")))
1425 or "")))
1426
1426
1427 if opt_output:
1427 if opt_output:
1428 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1428 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1429 for first, second in opt_output:
1429 for first, second in opt_output:
1430 if second:
1430 if second:
1431 ui.write(" %-*s %s\n" % (opts_len, first, second))
1431 ui.write(" %-*s %s\n" % (opts_len, first, second))
1432 else:
1432 else:
1433 ui.write("%s\n" % first)
1433 ui.write("%s\n" % first)
1434
1434
1435 def identify(ui, repo):
1435 def identify(ui, repo):
1436 """print information about the working copy
1436 """print information about the working copy
1437
1437
1438 Print a short summary of the current state of the repo.
1438 Print a short summary of the current state of the repo.
1439
1439
1440 This summary identifies the repository state using one or two parent
1440 This summary identifies the repository state using one or two parent
1441 hash identifiers, followed by a "+" if there are uncommitted changes
1441 hash identifiers, followed by a "+" if there are uncommitted changes
1442 in the working directory, followed by a list of tags for this revision.
1442 in the working directory, followed by a list of tags for this revision.
1443 """
1443 """
1444 parents = [p for p in repo.dirstate.parents() if p != nullid]
1444 parents = [p for p in repo.dirstate.parents() if p != nullid]
1445 if not parents:
1445 if not parents:
1446 ui.write(_("unknown\n"))
1446 ui.write(_("unknown\n"))
1447 return
1447 return
1448
1448
1449 hexfunc = ui.debugflag and hex or short
1449 hexfunc = ui.debugflag and hex or short
1450 modified, added, removed, deleted = repo.status()[:4]
1450 modified, added, removed, deleted = repo.status()[:4]
1451 output = ["%s%s" %
1451 output = ["%s%s" %
1452 ('+'.join([hexfunc(parent) for parent in parents]),
1452 ('+'.join([hexfunc(parent) for parent in parents]),
1453 (modified or added or removed or deleted) and "+" or "")]
1453 (modified or added or removed or deleted) and "+" or "")]
1454
1454
1455 if not ui.quiet:
1455 if not ui.quiet:
1456
1456
1457 branch = util.tolocal(repo.workingctx().branch())
1457 branch = util.tolocal(repo.workingctx().branch())
1458 if branch != 'default':
1458 if branch != 'default':
1459 output.append("(%s)" % branch)
1459 output.append("(%s)" % branch)
1460
1460
1461 # multiple tags for a single parent separated by '/'
1461 # multiple tags for a single parent separated by '/'
1462 parenttags = ['/'.join(tags)
1462 parenttags = ['/'.join(tags)
1463 for tags in map(repo.nodetags, parents) if tags]
1463 for tags in map(repo.nodetags, parents) if tags]
1464 # tags for multiple parents separated by ' + '
1464 # tags for multiple parents separated by ' + '
1465 if parenttags:
1465 if parenttags:
1466 output.append(' + '.join(parenttags))
1466 output.append(' + '.join(parenttags))
1467
1467
1468 ui.write("%s\n" % ' '.join(output))
1468 ui.write("%s\n" % ' '.join(output))
1469
1469
1470 def import_(ui, repo, patch1, *patches, **opts):
1470 def import_(ui, repo, patch1, *patches, **opts):
1471 """import an ordered set of patches
1471 """import an ordered set of patches
1472
1472
1473 Import a list of patches and commit them individually.
1473 Import a list of patches and commit them individually.
1474
1474
1475 If there are outstanding changes in the working directory, import
1475 If there are outstanding changes in the working directory, import
1476 will abort unless given the -f flag.
1476 will abort unless given the -f flag.
1477
1477
1478 You can import a patch straight from a mail message. Even patches
1478 You can import a patch straight from a mail message. Even patches
1479 as attachments work (body part must be type text/plain or
1479 as attachments work (body part must be type text/plain or
1480 text/x-patch to be used). From and Subject headers of email
1480 text/x-patch to be used). From and Subject headers of email
1481 message are used as default committer and commit message. All
1481 message are used as default committer and commit message. All
1482 text/plain body parts before first diff are added to commit
1482 text/plain body parts before first diff are added to commit
1483 message.
1483 message.
1484
1484
1485 If the imported patch was generated by hg export, user and description
1485 If the imported patch was generated by hg export, user and description
1486 from patch override values from message headers and body. Values
1486 from patch override values from message headers and body. Values
1487 given on command line with -m and -u override these.
1487 given on command line with -m and -u override these.
1488
1488
1489 If --exact is specified, import will set the working directory
1489 If --exact is specified, import will set the working directory
1490 to the parent of each patch before applying it, and will abort
1490 to the parent of each patch before applying it, and will abort
1491 if the resulting changeset has a different ID than the one
1491 if the resulting changeset has a different ID than the one
1492 recorded in the patch. This may happen due to character set
1492 recorded in the patch. This may happen due to character set
1493 problems or other deficiencies in the text patch format.
1493 problems or other deficiencies in the text patch format.
1494
1494
1495 To read a patch from standard input, use patch name "-".
1495 To read a patch from standard input, use patch name "-".
1496 """
1496 """
1497 patches = (patch1,) + patches
1497 patches = (patch1,) + patches
1498
1498
1499 if opts.get('exact') or not opts['force']:
1499 if opts.get('exact') or not opts['force']:
1500 cmdutil.bail_if_changed(repo)
1500 cmdutil.bail_if_changed(repo)
1501
1501
1502 d = opts["base"]
1502 d = opts["base"]
1503 strip = opts["strip"]
1503 strip = opts["strip"]
1504
1504
1505 wlock = repo.wlock()
1505 wlock = repo.wlock()
1506 lock = repo.lock()
1506 lock = repo.lock()
1507
1507
1508 for p in patches:
1508 for p in patches:
1509 pf = os.path.join(d, p)
1509 pf = os.path.join(d, p)
1510
1510
1511 if pf == '-':
1511 if pf == '-':
1512 ui.status(_("applying patch from stdin\n"))
1512 ui.status(_("applying patch from stdin\n"))
1513 tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, sys.stdin)
1513 tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, sys.stdin)
1514 else:
1514 else:
1515 ui.status(_("applying %s\n") % p)
1515 ui.status(_("applying %s\n") % p)
1516 tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, file(pf, 'rb'))
1516 tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, file(pf, 'rb'))
1517
1517
1518 if tmpname is None:
1518 if tmpname is None:
1519 raise util.Abort(_('no diffs found'))
1519 raise util.Abort(_('no diffs found'))
1520
1520
1521 try:
1521 try:
1522 cmdline_message = cmdutil.logmessage(opts)
1522 cmdline_message = cmdutil.logmessage(opts)
1523 if cmdline_message:
1523 if cmdline_message:
1524 # pickup the cmdline msg
1524 # pickup the cmdline msg
1525 message = cmdline_message
1525 message = cmdline_message
1526 elif message:
1526 elif message:
1527 # pickup the patch msg
1527 # pickup the patch msg
1528 message = message.strip()
1528 message = message.strip()
1529 else:
1529 else:
1530 # launch the editor
1530 # launch the editor
1531 message = None
1531 message = None
1532 ui.debug(_('message:\n%s\n') % message)
1532 ui.debug(_('message:\n%s\n') % message)
1533
1533
1534 wp = repo.workingctx().parents()
1534 wp = repo.workingctx().parents()
1535 if opts.get('exact'):
1535 if opts.get('exact'):
1536 if not nodeid or not p1:
1536 if not nodeid or not p1:
1537 raise util.Abort(_('not a mercurial patch'))
1537 raise util.Abort(_('not a mercurial patch'))
1538 p1 = repo.lookup(p1)
1538 p1 = repo.lookup(p1)
1539 p2 = repo.lookup(p2 or hex(nullid))
1539 p2 = repo.lookup(p2 or hex(nullid))
1540
1540
1541 if p1 != wp[0].node():
1541 if p1 != wp[0].node():
1542 hg.clean(repo, p1, wlock=wlock)
1542 hg.clean(repo, p1, wlock=wlock)
1543 repo.dirstate.setparents(p1, p2)
1543 repo.dirstate.setparents(p1, p2)
1544 elif p2:
1544 elif p2:
1545 try:
1545 try:
1546 p1 = repo.lookup(p1)
1546 p1 = repo.lookup(p1)
1547 p2 = repo.lookup(p2)
1547 p2 = repo.lookup(p2)
1548 if p1 == wp[0].node():
1548 if p1 == wp[0].node():
1549 repo.dirstate.setparents(p1, p2)
1549 repo.dirstate.setparents(p1, p2)
1550 except hg.RepoError:
1550 except hg.RepoError:
1551 pass
1551 pass
1552 if opts.get('exact') or opts.get('import_branch'):
1552 if opts.get('exact') or opts.get('import_branch'):
1553 repo.dirstate.setbranch(branch or 'default')
1553 repo.dirstate.setbranch(branch or 'default')
1554
1554
1555 files = {}
1555 files = {}
1556 try:
1556 try:
1557 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1557 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1558 files=files)
1558 files=files)
1559 finally:
1559 finally:
1560 files = patch.updatedir(ui, repo, files, wlock=wlock)
1560 files = patch.updatedir(ui, repo, files, wlock=wlock)
1561 n = repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1561 n = repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1562 if opts.get('exact'):
1562 if opts.get('exact'):
1563 if hex(n) != nodeid:
1563 if hex(n) != nodeid:
1564 repo.rollback(wlock=wlock, lock=lock)
1564 repo.rollback(wlock=wlock, lock=lock)
1565 raise util.Abort(_('patch is damaged or loses information'))
1565 raise util.Abort(_('patch is damaged or loses information'))
1566 finally:
1566 finally:
1567 os.unlink(tmpname)
1567 os.unlink(tmpname)
1568
1568
1569 def incoming(ui, repo, source="default", **opts):
1569 def incoming(ui, repo, source="default", **opts):
1570 """show new changesets found in source
1570 """show new changesets found in source
1571
1571
1572 Show new changesets found in the specified path/URL or the default
1572 Show new changesets found in the specified path/URL or the default
1573 pull location. These are the changesets that would be pulled if a pull
1573 pull location. These are the changesets that would be pulled if a pull
1574 was requested.
1574 was requested.
1575
1575
1576 For remote repository, using --bundle avoids downloading the changesets
1576 For remote repository, using --bundle avoids downloading the changesets
1577 twice if the incoming is followed by a pull.
1577 twice if the incoming is followed by a pull.
1578
1578
1579 See pull for valid source format details.
1579 See pull for valid source format details.
1580 """
1580 """
1581 source, revs = cmdutil.parseurl(ui.expandpath(source), opts['rev'])
1581 source, revs = cmdutil.parseurl(ui.expandpath(source), opts['rev'])
1582 cmdutil.setremoteconfig(ui, opts)
1582 cmdutil.setremoteconfig(ui, opts)
1583
1583
1584 other = hg.repository(ui, source)
1584 other = hg.repository(ui, source)
1585 ui.status(_('comparing with %s\n') % source)
1585 ui.status(_('comparing with %s\n') % source)
1586 if revs:
1586 if revs:
1587 if 'lookup' in other.capabilities:
1587 if 'lookup' in other.capabilities:
1588 revs = [other.lookup(rev) for rev in revs]
1588 revs = [other.lookup(rev) for rev in revs]
1589 else:
1589 else:
1590 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
1590 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
1591 raise util.Abort(error)
1591 raise util.Abort(error)
1592 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1592 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1593 if not incoming:
1593 if not incoming:
1594 try:
1594 try:
1595 os.unlink(opts["bundle"])
1595 os.unlink(opts["bundle"])
1596 except:
1596 except:
1597 pass
1597 pass
1598 ui.status(_("no changes found\n"))
1598 ui.status(_("no changes found\n"))
1599 return 1
1599 return 1
1600
1600
1601 cleanup = None
1601 cleanup = None
1602 try:
1602 try:
1603 fname = opts["bundle"]
1603 fname = opts["bundle"]
1604 if fname or not other.local():
1604 if fname or not other.local():
1605 # create a bundle (uncompressed if other repo is not local)
1605 # create a bundle (uncompressed if other repo is not local)
1606 if revs is None:
1606 if revs is None:
1607 cg = other.changegroup(incoming, "incoming")
1607 cg = other.changegroup(incoming, "incoming")
1608 else:
1608 else:
1609 if 'changegroupsubset' not in other.capabilities:
1609 if 'changegroupsubset' not in other.capabilities:
1610 raise util.Abort(_("Partial incoming cannot be done because other repository doesn't support changegroupsubset."))
1610 raise util.Abort(_("Partial incoming cannot be done because other repository doesn't support changegroupsubset."))
1611 cg = other.changegroupsubset(incoming, revs, 'incoming')
1611 cg = other.changegroupsubset(incoming, revs, 'incoming')
1612 bundletype = other.local() and "HG10BZ" or "HG10UN"
1612 bundletype = other.local() and "HG10BZ" or "HG10UN"
1613 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1613 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1614 # keep written bundle?
1614 # keep written bundle?
1615 if opts["bundle"]:
1615 if opts["bundle"]:
1616 cleanup = None
1616 cleanup = None
1617 if not other.local():
1617 if not other.local():
1618 # use the created uncompressed bundlerepo
1618 # use the created uncompressed bundlerepo
1619 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1619 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1620
1620
1621 o = other.changelog.nodesbetween(incoming, revs)[0]
1621 o = other.changelog.nodesbetween(incoming, revs)[0]
1622 if opts['newest_first']:
1622 if opts['newest_first']:
1623 o.reverse()
1623 o.reverse()
1624 displayer = cmdutil.show_changeset(ui, other, opts)
1624 displayer = cmdutil.show_changeset(ui, other, opts)
1625 for n in o:
1625 for n in o:
1626 parents = [p for p in other.changelog.parents(n) if p != nullid]
1626 parents = [p for p in other.changelog.parents(n) if p != nullid]
1627 if opts['no_merges'] and len(parents) == 2:
1627 if opts['no_merges'] and len(parents) == 2:
1628 continue
1628 continue
1629 displayer.show(changenode=n)
1629 displayer.show(changenode=n)
1630 finally:
1630 finally:
1631 if hasattr(other, 'close'):
1631 if hasattr(other, 'close'):
1632 other.close()
1632 other.close()
1633 if cleanup:
1633 if cleanup:
1634 os.unlink(cleanup)
1634 os.unlink(cleanup)
1635
1635
1636 def init(ui, dest=".", **opts):
1636 def init(ui, dest=".", **opts):
1637 """create a new repository in the given directory
1637 """create a new repository in the given directory
1638
1638
1639 Initialize a new repository in the given directory. If the given
1639 Initialize a new repository in the given directory. If the given
1640 directory does not exist, it is created.
1640 directory does not exist, it is created.
1641
1641
1642 If no directory is given, the current directory is used.
1642 If no directory is given, the current directory is used.
1643
1643
1644 It is possible to specify an ssh:// URL as the destination.
1644 It is possible to specify an ssh:// URL as the destination.
1645 Look at the help text for the pull command for important details
1645 Look at the help text for the pull command for important details
1646 about ssh:// URLs.
1646 about ssh:// URLs.
1647 """
1647 """
1648 cmdutil.setremoteconfig(ui, opts)
1648 cmdutil.setremoteconfig(ui, opts)
1649 hg.repository(ui, dest, create=1)
1649 hg.repository(ui, dest, create=1)
1650
1650
1651 def locate(ui, repo, *pats, **opts):
1651 def locate(ui, repo, *pats, **opts):
1652 """locate files matching specific patterns
1652 """locate files matching specific patterns
1653
1653
1654 Print all files under Mercurial control whose names match the
1654 Print all files under Mercurial control whose names match the
1655 given patterns.
1655 given patterns.
1656
1656
1657 This command searches the entire repository by default. To search
1657 This command searches the entire repository by default. To search
1658 just the current directory and its subdirectories, use "--include .".
1658 just the current directory and its subdirectories, use "--include .".
1659
1659
1660 If no patterns are given to match, this command prints all file
1660 If no patterns are given to match, this command prints all file
1661 names.
1661 names.
1662
1662
1663 If you want to feed the output of this command into the "xargs"
1663 If you want to feed the output of this command into the "xargs"
1664 command, use the "-0" option to both this command and "xargs".
1664 command, use the "-0" option to both this command and "xargs".
1665 This will avoid the problem of "xargs" treating single filenames
1665 This will avoid the problem of "xargs" treating single filenames
1666 that contain white space as multiple filenames.
1666 that contain white space as multiple filenames.
1667 """
1667 """
1668 end = opts['print0'] and '\0' or '\n'
1668 end = opts['print0'] and '\0' or '\n'
1669 rev = opts['rev']
1669 rev = opts['rev']
1670 if rev:
1670 if rev:
1671 node = repo.lookup(rev)
1671 node = repo.lookup(rev)
1672 else:
1672 else:
1673 node = None
1673 node = None
1674
1674
1675 ret = 1
1675 ret = 1
1676 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1676 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1677 badmatch=util.always,
1677 badmatch=util.always,
1678 default='relglob'):
1678 default='relglob'):
1679 if src == 'b':
1679 if src == 'b':
1680 continue
1680 continue
1681 if not node and repo.dirstate.state(abs) == '?':
1681 if not node and repo.dirstate.state(abs) == '?':
1682 continue
1682 continue
1683 if opts['fullpath']:
1683 if opts['fullpath']:
1684 ui.write(os.path.join(repo.root, abs), end)
1684 ui.write(os.path.join(repo.root, abs), end)
1685 else:
1685 else:
1686 ui.write(((pats and rel) or abs), end)
1686 ui.write(((pats and rel) or abs), end)
1687 ret = 0
1687 ret = 0
1688
1688
1689 return ret
1689 return ret
1690
1690
1691 def log(ui, repo, *pats, **opts):
1691 def log(ui, repo, *pats, **opts):
1692 """show revision history of entire repository or files
1692 """show revision history of entire repository or files
1693
1693
1694 Print the revision history of the specified files or the entire
1694 Print the revision history of the specified files or the entire
1695 project.
1695 project.
1696
1696
1697 File history is shown without following rename or copy history of
1697 File history is shown without following rename or copy history of
1698 files. Use -f/--follow with a file name to follow history across
1698 files. Use -f/--follow with a file name to follow history across
1699 renames and copies. --follow without a file name will only show
1699 renames and copies. --follow without a file name will only show
1700 ancestors or descendants of the starting revision. --follow-first
1700 ancestors or descendants of the starting revision. --follow-first
1701 only follows the first parent of merge revisions.
1701 only follows the first parent of merge revisions.
1702
1702
1703 If no revision range is specified, the default is tip:0 unless
1703 If no revision range is specified, the default is tip:0 unless
1704 --follow is set, in which case the working directory parent is
1704 --follow is set, in which case the working directory parent is
1705 used as the starting revision.
1705 used as the starting revision.
1706
1706
1707 By default this command outputs: changeset id and hash, tags,
1707 By default this command outputs: changeset id and hash, tags,
1708 non-trivial parents, user, date and time, and a summary for each
1708 non-trivial parents, user, date and time, and a summary for each
1709 commit. When the -v/--verbose switch is used, the list of changed
1709 commit. When the -v/--verbose switch is used, the list of changed
1710 files and full commit message is shown.
1710 files and full commit message is shown.
1711
1711
1712 NOTE: log -p may generate unexpected diff output for merge
1712 NOTE: log -p may generate unexpected diff output for merge
1713 changesets, as it will compare the merge changeset against its
1713 changesets, as it will compare the merge changeset against its
1714 first parent only. Also, the files: list will only reflect files
1714 first parent only. Also, the files: list will only reflect files
1715 that are different from BOTH parents.
1715 that are different from BOTH parents.
1716
1716
1717 """
1717 """
1718
1718
1719 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1719 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1720 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1720 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1721
1721
1722 if opts['limit']:
1722 if opts['limit']:
1723 try:
1723 try:
1724 limit = int(opts['limit'])
1724 limit = int(opts['limit'])
1725 except ValueError:
1725 except ValueError:
1726 raise util.Abort(_('limit must be a positive integer'))
1726 raise util.Abort(_('limit must be a positive integer'))
1727 if limit <= 0: raise util.Abort(_('limit must be positive'))
1727 if limit <= 0: raise util.Abort(_('limit must be positive'))
1728 else:
1728 else:
1729 limit = sys.maxint
1729 limit = sys.maxint
1730 count = 0
1730 count = 0
1731
1731
1732 if opts['copies'] and opts['rev']:
1732 if opts['copies'] and opts['rev']:
1733 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1733 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1734 else:
1734 else:
1735 endrev = repo.changelog.count()
1735 endrev = repo.changelog.count()
1736 rcache = {}
1736 rcache = {}
1737 ncache = {}
1737 ncache = {}
1738 dcache = []
1738 dcache = []
1739 def getrenamed(fn, rev, man):
1739 def getrenamed(fn, rev, man):
1740 '''looks up all renames for a file (up to endrev) the first
1740 '''looks up all renames for a file (up to endrev) the first
1741 time the file is given. It indexes on the changerev and only
1741 time the file is given. It indexes on the changerev and only
1742 parses the manifest if linkrev != changerev.
1742 parses the manifest if linkrev != changerev.
1743 Returns rename info for fn at changerev rev.'''
1743 Returns rename info for fn at changerev rev.'''
1744 if fn not in rcache:
1744 if fn not in rcache:
1745 rcache[fn] = {}
1745 rcache[fn] = {}
1746 ncache[fn] = {}
1746 ncache[fn] = {}
1747 fl = repo.file(fn)
1747 fl = repo.file(fn)
1748 for i in xrange(fl.count()):
1748 for i in xrange(fl.count()):
1749 node = fl.node(i)
1749 node = fl.node(i)
1750 lr = fl.linkrev(node)
1750 lr = fl.linkrev(node)
1751 renamed = fl.renamed(node)
1751 renamed = fl.renamed(node)
1752 rcache[fn][lr] = renamed
1752 rcache[fn][lr] = renamed
1753 if renamed:
1753 if renamed:
1754 ncache[fn][node] = renamed
1754 ncache[fn][node] = renamed
1755 if lr >= endrev:
1755 if lr >= endrev:
1756 break
1756 break
1757 if rev in rcache[fn]:
1757 if rev in rcache[fn]:
1758 return rcache[fn][rev]
1758 return rcache[fn][rev]
1759 mr = repo.manifest.rev(man)
1759 mr = repo.manifest.rev(man)
1760 if repo.manifest.parentrevs(mr) != (mr - 1, nullrev):
1760 if repo.manifest.parentrevs(mr) != (mr - 1, nullrev):
1761 return ncache[fn].get(repo.manifest.find(man, fn)[0])
1761 return ncache[fn].get(repo.manifest.find(man, fn)[0])
1762 if not dcache or dcache[0] != man:
1762 if not dcache or dcache[0] != man:
1763 dcache[:] = [man, repo.manifest.readdelta(man)]
1763 dcache[:] = [man, repo.manifest.readdelta(man)]
1764 if fn in dcache[1]:
1764 if fn in dcache[1]:
1765 return ncache[fn].get(dcache[1][fn])
1765 return ncache[fn].get(dcache[1][fn])
1766 return None
1766 return None
1767
1767
1768 df = False
1768 df = False
1769 if opts["date"]:
1769 if opts["date"]:
1770 df = util.matchdate(opts["date"])
1770 df = util.matchdate(opts["date"])
1771
1771
1772 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1772 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1773 for st, rev, fns in changeiter:
1773 for st, rev, fns in changeiter:
1774 if st == 'add':
1774 if st == 'add':
1775 changenode = repo.changelog.node(rev)
1775 changenode = repo.changelog.node(rev)
1776 parents = [p for p in repo.changelog.parentrevs(rev)
1776 parents = [p for p in repo.changelog.parentrevs(rev)
1777 if p != nullrev]
1777 if p != nullrev]
1778 if opts['no_merges'] and len(parents) == 2:
1778 if opts['no_merges'] and len(parents) == 2:
1779 continue
1779 continue
1780 if opts['only_merges'] and len(parents) != 2:
1780 if opts['only_merges'] and len(parents) != 2:
1781 continue
1781 continue
1782
1782
1783 if df:
1783 if df:
1784 changes = get(rev)
1784 changes = get(rev)
1785 if not df(changes[2][0]):
1785 if not df(changes[2][0]):
1786 continue
1786 continue
1787
1787
1788 if opts['keyword']:
1788 if opts['keyword']:
1789 changes = get(rev)
1789 changes = get(rev)
1790 miss = 0
1790 miss = 0
1791 for k in [kw.lower() for kw in opts['keyword']]:
1791 for k in [kw.lower() for kw in opts['keyword']]:
1792 if not (k in changes[1].lower() or
1792 if not (k in changes[1].lower() or
1793 k in changes[4].lower() or
1793 k in changes[4].lower() or
1794 k in " ".join(changes[3]).lower()):
1794 k in " ".join(changes[3]).lower()):
1795 miss = 1
1795 miss = 1
1796 break
1796 break
1797 if miss:
1797 if miss:
1798 continue
1798 continue
1799
1799
1800 copies = []
1800 copies = []
1801 if opts.get('copies') and rev:
1801 if opts.get('copies') and rev:
1802 mf = get(rev)[0]
1802 mf = get(rev)[0]
1803 for fn in get(rev)[3]:
1803 for fn in get(rev)[3]:
1804 rename = getrenamed(fn, rev, mf)
1804 rename = getrenamed(fn, rev, mf)
1805 if rename:
1805 if rename:
1806 copies.append((fn, rename[0]))
1806 copies.append((fn, rename[0]))
1807 displayer.show(rev, changenode, copies=copies)
1807 displayer.show(rev, changenode, copies=copies)
1808 elif st == 'iter':
1808 elif st == 'iter':
1809 if count == limit: break
1809 if count == limit: break
1810 if displayer.flush(rev):
1810 if displayer.flush(rev):
1811 count += 1
1811 count += 1
1812
1812
1813 def manifest(ui, repo, rev=None):
1813 def manifest(ui, repo, rev=None):
1814 """output the current or given revision of the project manifest
1814 """output the current or given revision of the project manifest
1815
1815
1816 Print a list of version controlled files for the given revision.
1816 Print a list of version controlled files for the given revision.
1817 If no revision is given, the parent of the working directory is used,
1817 If no revision is given, the parent of the working directory is used,
1818 or tip if no revision is checked out.
1818 or tip if no revision is checked out.
1819
1819
1820 The manifest is the list of files being version controlled. If no revision
1820 The manifest is the list of files being version controlled. If no revision
1821 is given then the first parent of the working directory is used.
1821 is given then the first parent of the working directory is used.
1822
1822
1823 With -v flag, print file permissions. With --debug flag, print
1823 With -v flag, print file permissions. With --debug flag, print
1824 file revision hashes.
1824 file revision hashes.
1825 """
1825 """
1826
1826
1827 m = repo.changectx(rev).manifest()
1827 m = repo.changectx(rev).manifest()
1828 files = m.keys()
1828 files = m.keys()
1829 files.sort()
1829 files.sort()
1830
1830
1831 for f in files:
1831 for f in files:
1832 if ui.debugflag:
1832 if ui.debugflag:
1833 ui.write("%40s " % hex(m[f]))
1833 ui.write("%40s " % hex(m[f]))
1834 if ui.verbose:
1834 if ui.verbose:
1835 ui.write("%3s " % (m.execf(f) and "755" or "644"))
1835 ui.write("%3s " % (m.execf(f) and "755" or "644"))
1836 ui.write("%s\n" % f)
1836 ui.write("%s\n" % f)
1837
1837
1838 def merge(ui, repo, node=None, force=None, rev=None):
1838 def merge(ui, repo, node=None, force=None, rev=None):
1839 """merge working directory with another revision
1839 """merge working directory with another revision
1840
1840
1841 Merge the contents of the current working directory and the
1841 Merge the contents of the current working directory and the
1842 requested revision. Files that changed between either parent are
1842 requested revision. Files that changed between either parent are
1843 marked as changed for the next commit and a commit must be
1843 marked as changed for the next commit and a commit must be
1844 performed before any further updates are allowed.
1844 performed before any further updates are allowed.
1845
1845
1846 If no revision is specified, the working directory's parent is a
1846 If no revision is specified, the working directory's parent is a
1847 head revision, and the repository contains exactly one other head,
1847 head revision, and the repository contains exactly one other head,
1848 the other head is merged with by default. Otherwise, an explicit
1848 the other head is merged with by default. Otherwise, an explicit
1849 revision to merge with must be provided.
1849 revision to merge with must be provided.
1850 """
1850 """
1851
1851
1852 if rev and node:
1852 if rev and node:
1853 raise util.Abort(_("please specify just one revision"))
1853 raise util.Abort(_("please specify just one revision"))
1854
1854
1855 if not node:
1855 if not node:
1856 node = rev
1856 node = rev
1857
1857
1858 if not node:
1858 if not node:
1859 heads = repo.heads()
1859 heads = repo.heads()
1860 if len(heads) > 2:
1860 if len(heads) > 2:
1861 raise util.Abort(_('repo has %d heads - '
1861 raise util.Abort(_('repo has %d heads - '
1862 'please merge with an explicit rev') %
1862 'please merge with an explicit rev') %
1863 len(heads))
1863 len(heads))
1864 if len(heads) == 1:
1864 if len(heads) == 1:
1865 raise util.Abort(_('there is nothing to merge - '
1865 raise util.Abort(_('there is nothing to merge - '
1866 'use "hg update" instead'))
1866 'use "hg update" instead'))
1867 parent = repo.dirstate.parents()[0]
1867 parent = repo.dirstate.parents()[0]
1868 if parent not in heads:
1868 if parent not in heads:
1869 raise util.Abort(_('working dir not at a head rev - '
1869 raise util.Abort(_('working dir not at a head rev - '
1870 'use "hg update" or merge with an explicit rev'))
1870 'use "hg update" or merge with an explicit rev'))
1871 node = parent == heads[0] and heads[-1] or heads[0]
1871 node = parent == heads[0] and heads[-1] or heads[0]
1872 return hg.merge(repo, node, force=force)
1872 return hg.merge(repo, node, force=force)
1873
1873
1874 def outgoing(ui, repo, dest=None, **opts):
1874 def outgoing(ui, repo, dest=None, **opts):
1875 """show changesets not found in destination
1875 """show changesets not found in destination
1876
1876
1877 Show changesets not found in the specified destination repository or
1877 Show changesets not found in the specified destination repository or
1878 the default push location. These are the changesets that would be pushed
1878 the default push location. These are the changesets that would be pushed
1879 if a push was requested.
1879 if a push was requested.
1880
1880
1881 See pull for valid destination format details.
1881 See pull for valid destination format details.
1882 """
1882 """
1883 dest, revs = cmdutil.parseurl(
1883 dest, revs = cmdutil.parseurl(
1884 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
1884 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
1885 cmdutil.setremoteconfig(ui, opts)
1885 cmdutil.setremoteconfig(ui, opts)
1886 if revs:
1886 if revs:
1887 revs = [repo.lookup(rev) for rev in revs]
1887 revs = [repo.lookup(rev) for rev in revs]
1888
1888
1889 other = hg.repository(ui, dest)
1889 other = hg.repository(ui, dest)
1890 ui.status(_('comparing with %s\n') % dest)
1890 ui.status(_('comparing with %s\n') % dest)
1891 o = repo.findoutgoing(other, force=opts['force'])
1891 o = repo.findoutgoing(other, force=opts['force'])
1892 if not o:
1892 if not o:
1893 ui.status(_("no changes found\n"))
1893 ui.status(_("no changes found\n"))
1894 return 1
1894 return 1
1895 o = repo.changelog.nodesbetween(o, revs)[0]
1895 o = repo.changelog.nodesbetween(o, revs)[0]
1896 if opts['newest_first']:
1896 if opts['newest_first']:
1897 o.reverse()
1897 o.reverse()
1898 displayer = cmdutil.show_changeset(ui, repo, opts)
1898 displayer = cmdutil.show_changeset(ui, repo, opts)
1899 for n in o:
1899 for n in o:
1900 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1900 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1901 if opts['no_merges'] and len(parents) == 2:
1901 if opts['no_merges'] and len(parents) == 2:
1902 continue
1902 continue
1903 displayer.show(changenode=n)
1903 displayer.show(changenode=n)
1904
1904
1905 def parents(ui, repo, file_=None, **opts):
1905 def parents(ui, repo, file_=None, **opts):
1906 """show the parents of the working dir or revision
1906 """show the parents of the working dir or revision
1907
1907
1908 Print the working directory's parent revisions. If a
1908 Print the working directory's parent revisions. If a
1909 revision is given via --rev, the parent of that revision
1909 revision is given via --rev, the parent of that revision
1910 will be printed. If a file argument is given, revision in
1910 will be printed. If a file argument is given, revision in
1911 which the file was last changed (before the working directory
1911 which the file was last changed (before the working directory
1912 revision or the argument to --rev if given) is printed.
1912 revision or the argument to --rev if given) is printed.
1913 """
1913 """
1914 rev = opts.get('rev')
1914 rev = opts.get('rev')
1915 if file_:
1915 if file_:
1916 ctx = repo.filectx(file_, changeid=rev)
1916 ctx = repo.filectx(file_, changeid=rev)
1917 elif rev:
1917 elif rev:
1918 ctx = repo.changectx(rev)
1918 ctx = repo.changectx(rev)
1919 else:
1919 else:
1920 ctx = repo.workingctx()
1920 ctx = repo.workingctx()
1921 p = [cp.node() for cp in ctx.parents()]
1921 p = [cp.node() for cp in ctx.parents()]
1922
1922
1923 displayer = cmdutil.show_changeset(ui, repo, opts)
1923 displayer = cmdutil.show_changeset(ui, repo, opts)
1924 for n in p:
1924 for n in p:
1925 if n != nullid:
1925 if n != nullid:
1926 displayer.show(changenode=n)
1926 displayer.show(changenode=n)
1927
1927
1928 def paths(ui, repo, search=None):
1928 def paths(ui, repo, search=None):
1929 """show definition of symbolic path names
1929 """show definition of symbolic path names
1930
1930
1931 Show definition of symbolic path name NAME. If no name is given, show
1931 Show definition of symbolic path name NAME. If no name is given, show
1932 definition of available names.
1932 definition of available names.
1933
1933
1934 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1934 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1935 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1935 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1936 """
1936 """
1937 if search:
1937 if search:
1938 for name, path in ui.configitems("paths"):
1938 for name, path in ui.configitems("paths"):
1939 if name == search:
1939 if name == search:
1940 ui.write("%s\n" % path)
1940 ui.write("%s\n" % path)
1941 return
1941 return
1942 ui.warn(_("not found!\n"))
1942 ui.warn(_("not found!\n"))
1943 return 1
1943 return 1
1944 else:
1944 else:
1945 for name, path in ui.configitems("paths"):
1945 for name, path in ui.configitems("paths"):
1946 ui.write("%s = %s\n" % (name, path))
1946 ui.write("%s = %s\n" % (name, path))
1947
1947
1948 def postincoming(ui, repo, modheads, optupdate):
1948 def postincoming(ui, repo, modheads, optupdate):
1949 if modheads == 0:
1949 if modheads == 0:
1950 return
1950 return
1951 if optupdate:
1951 if optupdate:
1952 if modheads == 1:
1952 if modheads == 1:
1953 return hg.update(repo, repo.changelog.tip()) # update
1953 return hg.update(repo, repo.changelog.tip()) # update
1954 else:
1954 else:
1955 ui.status(_("not updating, since new heads added\n"))
1955 ui.status(_("not updating, since new heads added\n"))
1956 if modheads > 1:
1956 if modheads > 1:
1957 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1957 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1958 else:
1958 else:
1959 ui.status(_("(run 'hg update' to get a working copy)\n"))
1959 ui.status(_("(run 'hg update' to get a working copy)\n"))
1960
1960
1961 def pull(ui, repo, source="default", **opts):
1961 def pull(ui, repo, source="default", **opts):
1962 """pull changes from the specified source
1962 """pull changes from the specified source
1963
1963
1964 Pull changes from a remote repository to a local one.
1964 Pull changes from a remote repository to a local one.
1965
1965
1966 This finds all changes from the repository at the specified path
1966 This finds all changes from the repository at the specified path
1967 or URL and adds them to the local repository. By default, this
1967 or URL and adds them to the local repository. By default, this
1968 does not update the copy of the project in the working directory.
1968 does not update the copy of the project in the working directory.
1969
1969
1970 Valid URLs are of the form:
1970 Valid URLs are of the form:
1971
1971
1972 local/filesystem/path (or file://local/filesystem/path)
1972 local/filesystem/path (or file://local/filesystem/path)
1973 http://[user@]host[:port]/[path]
1973 http://[user@]host[:port]/[path]
1974 https://[user@]host[:port]/[path]
1974 https://[user@]host[:port]/[path]
1975 ssh://[user@]host[:port]/[path]
1975 ssh://[user@]host[:port]/[path]
1976 static-http://host[:port]/[path]
1976 static-http://host[:port]/[path]
1977
1977
1978 Paths in the local filesystem can either point to Mercurial
1978 Paths in the local filesystem can either point to Mercurial
1979 repositories or to bundle files (as created by 'hg bundle' or
1979 repositories or to bundle files (as created by 'hg bundle' or
1980 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
1980 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
1981 allows access to a Mercurial repository where you simply use a web
1981 allows access to a Mercurial repository where you simply use a web
1982 server to publish the .hg directory as static content.
1982 server to publish the .hg directory as static content.
1983
1983
1984 An optional identifier after # indicates a particular branch, tag,
1984 An optional identifier after # indicates a particular branch, tag,
1985 or changeset to pull.
1985 or changeset to pull.
1986
1986
1987 Some notes about using SSH with Mercurial:
1987 Some notes about using SSH with Mercurial:
1988 - SSH requires an accessible shell account on the destination machine
1988 - SSH requires an accessible shell account on the destination machine
1989 and a copy of hg in the remote path or specified with as remotecmd.
1989 and a copy of hg in the remote path or specified with as remotecmd.
1990 - path is relative to the remote user's home directory by default.
1990 - path is relative to the remote user's home directory by default.
1991 Use an extra slash at the start of a path to specify an absolute path:
1991 Use an extra slash at the start of a path to specify an absolute path:
1992 ssh://example.com//tmp/repository
1992 ssh://example.com//tmp/repository
1993 - Mercurial doesn't use its own compression via SSH; the right thing
1993 - Mercurial doesn't use its own compression via SSH; the right thing
1994 to do is to configure it in your ~/.ssh/config, e.g.:
1994 to do is to configure it in your ~/.ssh/config, e.g.:
1995 Host *.mylocalnetwork.example.com
1995 Host *.mylocalnetwork.example.com
1996 Compression no
1996 Compression no
1997 Host *
1997 Host *
1998 Compression yes
1998 Compression yes
1999 Alternatively specify "ssh -C" as your ssh command in your hgrc or
1999 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2000 with the --ssh command line option.
2000 with the --ssh command line option.
2001 """
2001 """
2002 source, revs = cmdutil.parseurl(ui.expandpath(source), opts['rev'])
2002 source, revs = cmdutil.parseurl(ui.expandpath(source), opts['rev'])
2003 cmdutil.setremoteconfig(ui, opts)
2003 cmdutil.setremoteconfig(ui, opts)
2004
2004
2005 other = hg.repository(ui, source)
2005 other = hg.repository(ui, source)
2006 ui.status(_('pulling from %s\n') % (source))
2006 ui.status(_('pulling from %s\n') % (source))
2007 if revs:
2007 if revs:
2008 if 'lookup' in other.capabilities:
2008 if 'lookup' in other.capabilities:
2009 revs = [other.lookup(rev) for rev in revs]
2009 revs = [other.lookup(rev) for rev in revs]
2010 else:
2010 else:
2011 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
2011 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
2012 raise util.Abort(error)
2012 raise util.Abort(error)
2013
2013
2014 modheads = repo.pull(other, heads=revs, force=opts['force'])
2014 modheads = repo.pull(other, heads=revs, force=opts['force'])
2015 return postincoming(ui, repo, modheads, opts['update'])
2015 return postincoming(ui, repo, modheads, opts['update'])
2016
2016
2017 def push(ui, repo, dest=None, **opts):
2017 def push(ui, repo, dest=None, **opts):
2018 """push changes to the specified destination
2018 """push changes to the specified destination
2019
2019
2020 Push changes from the local repository to the given destination.
2020 Push changes from the local repository to the given destination.
2021
2021
2022 This is the symmetrical operation for pull. It helps to move
2022 This is the symmetrical operation for pull. It helps to move
2023 changes from the current repository to a different one. If the
2023 changes from the current repository to a different one. If the
2024 destination is local this is identical to a pull in that directory
2024 destination is local this is identical to a pull in that directory
2025 from the current one.
2025 from the current one.
2026
2026
2027 By default, push will refuse to run if it detects the result would
2027 By default, push will refuse to run if it detects the result would
2028 increase the number of remote heads. This generally indicates the
2028 increase the number of remote heads. This generally indicates the
2029 the client has forgotten to sync and merge before pushing.
2029 the client has forgotten to sync and merge before pushing.
2030
2030
2031 Valid URLs are of the form:
2031 Valid URLs are of the form:
2032
2032
2033 local/filesystem/path (or file://local/filesystem/path)
2033 local/filesystem/path (or file://local/filesystem/path)
2034 ssh://[user@]host[:port]/[path]
2034 ssh://[user@]host[:port]/[path]
2035 http://[user@]host[:port]/[path]
2035 http://[user@]host[:port]/[path]
2036 https://[user@]host[:port]/[path]
2036 https://[user@]host[:port]/[path]
2037
2037
2038 An optional identifier after # indicates a particular branch, tag,
2038 An optional identifier after # indicates a particular branch, tag,
2039 or changeset to push.
2039 or changeset to push.
2040
2040
2041 Look at the help text for the pull command for important details
2041 Look at the help text for the pull command for important details
2042 about ssh:// URLs.
2042 about ssh:// URLs.
2043
2043
2044 Pushing to http:// and https:// URLs is only possible, if this
2044 Pushing to http:// and https:// URLs is only possible, if this
2045 feature is explicitly enabled on the remote Mercurial server.
2045 feature is explicitly enabled on the remote Mercurial server.
2046 """
2046 """
2047 dest, revs = cmdutil.parseurl(
2047 dest, revs = cmdutil.parseurl(
2048 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
2048 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
2049 cmdutil.setremoteconfig(ui, opts)
2049 cmdutil.setremoteconfig(ui, opts)
2050
2050
2051 other = hg.repository(ui, dest)
2051 other = hg.repository(ui, dest)
2052 ui.status('pushing to %s\n' % (dest))
2052 ui.status('pushing to %s\n' % (dest))
2053 if revs:
2053 if revs:
2054 revs = [repo.lookup(rev) for rev in revs]
2054 revs = [repo.lookup(rev) for rev in revs]
2055 r = repo.push(other, opts['force'], revs=revs)
2055 r = repo.push(other, opts['force'], revs=revs)
2056 return r == 0
2056 return r == 0
2057
2057
2058 def rawcommit(ui, repo, *pats, **opts):
2058 def rawcommit(ui, repo, *pats, **opts):
2059 """raw commit interface (DEPRECATED)
2059 """raw commit interface (DEPRECATED)
2060
2060
2061 (DEPRECATED)
2061 (DEPRECATED)
2062 Lowlevel commit, for use in helper scripts.
2062 Lowlevel commit, for use in helper scripts.
2063
2063
2064 This command is not intended to be used by normal users, as it is
2064 This command is not intended to be used by normal users, as it is
2065 primarily useful for importing from other SCMs.
2065 primarily useful for importing from other SCMs.
2066
2066
2067 This command is now deprecated and will be removed in a future
2067 This command is now deprecated and will be removed in a future
2068 release, please use debugsetparents and commit instead.
2068 release, please use debugsetparents and commit instead.
2069 """
2069 """
2070
2070
2071 ui.warn(_("(the rawcommit command is deprecated)\n"))
2071 ui.warn(_("(the rawcommit command is deprecated)\n"))
2072
2072
2073 message = cmdutil.logmessage(opts)
2073 message = cmdutil.logmessage(opts)
2074
2074
2075 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
2075 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
2076 if opts['files']:
2076 if opts['files']:
2077 files += open(opts['files']).read().splitlines()
2077 files += open(opts['files']).read().splitlines()
2078
2078
2079 parents = [repo.lookup(p) for p in opts['parent']]
2079 parents = [repo.lookup(p) for p in opts['parent']]
2080
2080
2081 try:
2081 try:
2082 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2082 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2083 except ValueError, inst:
2083 except ValueError, inst:
2084 raise util.Abort(str(inst))
2084 raise util.Abort(str(inst))
2085
2085
2086 def recover(ui, repo):
2086 def recover(ui, repo):
2087 """roll back an interrupted transaction
2087 """roll back an interrupted transaction
2088
2088
2089 Recover from an interrupted commit or pull.
2089 Recover from an interrupted commit or pull.
2090
2090
2091 This command tries to fix the repository status after an interrupted
2091 This command tries to fix the repository status after an interrupted
2092 operation. It should only be necessary when Mercurial suggests it.
2092 operation. It should only be necessary when Mercurial suggests it.
2093 """
2093 """
2094 if repo.recover():
2094 if repo.recover():
2095 return hg.verify(repo)
2095 return hg.verify(repo)
2096 return 1
2096 return 1
2097
2097
2098 def remove(ui, repo, *pats, **opts):
2098 def remove(ui, repo, *pats, **opts):
2099 """remove the specified files on the next commit
2099 """remove the specified files on the next commit
2100
2100
2101 Schedule the indicated files for removal from the repository.
2101 Schedule the indicated files for removal from the repository.
2102
2102
2103 This only removes files from the current branch, not from the
2103 This only removes files from the current branch, not from the
2104 entire project history. If the files still exist in the working
2104 entire project history. If the files still exist in the working
2105 directory, they will be deleted from it. If invoked with --after,
2105 directory, they will be deleted from it. If invoked with --after,
2106 files are marked as removed, but not actually unlinked unless --force
2106 files are marked as removed, but not actually unlinked unless --force
2107 is also given. Without exact file names, --after will only mark
2107 is also given. Without exact file names, --after will only mark
2108 files as removed if they are no longer in the working directory.
2108 files as removed if they are no longer in the working directory.
2109
2109
2110 This command schedules the files to be removed at the next commit.
2110 This command schedules the files to be removed at the next commit.
2111 To undo a remove before that, see hg revert.
2111 To undo a remove before that, see hg revert.
2112
2112
2113 Modified files and added files are not removed by default. To
2113 Modified files and added files are not removed by default. To
2114 remove them, use the -f/--force option.
2114 remove them, use the -f/--force option.
2115 """
2115 """
2116 names = []
2116 names = []
2117 if not opts['after'] and not pats:
2117 if not opts['after'] and not pats:
2118 raise util.Abort(_('no files specified'))
2118 raise util.Abort(_('no files specified'))
2119 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2119 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2120 exact = dict.fromkeys(files)
2120 exact = dict.fromkeys(files)
2121 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2121 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2122 modified, added, removed, deleted, unknown = mardu
2122 modified, added, removed, deleted, unknown = mardu
2123 remove, forget = [], []
2123 remove, forget = [], []
2124 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2124 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2125 reason = None
2125 reason = None
2126 if abs in modified and not opts['force']:
2126 if abs in modified and not opts['force']:
2127 reason = _('is modified (use -f to force removal)')
2127 reason = _('is modified (use -f to force removal)')
2128 elif abs in added:
2128 elif abs in added:
2129 if opts['force']:
2129 if opts['force']:
2130 forget.append(abs)
2130 forget.append(abs)
2131 continue
2131 continue
2132 reason = _('has been marked for add (use -f to force removal)')
2132 reason = _('has been marked for add (use -f to force removal)')
2133 elif repo.dirstate.state(abs) == '?':
2133 elif repo.dirstate.state(abs) == '?':
2134 reason = _('is not managed')
2134 reason = _('is not managed')
2135 elif opts['after'] and not exact and abs not in deleted:
2135 elif opts['after'] and not exact and abs not in deleted:
2136 continue
2136 continue
2137 elif abs in removed:
2137 elif abs in removed:
2138 continue
2138 continue
2139 if reason:
2139 if reason:
2140 if exact:
2140 if exact:
2141 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2141 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2142 else:
2142 else:
2143 if ui.verbose or not exact:
2143 if ui.verbose or not exact:
2144 ui.status(_('removing %s\n') % rel)
2144 ui.status(_('removing %s\n') % rel)
2145 remove.append(abs)
2145 remove.append(abs)
2146 repo.forget(forget)
2146 repo.forget(forget)
2147 repo.remove(remove, unlink=opts['force'] or not opts['after'])
2147 repo.remove(remove, unlink=opts['force'] or not opts['after'])
2148
2148
2149 def rename(ui, repo, *pats, **opts):
2149 def rename(ui, repo, *pats, **opts):
2150 """rename files; equivalent of copy + remove
2150 """rename files; equivalent of copy + remove
2151
2151
2152 Mark dest as copies of sources; mark sources for deletion. If
2152 Mark dest as copies of sources; mark sources for deletion. If
2153 dest is a directory, copies are put in that directory. If dest is
2153 dest is a directory, copies are put in that directory. If dest is
2154 a file, there can only be one source.
2154 a file, there can only be one source.
2155
2155
2156 By default, this command copies the contents of files as they
2156 By default, this command copies the contents of files as they
2157 stand in the working directory. If invoked with --after, the
2157 stand in the working directory. If invoked with --after, the
2158 operation is recorded, but no copying is performed.
2158 operation is recorded, but no copying is performed.
2159
2159
2160 This command takes effect in the next commit. To undo a rename
2160 This command takes effect in the next commit. To undo a rename
2161 before that, see hg revert.
2161 before that, see hg revert.
2162 """
2162 """
2163 wlock = repo.wlock(0)
2163 wlock = repo.wlock(0)
2164 errs, copied = docopy(ui, repo, pats, opts, wlock)
2164 errs, copied = docopy(ui, repo, pats, opts, wlock)
2165 names = []
2165 names = []
2166 for abs, rel, exact in copied:
2166 for abs, rel, exact in copied:
2167 if ui.verbose or not exact:
2167 if ui.verbose or not exact:
2168 ui.status(_('removing %s\n') % rel)
2168 ui.status(_('removing %s\n') % rel)
2169 names.append(abs)
2169 names.append(abs)
2170 if not opts.get('dry_run'):
2170 if not opts.get('dry_run'):
2171 repo.remove(names, True, wlock=wlock)
2171 repo.remove(names, True, wlock=wlock)
2172 return errs
2172 return errs
2173
2173
2174 def revert(ui, repo, *pats, **opts):
2174 def revert(ui, repo, *pats, **opts):
2175 """revert files or dirs to their states as of some revision
2175 """revert files or dirs to their states as of some revision
2176
2176
2177 With no revision specified, revert the named files or directories
2177 With no revision specified, revert the named files or directories
2178 to the contents they had in the parent of the working directory.
2178 to the contents they had in the parent of the working directory.
2179 This restores the contents of the affected files to an unmodified
2179 This restores the contents of the affected files to an unmodified
2180 state and unschedules adds, removes, copies, and renames. If the
2180 state and unschedules adds, removes, copies, and renames. If the
2181 working directory has two parents, you must explicitly specify the
2181 working directory has two parents, you must explicitly specify the
2182 revision to revert to.
2182 revision to revert to.
2183
2183
2184 Modified files are saved with a .orig suffix before reverting.
2184 Modified files are saved with a .orig suffix before reverting.
2185 To disable these backups, use --no-backup.
2185 To disable these backups, use --no-backup.
2186
2186
2187 Using the -r option, revert the given files or directories to their
2187 Using the -r option, revert the given files or directories to their
2188 contents as of a specific revision. This can be helpful to "roll
2188 contents as of a specific revision. This can be helpful to "roll
2189 back" some or all of a change that should not have been committed.
2189 back" some or all of a change that should not have been committed.
2190
2190
2191 Revert modifies the working directory. It does not commit any
2191 Revert modifies the working directory. It does not commit any
2192 changes, or change the parent of the working directory. If you
2192 changes, or change the parent of the working directory. If you
2193 revert to a revision other than the parent of the working
2193 revert to a revision other than the parent of the working
2194 directory, the reverted files will thus appear modified
2194 directory, the reverted files will thus appear modified
2195 afterwards.
2195 afterwards.
2196
2196
2197 If a file has been deleted, it is recreated. If the executable
2197 If a file has been deleted, it is recreated. If the executable
2198 mode of a file was changed, it is reset.
2198 mode of a file was changed, it is reset.
2199
2199
2200 If names are given, all files matching the names are reverted.
2200 If names are given, all files matching the names are reverted.
2201
2201
2202 If no arguments are given, no files are reverted.
2202 If no arguments are given, no files are reverted.
2203 """
2203 """
2204
2204
2205 if opts["date"]:
2205 if opts["date"]:
2206 if opts["rev"]:
2206 if opts["rev"]:
2207 raise util.Abort(_("you can't specify a revision and a date"))
2207 raise util.Abort(_("you can't specify a revision and a date"))
2208 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2208 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2209
2209
2210 if not pats and not opts['all']:
2210 if not pats and not opts['all']:
2211 raise util.Abort(_('no files or directories specified; '
2211 raise util.Abort(_('no files or directories specified; '
2212 'use --all to revert the whole repo'))
2212 'use --all to revert the whole repo'))
2213
2213
2214 parent, p2 = repo.dirstate.parents()
2214 parent, p2 = repo.dirstate.parents()
2215 if not opts['rev'] and p2 != nullid:
2215 if not opts['rev'] and p2 != nullid:
2216 raise util.Abort(_('uncommitted merge - please provide a '
2216 raise util.Abort(_('uncommitted merge - please provide a '
2217 'specific revision'))
2217 'specific revision'))
2218 ctx = repo.changectx(opts['rev'])
2218 ctx = repo.changectx(opts['rev'])
2219 node = ctx.node()
2219 node = ctx.node()
2220 mf = ctx.manifest()
2220 mf = ctx.manifest()
2221 if node == parent:
2221 if node == parent:
2222 pmf = mf
2222 pmf = mf
2223 else:
2223 else:
2224 pmf = None
2224 pmf = None
2225
2225
2226 wlock = repo.wlock()
2226 wlock = repo.wlock()
2227
2227
2228 # need all matching names in dirstate and manifest of target rev,
2228 # need all matching names in dirstate and manifest of target rev,
2229 # so have to walk both. do not print errors if files exist in one
2229 # so have to walk both. do not print errors if files exist in one
2230 # but not other.
2230 # but not other.
2231
2231
2232 names = {}
2232 names = {}
2233 target_only = {}
2233 target_only = {}
2234
2234
2235 # walk dirstate.
2235 # walk dirstate.
2236
2236
2237 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2237 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2238 badmatch=mf.has_key):
2238 badmatch=mf.has_key):
2239 names[abs] = (rel, exact)
2239 names[abs] = (rel, exact)
2240 if src == 'b':
2240 if src == 'b':
2241 target_only[abs] = True
2241 target_only[abs] = True
2242
2242
2243 # walk target manifest.
2243 # walk target manifest.
2244
2244
2245 def badmatch(path):
2245 def badmatch(path):
2246 if path in names:
2246 if path in names:
2247 return True
2247 return True
2248 path_ = path + '/'
2248 path_ = path + '/'
2249 for f in names:
2249 for f in names:
2250 if f.startswith(path_):
2250 if f.startswith(path_):
2251 return True
2251 return True
2252 return False
2252 return False
2253
2253
2254 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2254 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2255 badmatch=badmatch):
2255 badmatch=badmatch):
2256 if abs in names or src == 'b':
2256 if abs in names or src == 'b':
2257 continue
2257 continue
2258 names[abs] = (rel, exact)
2258 names[abs] = (rel, exact)
2259 target_only[abs] = True
2259 target_only[abs] = True
2260
2260
2261 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2261 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2262 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2262 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2263
2263
2264 revert = ([], _('reverting %s\n'))
2264 revert = ([], _('reverting %s\n'))
2265 add = ([], _('adding %s\n'))
2265 add = ([], _('adding %s\n'))
2266 remove = ([], _('removing %s\n'))
2266 remove = ([], _('removing %s\n'))
2267 forget = ([], _('forgetting %s\n'))
2267 forget = ([], _('forgetting %s\n'))
2268 undelete = ([], _('undeleting %s\n'))
2268 undelete = ([], _('undeleting %s\n'))
2269 update = {}
2269 update = {}
2270
2270
2271 disptable = (
2271 disptable = (
2272 # dispatch table:
2272 # dispatch table:
2273 # file state
2273 # file state
2274 # action if in target manifest
2274 # action if in target manifest
2275 # action if not in target manifest
2275 # action if not in target manifest
2276 # make backup if in target manifest
2276 # make backup if in target manifest
2277 # make backup if not in target manifest
2277 # make backup if not in target manifest
2278 (modified, revert, remove, True, True),
2278 (modified, revert, remove, True, True),
2279 (added, revert, forget, True, False),
2279 (added, revert, forget, True, False),
2280 (removed, undelete, None, False, False),
2280 (removed, undelete, None, False, False),
2281 (deleted, revert, remove, False, False),
2281 (deleted, revert, remove, False, False),
2282 (unknown, add, None, True, False),
2282 (unknown, add, None, True, False),
2283 (target_only, add, None, False, False),
2283 (target_only, add, None, False, False),
2284 )
2284 )
2285
2285
2286 entries = names.items()
2286 entries = names.items()
2287 entries.sort()
2287 entries.sort()
2288
2288
2289 for abs, (rel, exact) in entries:
2289 for abs, (rel, exact) in entries:
2290 mfentry = mf.get(abs)
2290 mfentry = mf.get(abs)
2291 target = repo.wjoin(abs)
2291 target = repo.wjoin(abs)
2292 def handle(xlist, dobackup):
2292 def handle(xlist, dobackup):
2293 xlist[0].append(abs)
2293 xlist[0].append(abs)
2294 update[abs] = 1
2294 update[abs] = 1
2295 if dobackup and not opts['no_backup'] and util.lexists(target):
2295 if dobackup and not opts['no_backup'] and util.lexists(target):
2296 bakname = "%s.orig" % rel
2296 bakname = "%s.orig" % rel
2297 ui.note(_('saving current version of %s as %s\n') %
2297 ui.note(_('saving current version of %s as %s\n') %
2298 (rel, bakname))
2298 (rel, bakname))
2299 if not opts.get('dry_run'):
2299 if not opts.get('dry_run'):
2300 util.copyfile(target, bakname)
2300 util.copyfile(target, bakname)
2301 if ui.verbose or not exact:
2301 if ui.verbose or not exact:
2302 ui.status(xlist[1] % rel)
2302 ui.status(xlist[1] % rel)
2303 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2303 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2304 if abs not in table: continue
2304 if abs not in table: continue
2305 # file has changed in dirstate
2305 # file has changed in dirstate
2306 if mfentry:
2306 if mfentry:
2307 handle(hitlist, backuphit)
2307 handle(hitlist, backuphit)
2308 elif misslist is not None:
2308 elif misslist is not None:
2309 handle(misslist, backupmiss)
2309 handle(misslist, backupmiss)
2310 else:
2310 else:
2311 if exact: ui.warn(_('file not managed: %s\n') % rel)
2311 if exact: ui.warn(_('file not managed: %s\n') % rel)
2312 break
2312 break
2313 else:
2313 else:
2314 # file has not changed in dirstate
2314 # file has not changed in dirstate
2315 if node == parent:
2315 if node == parent:
2316 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2316 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2317 continue
2317 continue
2318 if pmf is None:
2318 if pmf is None:
2319 # only need parent manifest in this unlikely case,
2319 # only need parent manifest in this unlikely case,
2320 # so do not read by default
2320 # so do not read by default
2321 pmf = repo.changectx(parent).manifest()
2321 pmf = repo.changectx(parent).manifest()
2322 if abs in pmf:
2322 if abs in pmf:
2323 if mfentry:
2323 if mfentry:
2324 # if version of file is same in parent and target
2324 # if version of file is same in parent and target
2325 # manifests, do nothing
2325 # manifests, do nothing
2326 if pmf[abs] != mfentry:
2326 if pmf[abs] != mfentry:
2327 handle(revert, False)
2327 handle(revert, False)
2328 else:
2328 else:
2329 handle(remove, False)
2329 handle(remove, False)
2330
2330
2331 if not opts.get('dry_run'):
2331 if not opts.get('dry_run'):
2332 repo.dirstate.forget(forget[0])
2332 repo.dirstate.forget(forget[0])
2333 r = hg.revert(repo, node, update.has_key, wlock)
2333 r = hg.revert(repo, node, update.has_key, wlock)
2334 repo.dirstate.update(add[0], 'a')
2334 repo.dirstate.update(add[0], 'a')
2335 repo.dirstate.update(undelete[0], 'n')
2335 repo.dirstate.update(undelete[0], 'n')
2336 repo.dirstate.update(remove[0], 'r')
2336 repo.dirstate.update(remove[0], 'r')
2337 return r
2337 return r
2338
2338
2339 def rollback(ui, repo):
2339 def rollback(ui, repo):
2340 """roll back the last transaction in this repository
2340 """roll back the last transaction in this repository
2341
2341
2342 Roll back the last transaction in this repository, restoring the
2342 Roll back the last transaction in this repository, restoring the
2343 project to its state prior to the transaction.
2343 project to its state prior to the transaction.
2344
2344
2345 Transactions are used to encapsulate the effects of all commands
2345 Transactions are used to encapsulate the effects of all commands
2346 that create new changesets or propagate existing changesets into a
2346 that create new changesets or propagate existing changesets into a
2347 repository. For example, the following commands are transactional,
2347 repository. For example, the following commands are transactional,
2348 and their effects can be rolled back:
2348 and their effects can be rolled back:
2349
2349
2350 commit
2350 commit
2351 import
2351 import
2352 pull
2352 pull
2353 push (with this repository as destination)
2353 push (with this repository as destination)
2354 unbundle
2354 unbundle
2355
2355
2356 This command should be used with care. There is only one level of
2356 This command should be used with care. There is only one level of
2357 rollback, and there is no way to undo a rollback.
2357 rollback, and there is no way to undo a rollback.
2358
2358
2359 This command is not intended for use on public repositories. Once
2359 This command is not intended for use on public repositories. Once
2360 changes are visible for pull by other users, rolling a transaction
2360 changes are visible for pull by other users, rolling a transaction
2361 back locally is ineffective (someone else may already have pulled
2361 back locally is ineffective (someone else may already have pulled
2362 the changes). Furthermore, a race is possible with readers of the
2362 the changes). Furthermore, a race is possible with readers of the
2363 repository; for example an in-progress pull from the repository
2363 repository; for example an in-progress pull from the repository
2364 may fail if a rollback is performed.
2364 may fail if a rollback is performed.
2365 """
2365 """
2366 repo.rollback()
2366 repo.rollback()
2367
2367
2368 def root(ui, repo):
2368 def root(ui, repo):
2369 """print the root (top) of the current working dir
2369 """print the root (top) of the current working dir
2370
2370
2371 Print the root directory of the current repository.
2371 Print the root directory of the current repository.
2372 """
2372 """
2373 ui.write(repo.root + "\n")
2373 ui.write(repo.root + "\n")
2374
2374
2375 def serve(ui, repo, **opts):
2375 def serve(ui, repo, **opts):
2376 """export the repository via HTTP
2376 """export the repository via HTTP
2377
2377
2378 Start a local HTTP repository browser and pull server.
2378 Start a local HTTP repository browser and pull server.
2379
2379
2380 By default, the server logs accesses to stdout and errors to
2380 By default, the server logs accesses to stdout and errors to
2381 stderr. Use the "-A" and "-E" options to log to files.
2381 stderr. Use the "-A" and "-E" options to log to files.
2382 """
2382 """
2383
2383
2384 if opts["stdio"]:
2384 if opts["stdio"]:
2385 if repo is None:
2385 if repo is None:
2386 raise hg.RepoError(_("There is no Mercurial repository here"
2386 raise hg.RepoError(_("There is no Mercurial repository here"
2387 " (.hg not found)"))
2387 " (.hg not found)"))
2388 s = sshserver.sshserver(ui, repo)
2388 s = sshserver.sshserver(ui, repo)
2389 s.serve_forever()
2389 s.serve_forever()
2390
2390
2391 parentui = ui.parentui or ui
2391 parentui = ui.parentui or ui
2392 optlist = ("name templates style address port ipv6"
2392 optlist = ("name templates style address port ipv6"
2393 " accesslog errorlog webdir_conf")
2393 " accesslog errorlog webdir_conf")
2394 for o in optlist.split():
2394 for o in optlist.split():
2395 if opts[o]:
2395 if opts[o]:
2396 parentui.setconfig("web", o, str(opts[o]))
2396 parentui.setconfig("web", o, str(opts[o]))
2397
2397
2398 if repo is None and not ui.config("web", "webdir_conf"):
2398 if repo is None and not ui.config("web", "webdir_conf"):
2399 raise hg.RepoError(_("There is no Mercurial repository here"
2399 raise hg.RepoError(_("There is no Mercurial repository here"
2400 " (.hg not found)"))
2400 " (.hg not found)"))
2401
2401
2402 class service:
2402 class service:
2403 def init(self):
2403 def init(self):
2404 try:
2404 try:
2405 self.httpd = hgweb.server.create_server(parentui, repo)
2405 self.httpd = hgweb.server.create_server(parentui, repo)
2406 except socket.error, inst:
2406 except socket.error, inst:
2407 raise util.Abort(_('cannot start server: ') + inst.args[1])
2407 raise util.Abort(_('cannot start server: ') + inst.args[1])
2408
2408
2409 if not ui.verbose: return
2409 if not ui.verbose: return
2410
2410
2411 if self.httpd.port != 80:
2411 if self.httpd.port != 80:
2412 ui.status(_('listening at http://%s:%d/\n') %
2412 ui.status(_('listening at http://%s:%d/\n') %
2413 (self.httpd.addr, self.httpd.port))
2413 (self.httpd.addr, self.httpd.port))
2414 else:
2414 else:
2415 ui.status(_('listening at http://%s/\n') % self.httpd.addr)
2415 ui.status(_('listening at http://%s/\n') % self.httpd.addr)
2416
2416
2417 def run(self):
2417 def run(self):
2418 self.httpd.serve_forever()
2418 self.httpd.serve_forever()
2419
2419
2420 service = service()
2420 service = service()
2421
2421
2422 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2422 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2423
2423
2424 def status(ui, repo, *pats, **opts):
2424 def status(ui, repo, *pats, **opts):
2425 """show changed files in the working directory
2425 """show changed files in the working directory
2426
2426
2427 Show status of files in the repository. If names are given, only
2427 Show status of files in the repository. If names are given, only
2428 files that match are shown. Files that are clean or ignored, are
2428 files that match are shown. Files that are clean or ignored, are
2429 not listed unless -c (clean), -i (ignored) or -A is given.
2429 not listed unless -c (clean), -i (ignored) or -A is given.
2430
2430
2431 NOTE: status may appear to disagree with diff if permissions have
2431 NOTE: status may appear to disagree with diff if permissions have
2432 changed or a merge has occurred. The standard diff format does not
2432 changed or a merge has occurred. The standard diff format does not
2433 report permission changes and diff only reports changes relative
2433 report permission changes and diff only reports changes relative
2434 to one merge parent.
2434 to one merge parent.
2435
2435
2436 If one revision is given, it is used as the base revision.
2436 If one revision is given, it is used as the base revision.
2437 If two revisions are given, the difference between them is shown.
2437 If two revisions are given, the difference between them is shown.
2438
2438
2439 The codes used to show the status of files are:
2439 The codes used to show the status of files are:
2440 M = modified
2440 M = modified
2441 A = added
2441 A = added
2442 R = removed
2442 R = removed
2443 C = clean
2443 C = clean
2444 ! = deleted, but still tracked
2444 ! = deleted, but still tracked
2445 ? = not tracked
2445 ? = not tracked
2446 I = ignored (not shown by default)
2446 I = ignored (not shown by default)
2447 = the previous added file was copied from here
2447 = the previous added file was copied from here
2448 """
2448 """
2449
2449
2450 all = opts['all']
2450 all = opts['all']
2451 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2451 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2452
2452
2453 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2453 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2454 cwd = (pats and repo.getcwd()) or ''
2454 cwd = (pats and repo.getcwd()) or ''
2455 modified, added, removed, deleted, unknown, ignored, clean = [
2455 modified, added, removed, deleted, unknown, ignored, clean = [
2456 n for n in repo.status(node1=node1, node2=node2, files=files,
2456 n for n in repo.status(node1=node1, node2=node2, files=files,
2457 match=matchfn,
2457 match=matchfn,
2458 list_ignored=all or opts['ignored'],
2458 list_ignored=all or opts['ignored'],
2459 list_clean=all or opts['clean'])]
2459 list_clean=all or opts['clean'])]
2460
2460
2461 changetypes = (('modified', 'M', modified),
2461 changetypes = (('modified', 'M', modified),
2462 ('added', 'A', added),
2462 ('added', 'A', added),
2463 ('removed', 'R', removed),
2463 ('removed', 'R', removed),
2464 ('deleted', '!', deleted),
2464 ('deleted', '!', deleted),
2465 ('unknown', '?', unknown),
2465 ('unknown', '?', unknown),
2466 ('ignored', 'I', ignored))
2466 ('ignored', 'I', ignored))
2467
2467
2468 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2468 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2469
2469
2470 end = opts['print0'] and '\0' or '\n'
2470 end = opts['print0'] and '\0' or '\n'
2471
2471
2472 for opt, char, changes in ([ct for ct in explicit_changetypes
2472 for opt, char, changes in ([ct for ct in explicit_changetypes
2473 if all or opts[ct[0]]]
2473 if all or opts[ct[0]]]
2474 or changetypes):
2474 or changetypes):
2475 if opts['no_status']:
2475 if opts['no_status']:
2476 format = "%%s%s" % end
2476 format = "%%s%s" % end
2477 else:
2477 else:
2478 format = "%s %%s%s" % (char, end)
2478 format = "%s %%s%s" % (char, end)
2479
2479
2480 for f in changes:
2480 for f in changes:
2481 ui.write(format % repo.pathto(f, cwd))
2481 ui.write(format % repo.pathto(f, cwd))
2482 if ((all or opts.get('copies')) and not opts.get('no_status')):
2482 if ((all or opts.get('copies')) and not opts.get('no_status')):
2483 copied = repo.dirstate.copied(f)
2483 copied = repo.dirstate.copied(f)
2484 if copied:
2484 if copied:
2485 ui.write(' %s%s' % (repo.pathto(copied, cwd), end))
2485 ui.write(' %s%s' % (repo.pathto(copied, cwd), end))
2486
2486
2487 def tag(ui, repo, name, rev_=None, **opts):
2487 def tag(ui, repo, name, rev_=None, **opts):
2488 """add a tag for the current or given revision
2488 """add a tag for the current or given revision
2489
2489
2490 Name a particular revision using <name>.
2490 Name a particular revision using <name>.
2491
2491
2492 Tags are used to name particular revisions of the repository and are
2492 Tags are used to name particular revisions of the repository and are
2493 very useful to compare different revision, to go back to significant
2493 very useful to compare different revision, to go back to significant
2494 earlier versions or to mark branch points as releases, etc.
2494 earlier versions or to mark branch points as releases, etc.
2495
2495
2496 If no revision is given, the parent of the working directory is used,
2496 If no revision is given, the parent of the working directory is used,
2497 or tip if no revision is checked out.
2497 or tip if no revision is checked out.
2498
2498
2499 To facilitate version control, distribution, and merging of tags,
2499 To facilitate version control, distribution, and merging of tags,
2500 they are stored as a file named ".hgtags" which is managed
2500 they are stored as a file named ".hgtags" which is managed
2501 similarly to other project files and can be hand-edited if
2501 similarly to other project files and can be hand-edited if
2502 necessary. The file '.hg/localtags' is used for local tags (not
2502 necessary. The file '.hg/localtags' is used for local tags (not
2503 shared among repositories).
2503 shared among repositories).
2504 """
2504 """
2505 if name in ['tip', '.', 'null']:
2505 if name in ['tip', '.', 'null']:
2506 raise util.Abort(_("the name '%s' is reserved") % name)
2506 raise util.Abort(_("the name '%s' is reserved") % name)
2507 if rev_ is not None:
2507 if rev_ is not None:
2508 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2508 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2509 "please use 'hg tag [-r REV] NAME' instead\n"))
2509 "please use 'hg tag [-r REV] NAME' instead\n"))
2510 if opts['rev']:
2510 if opts['rev']:
2511 raise util.Abort(_("use only one form to specify the revision"))
2511 raise util.Abort(_("use only one form to specify the revision"))
2512 if opts['rev'] and opts['remove']:
2512 if opts['rev'] and opts['remove']:
2513 raise util.Abort(_("--rev and --remove are incompatible"))
2513 raise util.Abort(_("--rev and --remove are incompatible"))
2514 if opts['rev']:
2514 if opts['rev']:
2515 rev_ = opts['rev']
2515 rev_ = opts['rev']
2516 message = opts['message']
2516 message = opts['message']
2517 if opts['remove']:
2517 if opts['remove']:
2518 if not name in repo.tags():
2518 if not name in repo.tags():
2519 raise util.Abort(_('tag %s does not exist') % name)
2519 raise util.Abort(_('tag %s does not exist') % name)
2520 rev_ = nullid
2520 rev_ = nullid
2521 if not message:
2521 if not message:
2522 message = _('Removed tag %s') % name
2522 message = _('Removed tag %s') % name
2523 elif name in repo.tags() and not opts['force']:
2523 elif name in repo.tags() and not opts['force']:
2524 raise util.Abort(_('a tag named %s already exists (use -f to force)')
2524 raise util.Abort(_('a tag named %s already exists (use -f to force)')
2525 % name)
2525 % name)
2526 if not rev_ and repo.dirstate.parents()[1] != nullid:
2526 if not rev_ and repo.dirstate.parents()[1] != nullid:
2527 raise util.Abort(_('uncommitted merge - please provide a '
2527 raise util.Abort(_('uncommitted merge - please provide a '
2528 'specific revision'))
2528 'specific revision'))
2529 r = repo.changectx(rev_).node()
2529 r = repo.changectx(rev_).node()
2530
2530
2531 if not message:
2531 if not message:
2532 message = _('Added tag %s for changeset %s') % (name, short(r))
2532 message = _('Added tag %s for changeset %s') % (name, short(r))
2533
2533
2534 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2534 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2535
2535
2536 def tags(ui, repo):
2536 def tags(ui, repo):
2537 """list repository tags
2537 """list repository tags
2538
2538
2539 List the repository tags.
2539 List the repository tags.
2540
2540
2541 This lists both regular and local tags.
2541 This lists both regular and local tags.
2542 """
2542 """
2543
2543
2544 l = repo.tagslist()
2544 l = repo.tagslist()
2545 l.reverse()
2545 l.reverse()
2546 hexfunc = ui.debugflag and hex or short
2546 hexfunc = ui.debugflag and hex or short
2547 for t, n in l:
2547 for t, n in l:
2548 try:
2548 try:
2549 hn = hexfunc(n)
2549 hn = hexfunc(n)
2550 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2550 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2551 except revlog.LookupError:
2551 except revlog.LookupError:
2552 r = " ?:%s" % hn
2552 r = " ?:%s" % hn
2553 if ui.quiet:
2553 if ui.quiet:
2554 ui.write("%s\n" % t)
2554 ui.write("%s\n" % t)
2555 else:
2555 else:
2556 spaces = " " * (30 - util.locallen(t))
2556 spaces = " " * (30 - util.locallen(t))
2557 ui.write("%s%s %s\n" % (t, spaces, r))
2557 ui.write("%s%s %s\n" % (t, spaces, r))
2558
2558
2559 def tip(ui, repo, **opts):
2559 def tip(ui, repo, **opts):
2560 """show the tip revision
2560 """show the tip revision
2561
2561
2562 Show the tip revision.
2562 Show the tip revision.
2563 """
2563 """
2564 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2564 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2565
2565
2566 def unbundle(ui, repo, fname, **opts):
2566 def unbundle(ui, repo, fname, **opts):
2567 """apply a changegroup file
2567 """apply a changegroup file
2568
2568
2569 Apply a compressed changegroup file generated by the bundle
2569 Apply a compressed changegroup file generated by the bundle
2570 command.
2570 command.
2571 """
2571 """
2572 if os.path.exists(fname):
2572 if os.path.exists(fname):
2573 f = open(fname, "rb")
2573 f = open(fname, "rb")
2574 else:
2574 else:
2575 f = urllib.urlopen(fname)
2575 f = urllib.urlopen(fname)
2576 gen = changegroup.readbundle(f, fname)
2576 gen = changegroup.readbundle(f, fname)
2577 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2577 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2578 return postincoming(ui, repo, modheads, opts['update'])
2578 return postincoming(ui, repo, modheads, opts['update'])
2579
2579
2580 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2580 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2581 """update working directory
2581 """update working directory
2582
2582
2583 Update the working directory to the specified revision, or the
2583 Update the working directory to the specified revision, or the
2584 tip of the current branch if none is specified.
2584 tip of the current branch if none is specified.
2585
2585
2586 If there are no outstanding changes in the working directory and
2586 If there are no outstanding changes in the working directory and
2587 there is a linear relationship between the current version and the
2587 there is a linear relationship between the current version and the
2588 requested version, the result is the requested version.
2588 requested version, the result is the requested version.
2589
2589
2590 To merge the working directory with another revision, use the
2590 To merge the working directory with another revision, use the
2591 merge command.
2591 merge command.
2592
2592
2593 By default, update will refuse to run if doing so would require
2593 By default, update will refuse to run if doing so would require
2594 discarding local changes.
2594 discarding local changes.
2595 """
2595 """
2596 if rev and node:
2596 if rev and node:
2597 raise util.Abort(_("please specify just one revision"))
2597 raise util.Abort(_("please specify just one revision"))
2598
2598
2599 if not rev:
2599 if not rev:
2600 rev = node
2600 rev = node
2601
2601
2602 if date:
2602 if date:
2603 if rev:
2603 if rev:
2604 raise util.Abort(_("you can't specify a revision and a date"))
2604 raise util.Abort(_("you can't specify a revision and a date"))
2605 rev = cmdutil.finddate(ui, repo, date)
2605 rev = cmdutil.finddate(ui, repo, date)
2606
2606
2607 if clean:
2607 if clean:
2608 return hg.clean(repo, rev)
2608 return hg.clean(repo, rev)
2609 else:
2609 else:
2610 return hg.update(repo, rev)
2610 return hg.update(repo, rev)
2611
2611
2612 def verify(ui, repo):
2612 def verify(ui, repo):
2613 """verify the integrity of the repository
2613 """verify the integrity of the repository
2614
2614
2615 Verify the integrity of the current repository.
2615 Verify the integrity of the current repository.
2616
2616
2617 This will perform an extensive check of the repository's
2617 This will perform an extensive check of the repository's
2618 integrity, validating the hashes and checksums of each entry in
2618 integrity, validating the hashes and checksums of each entry in
2619 the changelog, manifest, and tracked files, as well as the
2619 the changelog, manifest, and tracked files, as well as the
2620 integrity of their crosslinks and indices.
2620 integrity of their crosslinks and indices.
2621 """
2621 """
2622 return hg.verify(repo)
2622 return hg.verify(repo)
2623
2623
2624 def version_(ui):
2624 def version_(ui):
2625 """output version and copyright information"""
2625 """output version and copyright information"""
2626 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2626 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2627 % version.get_version())
2627 % version.get_version())
2628 ui.status(_(
2628 ui.status(_(
2629 "\nCopyright (C) 2005-2007 Matt Mackall <mpm@selenic.com> and others\n"
2629 "\nCopyright (C) 2005-2007 Matt Mackall <mpm@selenic.com> and others\n"
2630 "This is free software; see the source for copying conditions. "
2630 "This is free software; see the source for copying conditions. "
2631 "There is NO\nwarranty; "
2631 "There is NO\nwarranty; "
2632 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2632 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2633 ))
2633 ))
2634
2634
2635 # Command options and aliases are listed here, alphabetically
2635 # Command options and aliases are listed here, alphabetically
2636
2636
2637 globalopts = [
2637 globalopts = [
2638 ('R', 'repository', '',
2638 ('R', 'repository', '',
2639 _('repository root directory or symbolic path name')),
2639 _('repository root directory or symbolic path name')),
2640 ('', 'cwd', '', _('change working directory')),
2640 ('', 'cwd', '', _('change working directory')),
2641 ('y', 'noninteractive', None,
2641 ('y', 'noninteractive', None,
2642 _('do not prompt, assume \'yes\' for any required answers')),
2642 _('do not prompt, assume \'yes\' for any required answers')),
2643 ('q', 'quiet', None, _('suppress output')),
2643 ('q', 'quiet', None, _('suppress output')),
2644 ('v', 'verbose', None, _('enable additional output')),
2644 ('v', 'verbose', None, _('enable additional output')),
2645 ('', 'config', [], _('set/override config option')),
2645 ('', 'config', [], _('set/override config option')),
2646 ('', 'debug', None, _('enable debugging output')),
2646 ('', 'debug', None, _('enable debugging output')),
2647 ('', 'debugger', None, _('start debugger')),
2647 ('', 'debugger', None, _('start debugger')),
2648 ('', 'encoding', util._encoding, _('set the charset encoding')),
2648 ('', 'encoding', util._encoding, _('set the charset encoding')),
2649 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2649 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2650 ('', 'lsprof', None, _('print improved command execution profile')),
2650 ('', 'lsprof', None, _('print improved command execution profile')),
2651 ('', 'traceback', None, _('print traceback on exception')),
2651 ('', 'traceback', None, _('print traceback on exception')),
2652 ('', 'time', None, _('time how long the command takes')),
2652 ('', 'time', None, _('time how long the command takes')),
2653 ('', 'profile', None, _('print command execution profile')),
2653 ('', 'profile', None, _('print command execution profile')),
2654 ('', 'version', None, _('output version information and exit')),
2654 ('', 'version', None, _('output version information and exit')),
2655 ('h', 'help', None, _('display help and exit')),
2655 ('h', 'help', None, _('display help and exit')),
2656 ]
2656 ]
2657
2657
2658 dryrunopts = [('n', 'dry-run', None,
2658 dryrunopts = [('n', 'dry-run', None,
2659 _('do not perform actions, just print output'))]
2659 _('do not perform actions, just print output'))]
2660
2660
2661 remoteopts = [
2661 remoteopts = [
2662 ('e', 'ssh', '', _('specify ssh command to use')),
2662 ('e', 'ssh', '', _('specify ssh command to use')),
2663 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2663 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2664 ]
2664 ]
2665
2665
2666 walkopts = [
2666 walkopts = [
2667 ('I', 'include', [], _('include names matching the given patterns')),
2667 ('I', 'include', [], _('include names matching the given patterns')),
2668 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2668 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2669 ]
2669 ]
2670
2670
2671 commitopts = [
2671 commitopts = [
2672 ('m', 'message', '', _('use <text> as commit message')),
2672 ('m', 'message', '', _('use <text> as commit message')),
2673 ('l', 'logfile', '', _('read commit message from <file>')),
2673 ('l', 'logfile', '', _('read commit message from <file>')),
2674 ]
2674 ]
2675
2675
2676 table = {
2676 table = {
2677 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2677 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2678 "addremove":
2678 "addremove":
2679 (addremove,
2679 (addremove,
2680 [('s', 'similarity', '',
2680 [('s', 'similarity', '',
2681 _('guess renamed files by similarity (0<=s<=100)')),
2681 _('guess renamed files by similarity (0<=s<=100)')),
2682 ] + walkopts + dryrunopts,
2682 ] + walkopts + dryrunopts,
2683 _('hg addremove [OPTION]... [FILE]...')),
2683 _('hg addremove [OPTION]... [FILE]...')),
2684 "^annotate":
2684 "^annotate":
2685 (annotate,
2685 (annotate,
2686 [('r', 'rev', '', _('annotate the specified revision')),
2686 [('r', 'rev', '', _('annotate the specified revision')),
2687 ('f', 'follow', None, _('follow file copies and renames')),
2687 ('f', 'follow', None, _('follow file copies and renames')),
2688 ('a', 'text', None, _('treat all files as text')),
2688 ('a', 'text', None, _('treat all files as text')),
2689 ('u', 'user', None, _('list the author')),
2689 ('u', 'user', None, _('list the author')),
2690 ('d', 'date', None, _('list the date')),
2690 ('d', 'date', None, _('list the date')),
2691 ('n', 'number', None, _('list the revision number (default)')),
2691 ('n', 'number', None, _('list the revision number (default)')),
2692 ('c', 'changeset', None, _('list the changeset')),
2692 ('c', 'changeset', None, _('list the changeset')),
2693 ] + walkopts,
2693 ] + walkopts,
2694 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] FILE...')),
2694 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] FILE...')),
2695 "archive":
2695 "archive":
2696 (archive,
2696 (archive,
2697 [('', 'no-decode', None, _('do not pass files through decoders')),
2697 [('', 'no-decode', None, _('do not pass files through decoders')),
2698 ('p', 'prefix', '', _('directory prefix for files in archive')),
2698 ('p', 'prefix', '', _('directory prefix for files in archive')),
2699 ('r', 'rev', '', _('revision to distribute')),
2699 ('r', 'rev', '', _('revision to distribute')),
2700 ('t', 'type', '', _('type of distribution to create')),
2700 ('t', 'type', '', _('type of distribution to create')),
2701 ] + walkopts,
2701 ] + walkopts,
2702 _('hg archive [OPTION]... DEST')),
2702 _('hg archive [OPTION]... DEST')),
2703 "backout":
2703 "backout":
2704 (backout,
2704 (backout,
2705 [('', 'merge', None,
2705 [('', 'merge', None,
2706 _('merge with old dirstate parent after backout')),
2706 _('merge with old dirstate parent after backout')),
2707 ('d', 'date', '', _('record datecode as commit date')),
2707 ('d', 'date', '', _('record datecode as commit date')),
2708 ('', 'parent', '', _('parent to choose when backing out merge')),
2708 ('', 'parent', '', _('parent to choose when backing out merge')),
2709 ('u', 'user', '', _('record user as committer')),
2709 ('u', 'user', '', _('record user as committer')),
2710 ('r', 'rev', '', _('revision to backout')),
2710 ('r', 'rev', '', _('revision to backout')),
2711 ] + walkopts + commitopts,
2711 ] + walkopts + commitopts,
2712 _('hg backout [OPTION]... [-r] REV')),
2712 _('hg backout [OPTION]... [-r] REV')),
2713 "branch": (branch,
2713 "branch": (branch,
2714 [('f', 'force', None,
2714 [('f', 'force', None,
2715 _('set branch name even if it shadows an existing branch'))],
2715 _('set branch name even if it shadows an existing branch'))],
2716 _('hg branch [NAME]')),
2716 _('hg branch [NAME]')),
2717 "branches": (branches, [], _('hg branches')),
2717 "branches": (branches, [], _('hg branches')),
2718 "bundle":
2718 "bundle":
2719 (bundle,
2719 (bundle,
2720 [('f', 'force', None,
2720 [('f', 'force', None,
2721 _('run even when remote repository is unrelated')),
2721 _('run even when remote repository is unrelated')),
2722 ('r', 'rev', [],
2722 ('r', 'rev', [],
2723 _('a changeset you would like to bundle')),
2723 _('a changeset you would like to bundle')),
2724 ('', 'base', [],
2724 ('', 'base', [],
2725 _('a base changeset to specify instead of a destination')),
2725 _('a base changeset to specify instead of a destination')),
2726 ] + remoteopts,
2726 ] + remoteopts,
2727 _('hg bundle [-f] [-r REV]... [--base REV]... FILE [DEST]')),
2727 _('hg bundle [-f] [-r REV]... [--base REV]... FILE [DEST]')),
2728 "cat":
2728 "cat":
2729 (cat,
2729 (cat,
2730 [('o', 'output', '', _('print output to file with formatted name')),
2730 [('o', 'output', '', _('print output to file with formatted name')),
2731 ('r', 'rev', '', _('print the given revision')),
2731 ('r', 'rev', '', _('print the given revision')),
2732 ] + walkopts,
2732 ] + walkopts,
2733 _('hg cat [OPTION]... FILE...')),
2733 _('hg cat [OPTION]... FILE...')),
2734 "^clone":
2734 "^clone":
2735 (clone,
2735 (clone,
2736 [('U', 'noupdate', None, _('do not update the new working directory')),
2736 [('U', 'noupdate', None, _('do not update the new working directory')),
2737 ('r', 'rev', [],
2737 ('r', 'rev', [],
2738 _('a changeset you would like to have after cloning')),
2738 _('a changeset you would like to have after cloning')),
2739 ('', 'pull', None, _('use pull protocol to copy metadata')),
2739 ('', 'pull', None, _('use pull protocol to copy metadata')),
2740 ('', 'uncompressed', None,
2740 ('', 'uncompressed', None,
2741 _('use uncompressed transfer (fast over LAN)')),
2741 _('use uncompressed transfer (fast over LAN)')),
2742 ] + remoteopts,
2742 ] + remoteopts,
2743 _('hg clone [OPTION]... SOURCE [DEST]')),
2743 _('hg clone [OPTION]... SOURCE [DEST]')),
2744 "^commit|ci":
2744 "^commit|ci":
2745 (commit,
2745 (commit,
2746 [('A', 'addremove', None,
2746 [('A', 'addremove', None,
2747 _('mark new/missing files as added/removed before committing')),
2747 _('mark new/missing files as added/removed before committing')),
2748 ('d', 'date', '', _('record datecode as commit date')),
2748 ('d', 'date', '', _('record datecode as commit date')),
2749 ('u', 'user', '', _('record user as commiter')),
2749 ('u', 'user', '', _('record user as commiter')),
2750 ] + walkopts + commitopts,
2750 ] + walkopts + commitopts,
2751 _('hg commit [OPTION]... [FILE]...')),
2751 _('hg commit [OPTION]... [FILE]...')),
2752 "copy|cp":
2752 "copy|cp":
2753 (copy,
2753 (copy,
2754 [('A', 'after', None, _('record a copy that has already occurred')),
2754 [('A', 'after', None, _('record a copy that has already occurred')),
2755 ('f', 'force', None,
2755 ('f', 'force', None,
2756 _('forcibly copy over an existing managed file')),
2756 _('forcibly copy over an existing managed file')),
2757 ] + walkopts + dryrunopts,
2757 ] + walkopts + dryrunopts,
2758 _('hg copy [OPTION]... [SOURCE]... DEST')),
2758 _('hg copy [OPTION]... [SOURCE]... DEST')),
2759 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2759 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2760 "debugcomplete":
2760 "debugcomplete":
2761 (debugcomplete,
2761 (debugcomplete,
2762 [('o', 'options', None, _('show the command options'))],
2762 [('o', 'options', None, _('show the command options'))],
2763 _('debugcomplete [-o] CMD')),
2763 _('debugcomplete [-o] CMD')),
2764 "debuginstall": (debuginstall, [], _('debuginstall')),
2764 "debuginstall": (debuginstall, [], _('debuginstall')),
2765 "debugrebuildstate":
2765 "debugrebuildstate":
2766 (debugrebuildstate,
2766 (debugrebuildstate,
2767 [('r', 'rev', '', _('revision to rebuild to'))],
2767 [('r', 'rev', '', _('revision to rebuild to'))],
2768 _('debugrebuildstate [-r REV] [REV]')),
2768 _('debugrebuildstate [-r REV] [REV]')),
2769 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2769 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2770 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2770 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2771 "debugstate": (debugstate, [], _('debugstate')),
2771 "debugstate": (debugstate, [], _('debugstate')),
2772 "debugdate":
2772 "debugdate":
2773 (debugdate,
2773 (debugdate,
2774 [('e', 'extended', None, _('try extended date formats'))],
2774 [('e', 'extended', None, _('try extended date formats'))],
2775 _('debugdate [-e] DATE [RANGE]')),
2775 _('debugdate [-e] DATE [RANGE]')),
2776 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2776 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2777 "debugindex": (debugindex, [], _('debugindex FILE')),
2777 "debugindex": (debugindex, [], _('debugindex FILE')),
2778 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2778 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2779 "debugrename": (debugrename,
2779 "debugrename": (debugrename,
2780 [('r', 'rev', '', _('revision to debug'))],
2780 [('r', 'rev', '', _('revision to debug'))],
2781 _('debugrename [-r REV] FILE')),
2781 _('debugrename [-r REV] FILE')),
2782 "debugwalk": (debugwalk, walkopts, _('debugwalk [OPTION]... [FILE]...')),
2782 "debugwalk": (debugwalk, walkopts, _('debugwalk [OPTION]... [FILE]...')),
2783 "^diff":
2783 "^diff":
2784 (diff,
2784 (diff,
2785 [('r', 'rev', [], _('revision')),
2785 [('r', 'rev', [], _('revision')),
2786 ('a', 'text', None, _('treat all files as text')),
2786 ('a', 'text', None, _('treat all files as text')),
2787 ('p', 'show-function', None,
2787 ('p', 'show-function', None,
2788 _('show which function each change is in')),
2788 _('show which function each change is in')),
2789 ('g', 'git', None, _('use git extended diff format')),
2789 ('g', 'git', None, _('use git extended diff format')),
2790 ('', 'nodates', None, _("don't include dates in diff headers")),
2790 ('', 'nodates', None, _("don't include dates in diff headers")),
2791 ('w', 'ignore-all-space', None,
2791 ('w', 'ignore-all-space', None,
2792 _('ignore white space when comparing lines')),
2792 _('ignore white space when comparing lines')),
2793 ('b', 'ignore-space-change', None,
2793 ('b', 'ignore-space-change', None,
2794 _('ignore changes in the amount of white space')),
2794 _('ignore changes in the amount of white space')),
2795 ('B', 'ignore-blank-lines', None,
2795 ('B', 'ignore-blank-lines', None,
2796 _('ignore changes whose lines are all blank')),
2796 _('ignore changes whose lines are all blank')),
2797 ] + walkopts,
2797 ] + walkopts,
2798 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
2798 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
2799 "^export":
2799 "^export":
2800 (export,
2800 (export,
2801 [('o', 'output', '', _('print output to file with formatted name')),
2801 [('o', 'output', '', _('print output to file with formatted name')),
2802 ('a', 'text', None, _('treat all files as text')),
2802 ('a', 'text', None, _('treat all files as text')),
2803 ('g', 'git', None, _('use git extended diff format')),
2803 ('g', 'git', None, _('use git extended diff format')),
2804 ('', 'nodates', None, _("don't include dates in diff headers")),
2804 ('', 'nodates', None, _("don't include dates in diff headers")),
2805 ('', 'switch-parent', None, _('diff against the second parent'))],
2805 ('', 'switch-parent', None, _('diff against the second parent'))],
2806 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
2806 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
2807 "grep":
2807 "grep":
2808 (grep,
2808 (grep,
2809 [('0', 'print0', None, _('end fields with NUL')),
2809 [('0', 'print0', None, _('end fields with NUL')),
2810 ('', 'all', None, _('print all revisions that match')),
2810 ('', 'all', None, _('print all revisions that match')),
2811 ('f', 'follow', None,
2811 ('f', 'follow', None,
2812 _('follow changeset history, or file history across copies and renames')),
2812 _('follow changeset history, or file history across copies and renames')),
2813 ('i', 'ignore-case', None, _('ignore case when matching')),
2813 ('i', 'ignore-case', None, _('ignore case when matching')),
2814 ('l', 'files-with-matches', None,
2814 ('l', 'files-with-matches', None,
2815 _('print only filenames and revs that match')),
2815 _('print only filenames and revs that match')),
2816 ('n', 'line-number', None, _('print matching line numbers')),
2816 ('n', 'line-number', None, _('print matching line numbers')),
2817 ('r', 'rev', [], _('search in given revision range')),
2817 ('r', 'rev', [], _('search in given revision range')),
2818 ('u', 'user', None, _('print user who committed change')),
2818 ('u', 'user', None, _('print user who committed change')),
2819 ] + walkopts,
2819 ] + walkopts,
2820 _('hg grep [OPTION]... PATTERN [FILE]...')),
2820 _('hg grep [OPTION]... PATTERN [FILE]...')),
2821 "heads":
2821 "heads":
2822 (heads,
2822 (heads,
2823 [('', 'style', '', _('display using template map file')),
2823 [('', 'style', '', _('display using template map file')),
2824 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2824 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2825 ('', 'template', '', _('display with template'))],
2825 ('', 'template', '', _('display with template'))],
2826 _('hg heads [-r REV] [REV]...')),
2826 _('hg heads [-r REV] [REV]...')),
2827 "help": (help_, [], _('hg help [COMMAND]')),
2827 "help": (help_, [], _('hg help [COMMAND]')),
2828 "identify|id": (identify, [], _('hg identify')),
2828 "identify|id": (identify, [], _('hg identify')),
2829 "import|patch":
2829 "import|patch":
2830 (import_,
2830 (import_,
2831 [('p', 'strip', 1,
2831 [('p', 'strip', 1,
2832 _('directory strip option for patch. This has the same\n'
2832 _('directory strip option for patch. This has the same\n'
2833 'meaning as the corresponding patch option')),
2833 'meaning as the corresponding patch option')),
2834 ('b', 'base', '', _('base path')),
2834 ('b', 'base', '', _('base path')),
2835 ('f', 'force', None,
2835 ('f', 'force', None,
2836 _('skip check for outstanding uncommitted changes')),
2836 _('skip check for outstanding uncommitted changes')),
2837 ('', 'exact', None,
2837 ('', 'exact', None,
2838 _('apply patch to the nodes from which it was generated')),
2838 _('apply patch to the nodes from which it was generated')),
2839 ('', 'import-branch', None,
2839 ('', 'import-branch', None,
2840 _('Use any branch information in patch (implied by --exact)'))] + commitopts,
2840 _('Use any branch information in patch (implied by --exact)'))] + commitopts,
2841 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
2841 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
2842 "incoming|in": (incoming,
2842 "incoming|in": (incoming,
2843 [('M', 'no-merges', None, _('do not show merges')),
2843 [('M', 'no-merges', None, _('do not show merges')),
2844 ('f', 'force', None,
2844 ('f', 'force', None,
2845 _('run even when remote repository is unrelated')),
2845 _('run even when remote repository is unrelated')),
2846 ('', 'style', '', _('display using template map file')),
2846 ('', 'style', '', _('display using template map file')),
2847 ('n', 'newest-first', None, _('show newest record first')),
2847 ('n', 'newest-first', None, _('show newest record first')),
2848 ('', 'bundle', '', _('file to store the bundles into')),
2848 ('', 'bundle', '', _('file to store the bundles into')),
2849 ('p', 'patch', None, _('show patch')),
2849 ('p', 'patch', None, _('show patch')),
2850 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2850 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2851 ('', 'template', '', _('display with template')),
2851 ('', 'template', '', _('display with template')),
2852 ] + remoteopts,
2852 ] + remoteopts,
2853 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
2853 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
2854 ' [--bundle FILENAME] [SOURCE]')),
2854 ' [--bundle FILENAME] [SOURCE]')),
2855 "^init":
2855 "^init":
2856 (init,
2856 (init,
2857 remoteopts,
2857 remoteopts,
2858 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
2858 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
2859 "locate":
2859 "locate":
2860 (locate,
2860 (locate,
2861 [('r', 'rev', '', _('search the repository as it stood at rev')),
2861 [('r', 'rev', '', _('search the repository as it stood at rev')),
2862 ('0', 'print0', None,
2862 ('0', 'print0', None,
2863 _('end filenames with NUL, for use with xargs')),
2863 _('end filenames with NUL, for use with xargs')),
2864 ('f', 'fullpath', None,
2864 ('f', 'fullpath', None,
2865 _('print complete paths from the filesystem root')),
2865 _('print complete paths from the filesystem root')),
2866 ] + walkopts,
2866 ] + walkopts,
2867 _('hg locate [OPTION]... [PATTERN]...')),
2867 _('hg locate [OPTION]... [PATTERN]...')),
2868 "^log|history":
2868 "^log|history":
2869 (log,
2869 (log,
2870 [('f', 'follow', None,
2870 [('f', 'follow', None,
2871 _('follow changeset history, or file history across copies and renames')),
2871 _('follow changeset history, or file history across copies and renames')),
2872 ('', 'follow-first', None,
2872 ('', 'follow-first', None,
2873 _('only follow the first parent of merge changesets')),
2873 _('only follow the first parent of merge changesets')),
2874 ('d', 'date', '', _('show revs matching date spec')),
2874 ('d', 'date', '', _('show revs matching date spec')),
2875 ('C', 'copies', None, _('show copied files')),
2875 ('C', 'copies', None, _('show copied files')),
2876 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
2876 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
2877 ('l', 'limit', '', _('limit number of changes displayed')),
2877 ('l', 'limit', '', _('limit number of changes displayed')),
2878 ('r', 'rev', [], _('show the specified revision or range')),
2878 ('r', 'rev', [], _('show the specified revision or range')),
2879 ('', 'removed', None, _('include revs where files were removed')),
2879 ('', 'removed', None, _('include revs where files were removed')),
2880 ('M', 'no-merges', None, _('do not show merges')),
2880 ('M', 'no-merges', None, _('do not show merges')),
2881 ('', 'style', '', _('display using template map file')),
2881 ('', 'style', '', _('display using template map file')),
2882 ('m', 'only-merges', None, _('show only merges')),
2882 ('m', 'only-merges', None, _('show only merges')),
2883 ('p', 'patch', None, _('show patch')),
2883 ('p', 'patch', None, _('show patch')),
2884 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2884 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2885 ('', 'template', '', _('display with template')),
2885 ('', 'template', '', _('display with template')),
2886 ] + walkopts,
2886 ] + walkopts,
2887 _('hg log [OPTION]... [FILE]')),
2887 _('hg log [OPTION]... [FILE]')),
2888 "manifest": (manifest, [], _('hg manifest [REV]')),
2888 "manifest": (manifest, [], _('hg manifest [REV]')),
2889 "^merge":
2889 "^merge":
2890 (merge,
2890 (merge,
2891 [('f', 'force', None, _('force a merge with outstanding changes')),
2891 [('f', 'force', None, _('force a merge with outstanding changes')),
2892 ('r', 'rev', '', _('revision to merge')),
2892 ('r', 'rev', '', _('revision to merge')),
2893 ],
2893 ],
2894 _('hg merge [-f] [[-r] REV]')),
2894 _('hg merge [-f] [[-r] REV]')),
2895 "outgoing|out": (outgoing,
2895 "outgoing|out": (outgoing,
2896 [('M', 'no-merges', None, _('do not show merges')),
2896 [('M', 'no-merges', None, _('do not show merges')),
2897 ('f', 'force', None,
2897 ('f', 'force', None,
2898 _('run even when remote repository is unrelated')),
2898 _('run even when remote repository is unrelated')),
2899 ('p', 'patch', None, _('show patch')),
2899 ('p', 'patch', None, _('show patch')),
2900 ('', 'style', '', _('display using template map file')),
2900 ('', 'style', '', _('display using template map file')),
2901 ('r', 'rev', [], _('a specific revision you would like to push')),
2901 ('r', 'rev', [], _('a specific revision you would like to push')),
2902 ('n', 'newest-first', None, _('show newest record first')),
2902 ('n', 'newest-first', None, _('show newest record first')),
2903 ('', 'template', '', _('display with template')),
2903 ('', 'template', '', _('display with template')),
2904 ] + remoteopts,
2904 ] + remoteopts,
2905 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
2905 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
2906 "^parents":
2906 "^parents":
2907 (parents,
2907 (parents,
2908 [('r', 'rev', '', _('show parents from the specified rev')),
2908 [('r', 'rev', '', _('show parents from the specified rev')),
2909 ('', 'style', '', _('display using template map file')),
2909 ('', 'style', '', _('display using template map file')),
2910 ('', 'template', '', _('display with template'))],
2910 ('', 'template', '', _('display with template'))],
2911 _('hg parents [-r REV] [FILE]')),
2911 _('hg parents [-r REV] [FILE]')),
2912 "paths": (paths, [], _('hg paths [NAME]')),
2912 "paths": (paths, [], _('hg paths [NAME]')),
2913 "^pull":
2913 "^pull":
2914 (pull,
2914 (pull,
2915 [('u', 'update', None,
2915 [('u', 'update', None,
2916 _('update to new tip if changesets were pulled')),
2916 _('update to new tip if changesets were pulled')),
2917 ('f', 'force', None,
2917 ('f', 'force', None,
2918 _('run even when remote repository is unrelated')),
2918 _('run even when remote repository is unrelated')),
2919 ('r', 'rev', [],
2919 ('r', 'rev', [],
2920 _('a specific revision up to which you would like to pull')),
2920 _('a specific revision up to which you would like to pull')),
2921 ] + remoteopts,
2921 ] + remoteopts,
2922 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
2922 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
2923 "^push":
2923 "^push":
2924 (push,
2924 (push,
2925 [('f', 'force', None, _('force push')),
2925 [('f', 'force', None, _('force push')),
2926 ('r', 'rev', [], _('a specific revision you would like to push')),
2926 ('r', 'rev', [], _('a specific revision you would like to push')),
2927 ] + remoteopts,
2927 ] + remoteopts,
2928 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
2928 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
2929 "debugrawcommit|rawcommit":
2929 "debugrawcommit|rawcommit":
2930 (rawcommit,
2930 (rawcommit,
2931 [('p', 'parent', [], _('parent')),
2931 [('p', 'parent', [], _('parent')),
2932 ('d', 'date', '', _('date code')),
2932 ('d', 'date', '', _('date code')),
2933 ('u', 'user', '', _('user')),
2933 ('u', 'user', '', _('user')),
2934 ('F', 'files', '', _('file list'))
2934 ('F', 'files', '', _('file list'))
2935 ] + commitopts,
2935 ] + commitopts,
2936 _('hg debugrawcommit [OPTION]... [FILE]...')),
2936 _('hg debugrawcommit [OPTION]... [FILE]...')),
2937 "recover": (recover, [], _('hg recover')),
2937 "recover": (recover, [], _('hg recover')),
2938 "^remove|rm":
2938 "^remove|rm":
2939 (remove,
2939 (remove,
2940 [('A', 'after', None, _('record remove that has already occurred')),
2940 [('A', 'after', None, _('record remove that has already occurred')),
2941 ('f', 'force', None, _('remove file even if modified')),
2941 ('f', 'force', None, _('remove file even if modified')),
2942 ] + walkopts,
2942 ] + walkopts,
2943 _('hg remove [OPTION]... FILE...')),
2943 _('hg remove [OPTION]... FILE...')),
2944 "rename|mv":
2944 "rename|mv":
2945 (rename,
2945 (rename,
2946 [('A', 'after', None, _('record a rename that has already occurred')),
2946 [('A', 'after', None, _('record a rename that has already occurred')),
2947 ('f', 'force', None,
2947 ('f', 'force', None,
2948 _('forcibly copy over an existing managed file')),
2948 _('forcibly copy over an existing managed file')),
2949 ] + walkopts + dryrunopts,
2949 ] + walkopts + dryrunopts,
2950 _('hg rename [OPTION]... SOURCE... DEST')),
2950 _('hg rename [OPTION]... SOURCE... DEST')),
2951 "^revert":
2951 "^revert":
2952 (revert,
2952 (revert,
2953 [('a', 'all', None, _('revert all changes when no arguments given')),
2953 [('a', 'all', None, _('revert all changes when no arguments given')),
2954 ('d', 'date', '', _('tipmost revision matching date')),
2954 ('d', 'date', '', _('tipmost revision matching date')),
2955 ('r', 'rev', '', _('revision to revert to')),
2955 ('r', 'rev', '', _('revision to revert to')),
2956 ('', 'no-backup', None, _('do not save backup copies of files')),
2956 ('', 'no-backup', None, _('do not save backup copies of files')),
2957 ] + walkopts + dryrunopts,
2957 ] + walkopts + dryrunopts,
2958 _('hg revert [OPTION]... [-r REV] [NAME]...')),
2958 _('hg revert [OPTION]... [-r REV] [NAME]...')),
2959 "rollback": (rollback, [], _('hg rollback')),
2959 "rollback": (rollback, [], _('hg rollback')),
2960 "root": (root, [], _('hg root')),
2960 "root": (root, [], _('hg root')),
2961 "showconfig|debugconfig":
2961 "showconfig|debugconfig":
2962 (showconfig,
2962 (showconfig,
2963 [('u', 'untrusted', None, _('show untrusted configuration options'))],
2963 [('u', 'untrusted', None, _('show untrusted configuration options'))],
2964 _('showconfig [-u] [NAME]...')),
2964 _('showconfig [-u] [NAME]...')),
2965 "^serve":
2965 "^serve":
2966 (serve,
2966 (serve,
2967 [('A', 'accesslog', '', _('name of access log file to write to')),
2967 [('A', 'accesslog', '', _('name of access log file to write to')),
2968 ('d', 'daemon', None, _('run server in background')),
2968 ('d', 'daemon', None, _('run server in background')),
2969 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2969 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2970 ('E', 'errorlog', '', _('name of error log file to write to')),
2970 ('E', 'errorlog', '', _('name of error log file to write to')),
2971 ('p', 'port', 0, _('port to use (default: 8000)')),
2971 ('p', 'port', 0, _('port to use (default: 8000)')),
2972 ('a', 'address', '', _('address to use')),
2972 ('a', 'address', '', _('address to use')),
2973 ('n', 'name', '',
2973 ('n', 'name', '',
2974 _('name to show in web pages (default: working dir)')),
2974 _('name to show in web pages (default: working dir)')),
2975 ('', 'webdir-conf', '', _('name of the webdir config file'
2975 ('', 'webdir-conf', '', _('name of the webdir config file'
2976 ' (serve more than one repo)')),
2976 ' (serve more than one repo)')),
2977 ('', 'pid-file', '', _('name of file to write process ID to')),
2977 ('', 'pid-file', '', _('name of file to write process ID to')),
2978 ('', 'stdio', None, _('for remote clients')),
2978 ('', 'stdio', None, _('for remote clients')),
2979 ('t', 'templates', '', _('web templates to use')),
2979 ('t', 'templates', '', _('web templates to use')),
2980 ('', 'style', '', _('template style to use')),
2980 ('', 'style', '', _('template style to use')),
2981 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2981 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2982 _('hg serve [OPTION]...')),
2982 _('hg serve [OPTION]...')),
2983 "^status|st":
2983 "^status|st":
2984 (status,
2984 (status,
2985 [('A', 'all', None, _('show status of all files')),
2985 [('A', 'all', None, _('show status of all files')),
2986 ('m', 'modified', None, _('show only modified files')),
2986 ('m', 'modified', None, _('show only modified files')),
2987 ('a', 'added', None, _('show only added files')),
2987 ('a', 'added', None, _('show only added files')),
2988 ('r', 'removed', None, _('show only removed files')),
2988 ('r', 'removed', None, _('show only removed files')),
2989 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2989 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2990 ('c', 'clean', None, _('show only files without changes')),
2990 ('c', 'clean', None, _('show only files without changes')),
2991 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2991 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2992 ('i', 'ignored', None, _('show only ignored files')),
2992 ('i', 'ignored', None, _('show only ignored files')),
2993 ('n', 'no-status', None, _('hide status prefix')),
2993 ('n', 'no-status', None, _('hide status prefix')),
2994 ('C', 'copies', None, _('show source of copied files')),
2994 ('C', 'copies', None, _('show source of copied files')),
2995 ('0', 'print0', None,
2995 ('0', 'print0', None,
2996 _('end filenames with NUL, for use with xargs')),
2996 _('end filenames with NUL, for use with xargs')),
2997 ('', 'rev', [], _('show difference from revision')),
2997 ('', 'rev', [], _('show difference from revision')),
2998 ] + walkopts,
2998 ] + walkopts,
2999 _('hg status [OPTION]... [FILE]...')),
2999 _('hg status [OPTION]... [FILE]...')),
3000 "tag":
3000 "tag":
3001 (tag,
3001 (tag,
3002 [('f', 'force', None, _('replace existing tag')),
3002 [('f', 'force', None, _('replace existing tag')),
3003 ('l', 'local', None, _('make the tag local')),
3003 ('l', 'local', None, _('make the tag local')),
3004 ('m', 'message', '', _('message for tag commit log entry')),
3004 ('m', 'message', '', _('message for tag commit log entry')),
3005 ('d', 'date', '', _('record datecode as commit date')),
3005 ('d', 'date', '', _('record datecode as commit date')),
3006 ('u', 'user', '', _('record user as commiter')),
3006 ('u', 'user', '', _('record user as commiter')),
3007 ('r', 'rev', '', _('revision to tag')),
3007 ('r', 'rev', '', _('revision to tag')),
3008 ('', 'remove', None, _('remove a tag'))],
3008 ('', 'remove', None, _('remove a tag'))],
3009 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3009 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3010 "tags": (tags, [], _('hg tags')),
3010 "tags": (tags, [], _('hg tags')),
3011 "tip":
3011 "tip":
3012 (tip,
3012 (tip,
3013 [('', 'style', '', _('display using template map file')),
3013 [('', 'style', '', _('display using template map file')),
3014 ('p', 'patch', None, _('show patch')),
3014 ('p', 'patch', None, _('show patch')),
3015 ('', 'template', '', _('display with template'))],
3015 ('', 'template', '', _('display with template'))],
3016 _('hg tip [-p]')),
3016 _('hg tip [-p]')),
3017 "unbundle":
3017 "unbundle":
3018 (unbundle,
3018 (unbundle,
3019 [('u', 'update', None,
3019 [('u', 'update', None,
3020 _('update to new tip if changesets were unbundled'))],
3020 _('update to new tip if changesets were unbundled'))],
3021 _('hg unbundle [-u] FILE')),
3021 _('hg unbundle [-u] FILE')),
3022 "^update|up|checkout|co":
3022 "^update|up|checkout|co":
3023 (update,
3023 (update,
3024 [('C', 'clean', None, _('overwrite locally modified files')),
3024 [('C', 'clean', None, _('overwrite locally modified files')),
3025 ('d', 'date', '', _('tipmost revision matching date')),
3025 ('d', 'date', '', _('tipmost revision matching date')),
3026 ('r', 'rev', '', _('revision'))],
3026 ('r', 'rev', '', _('revision'))],
3027 _('hg update [-C] [-d DATE] [[-r] REV]')),
3027 _('hg update [-C] [-d DATE] [[-r] REV]')),
3028 "verify": (verify, [], _('hg verify')),
3028 "verify": (verify, [], _('hg verify')),
3029 "version": (version_, [], _('hg version')),
3029 "version": (version_, [], _('hg version')),
3030 }
3030 }
3031
3031
3032 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3032 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3033 " debugindex debugindexdot debugdate debuginstall")
3033 " debugindex debugindexdot debugdate debuginstall")
3034 optionalrepo = ("paths serve showconfig")
3034 optionalrepo = ("paths serve showconfig")
3035
3035
3036 def dispatch(args):
3036 def dispatch(args):
3037 try:
3037 try:
3038 u = ui.ui(traceback='--traceback' in args)
3038 u = ui.ui(traceback='--traceback' in args)
3039 except util.Abort, inst:
3039 except util.Abort, inst:
3040 sys.stderr.write(_("abort: %s\n") % inst)
3040 sys.stderr.write(_("abort: %s\n") % inst)
3041 return -1
3041 return -1
3042 return cmdutil.runcatch(u, args)
3042 return cmdutil.runcatch(u, args)
3043
3043
3044 def run():
3044 def run():
3045 sys.exit(dispatch(sys.argv[1:]))
3045 sys.exit(dispatch(sys.argv[1:]))
@@ -1,675 +1,675 b''
1 # patch.py - patch file parsing routines
1 # patch.py - patch file parsing routines
2 #
2 #
3 # Copyright 2006 Brendan Cully <brendan@kublai.com>
3 # Copyright 2006 Brendan Cully <brendan@kublai.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from i18n import _
8 from i18n import _
9 from node import *
9 from node import *
10 import base85, cmdutil, mdiff, util, context, revlog
10 import base85, cmdutil, mdiff, util, context, revlog
11 import cStringIO, email.Parser, os, popen2, re, sha
11 import cStringIO, email.Parser, os, popen2, re, sha
12 import sys, tempfile, zlib
12 import sys, tempfile, zlib
13
13
14 # helper functions
14 # helper functions
15
15
16 def copyfile(src, dst, basedir=None):
16 def copyfile(src, dst, basedir=None):
17 if not basedir:
17 if not basedir:
18 basedir = os.getcwd()
18 basedir = os.getcwd()
19
19
20 abssrc, absdst = [os.path.join(basedir, n) for n in (src, dst)]
20 abssrc, absdst = [os.path.join(basedir, n) for n in (src, dst)]
21 if os.path.exists(absdst):
21 if os.path.exists(absdst):
22 raise util.Abort(_("cannot create %s: destination already exists") %
22 raise util.Abort(_("cannot create %s: destination already exists") %
23 dst)
23 dst)
24
24
25 targetdir = os.path.dirname(absdst)
25 targetdir = os.path.dirname(absdst)
26 if not os.path.isdir(targetdir):
26 if not os.path.isdir(targetdir):
27 os.makedirs(targetdir)
27 os.makedirs(targetdir)
28
28
29 util.copyfile(abssrc, absdst)
29 util.copyfile(abssrc, absdst)
30
30
31 # public functions
31 # public functions
32
32
33 def extract(ui, fileobj):
33 def extract(ui, fileobj):
34 '''extract patch from data read from fileobj.
34 '''extract patch from data read from fileobj.
35
35
36 patch can be a normal patch or contained in an email message.
36 patch can be a normal patch or contained in an email message.
37
37
38 return tuple (filename, message, user, date, node, p1, p2).
38 return tuple (filename, message, user, date, node, p1, p2).
39 Any item in the returned tuple can be None. If filename is None,
39 Any item in the returned tuple can be None. If filename is None,
40 fileobj did not contain a patch. Caller must unlink filename when done.'''
40 fileobj did not contain a patch. Caller must unlink filename when done.'''
41
41
42 # attempt to detect the start of a patch
42 # attempt to detect the start of a patch
43 # (this heuristic is borrowed from quilt)
43 # (this heuristic is borrowed from quilt)
44 diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
44 diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
45 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
45 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
46 '(---|\*\*\*)[ \t])', re.MULTILINE)
46 '(---|\*\*\*)[ \t])', re.MULTILINE)
47
47
48 fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
48 fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
49 tmpfp = os.fdopen(fd, 'w')
49 tmpfp = os.fdopen(fd, 'w')
50 try:
50 try:
51 msg = email.Parser.Parser().parse(fileobj)
51 msg = email.Parser.Parser().parse(fileobj)
52
52
53 message = msg['Subject']
53 message = msg['Subject']
54 user = msg['From']
54 user = msg['From']
55 # should try to parse msg['Date']
55 # should try to parse msg['Date']
56 date = None
56 date = None
57 nodeid = None
57 nodeid = None
58 branch = None
58 branch = None
59 parents = []
59 parents = []
60
60
61 if message:
61 if message:
62 if message.startswith('[PATCH'):
62 if message.startswith('[PATCH'):
63 pend = message.find(']')
63 pend = message.find(']')
64 if pend >= 0:
64 if pend >= 0:
65 message = message[pend+1:].lstrip()
65 message = message[pend+1:].lstrip()
66 message = message.replace('\n\t', ' ')
66 message = message.replace('\n\t', ' ')
67 ui.debug('Subject: %s\n' % message)
67 ui.debug('Subject: %s\n' % message)
68 if user:
68 if user:
69 ui.debug('From: %s\n' % user)
69 ui.debug('From: %s\n' % user)
70 diffs_seen = 0
70 diffs_seen = 0
71 ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
71 ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
72
72
73 for part in msg.walk():
73 for part in msg.walk():
74 content_type = part.get_content_type()
74 content_type = part.get_content_type()
75 ui.debug('Content-Type: %s\n' % content_type)
75 ui.debug('Content-Type: %s\n' % content_type)
76 if content_type not in ok_types:
76 if content_type not in ok_types:
77 continue
77 continue
78 payload = part.get_payload(decode=True)
78 payload = part.get_payload(decode=True)
79 m = diffre.search(payload)
79 m = diffre.search(payload)
80 if m:
80 if m:
81 hgpatch = False
81 hgpatch = False
82 ignoretext = False
82 ignoretext = False
83
83
84 ui.debug(_('found patch at byte %d\n') % m.start(0))
84 ui.debug(_('found patch at byte %d\n') % m.start(0))
85 diffs_seen += 1
85 diffs_seen += 1
86 cfp = cStringIO.StringIO()
86 cfp = cStringIO.StringIO()
87 if message:
87 if message:
88 cfp.write(message)
88 cfp.write(message)
89 cfp.write('\n')
89 cfp.write('\n')
90 for line in payload[:m.start(0)].splitlines():
90 for line in payload[:m.start(0)].splitlines():
91 if line.startswith('# HG changeset patch'):
91 if line.startswith('# HG changeset patch'):
92 ui.debug(_('patch generated by hg export\n'))
92 ui.debug(_('patch generated by hg export\n'))
93 hgpatch = True
93 hgpatch = True
94 # drop earlier commit message content
94 # drop earlier commit message content
95 cfp.seek(0)
95 cfp.seek(0)
96 cfp.truncate()
96 cfp.truncate()
97 elif hgpatch:
97 elif hgpatch:
98 if line.startswith('# User '):
98 if line.startswith('# User '):
99 user = line[7:]
99 user = line[7:]
100 ui.debug('From: %s\n' % user)
100 ui.debug('From: %s\n' % user)
101 elif line.startswith("# Date "):
101 elif line.startswith("# Date "):
102 date = line[7:]
102 date = line[7:]
103 elif line.startswith("# Branch "):
103 elif line.startswith("# Branch "):
104 branch = line[9:]
104 branch = line[9:]
105 elif line.startswith("# Node ID "):
105 elif line.startswith("# Node ID "):
106 nodeid = line[10:]
106 nodeid = line[10:]
107 elif line.startswith("# Parent "):
107 elif line.startswith("# Parent "):
108 parents.append(line[10:])
108 parents.append(line[10:])
109 elif line == '---' and 'git-send-email' in msg['X-Mailer']:
109 elif line == '---' and 'git-send-email' in msg['X-Mailer']:
110 ignoretext = True
110 ignoretext = True
111 if not line.startswith('# ') and not ignoretext:
111 if not line.startswith('# ') and not ignoretext:
112 cfp.write(line)
112 cfp.write(line)
113 cfp.write('\n')
113 cfp.write('\n')
114 message = cfp.getvalue()
114 message = cfp.getvalue()
115 if tmpfp:
115 if tmpfp:
116 tmpfp.write(payload)
116 tmpfp.write(payload)
117 if not payload.endswith('\n'):
117 if not payload.endswith('\n'):
118 tmpfp.write('\n')
118 tmpfp.write('\n')
119 elif not diffs_seen and message and content_type == 'text/plain':
119 elif not diffs_seen and message and content_type == 'text/plain':
120 message += '\n' + payload
120 message += '\n' + payload
121 except:
121 except:
122 tmpfp.close()
122 tmpfp.close()
123 os.unlink(tmpname)
123 os.unlink(tmpname)
124 raise
124 raise
125
125
126 tmpfp.close()
126 tmpfp.close()
127 if not diffs_seen:
127 if not diffs_seen:
128 os.unlink(tmpname)
128 os.unlink(tmpname)
129 return None, message, user, date, branch, None, None, None
129 return None, message, user, date, branch, None, None, None
130 p1 = parents and parents.pop(0) or None
130 p1 = parents and parents.pop(0) or None
131 p2 = parents and parents.pop(0) or None
131 p2 = parents and parents.pop(0) or None
132 return tmpname, message, user, date, branch, nodeid, p1, p2
132 return tmpname, message, user, date, branch, nodeid, p1, p2
133
133
134 GP_PATCH = 1 << 0 # we have to run patch
134 GP_PATCH = 1 << 0 # we have to run patch
135 GP_FILTER = 1 << 1 # there's some copy/rename operation
135 GP_FILTER = 1 << 1 # there's some copy/rename operation
136 GP_BINARY = 1 << 2 # there's a binary patch
136 GP_BINARY = 1 << 2 # there's a binary patch
137
137
138 def readgitpatch(patchname):
138 def readgitpatch(patchname):
139 """extract git-style metadata about patches from <patchname>"""
139 """extract git-style metadata about patches from <patchname>"""
140 class gitpatch:
140 class gitpatch:
141 "op is one of ADD, DELETE, RENAME, MODIFY or COPY"
141 "op is one of ADD, DELETE, RENAME, MODIFY or COPY"
142 def __init__(self, path):
142 def __init__(self, path):
143 self.path = path
143 self.path = path
144 self.oldpath = None
144 self.oldpath = None
145 self.mode = None
145 self.mode = None
146 self.op = 'MODIFY'
146 self.op = 'MODIFY'
147 self.copymod = False
147 self.copymod = False
148 self.lineno = 0
148 self.lineno = 0
149 self.binary = False
149 self.binary = False
150
150
151 # Filter patch for git information
151 # Filter patch for git information
152 gitre = re.compile('diff --git a/(.*) b/(.*)')
152 gitre = re.compile('diff --git a/(.*) b/(.*)')
153 pf = file(patchname)
153 pf = file(patchname)
154 gp = None
154 gp = None
155 gitpatches = []
155 gitpatches = []
156 # Can have a git patch with only metadata, causing patch to complain
156 # Can have a git patch with only metadata, causing patch to complain
157 dopatch = 0
157 dopatch = 0
158
158
159 lineno = 0
159 lineno = 0
160 for line in pf:
160 for line in pf:
161 lineno += 1
161 lineno += 1
162 if line.startswith('diff --git'):
162 if line.startswith('diff --git'):
163 m = gitre.match(line)
163 m = gitre.match(line)
164 if m:
164 if m:
165 if gp:
165 if gp:
166 gitpatches.append(gp)
166 gitpatches.append(gp)
167 src, dst = m.group(1, 2)
167 src, dst = m.group(1, 2)
168 gp = gitpatch(dst)
168 gp = gitpatch(dst)
169 gp.lineno = lineno
169 gp.lineno = lineno
170 elif gp:
170 elif gp:
171 if line.startswith('--- '):
171 if line.startswith('--- '):
172 if gp.op in ('COPY', 'RENAME'):
172 if gp.op in ('COPY', 'RENAME'):
173 gp.copymod = True
173 gp.copymod = True
174 dopatch |= GP_FILTER
174 dopatch |= GP_FILTER
175 gitpatches.append(gp)
175 gitpatches.append(gp)
176 gp = None
176 gp = None
177 dopatch |= GP_PATCH
177 dopatch |= GP_PATCH
178 continue
178 continue
179 if line.startswith('rename from '):
179 if line.startswith('rename from '):
180 gp.op = 'RENAME'
180 gp.op = 'RENAME'
181 gp.oldpath = line[12:].rstrip()
181 gp.oldpath = line[12:].rstrip()
182 elif line.startswith('rename to '):
182 elif line.startswith('rename to '):
183 gp.path = line[10:].rstrip()
183 gp.path = line[10:].rstrip()
184 elif line.startswith('copy from '):
184 elif line.startswith('copy from '):
185 gp.op = 'COPY'
185 gp.op = 'COPY'
186 gp.oldpath = line[10:].rstrip()
186 gp.oldpath = line[10:].rstrip()
187 elif line.startswith('copy to '):
187 elif line.startswith('copy to '):
188 gp.path = line[8:].rstrip()
188 gp.path = line[8:].rstrip()
189 elif line.startswith('deleted file'):
189 elif line.startswith('deleted file'):
190 gp.op = 'DELETE'
190 gp.op = 'DELETE'
191 elif line.startswith('new file mode '):
191 elif line.startswith('new file mode '):
192 gp.op = 'ADD'
192 gp.op = 'ADD'
193 gp.mode = int(line.rstrip()[-3:], 8)
193 gp.mode = int(line.rstrip()[-3:], 8)
194 elif line.startswith('new mode '):
194 elif line.startswith('new mode '):
195 gp.mode = int(line.rstrip()[-3:], 8)
195 gp.mode = int(line.rstrip()[-3:], 8)
196 elif line.startswith('GIT binary patch'):
196 elif line.startswith('GIT binary patch'):
197 dopatch |= GP_BINARY
197 dopatch |= GP_BINARY
198 gp.binary = True
198 gp.binary = True
199 if gp:
199 if gp:
200 gitpatches.append(gp)
200 gitpatches.append(gp)
201
201
202 if not gitpatches:
202 if not gitpatches:
203 dopatch = GP_PATCH
203 dopatch = GP_PATCH
204
204
205 return (dopatch, gitpatches)
205 return (dopatch, gitpatches)
206
206
207 def dogitpatch(patchname, gitpatches, cwd=None):
207 def dogitpatch(patchname, gitpatches, cwd=None):
208 """Preprocess git patch so that vanilla patch can handle it"""
208 """Preprocess git patch so that vanilla patch can handle it"""
209 def extractbin(fp):
209 def extractbin(fp):
210 i = [0] # yuck
210 i = [0] # yuck
211 def readline():
211 def readline():
212 i[0] += 1
212 i[0] += 1
213 return fp.readline().rstrip()
213 return fp.readline().rstrip()
214 line = readline()
214 line = readline()
215 while line and not line.startswith('literal '):
215 while line and not line.startswith('literal '):
216 line = readline()
216 line = readline()
217 if not line:
217 if not line:
218 return None, i[0]
218 return None, i[0]
219 size = int(line[8:])
219 size = int(line[8:])
220 dec = []
220 dec = []
221 line = readline()
221 line = readline()
222 while line:
222 while line:
223 l = line[0]
223 l = line[0]
224 if l <= 'Z' and l >= 'A':
224 if l <= 'Z' and l >= 'A':
225 l = ord(l) - ord('A') + 1
225 l = ord(l) - ord('A') + 1
226 else:
226 else:
227 l = ord(l) - ord('a') + 27
227 l = ord(l) - ord('a') + 27
228 dec.append(base85.b85decode(line[1:])[:l])
228 dec.append(base85.b85decode(line[1:])[:l])
229 line = readline()
229 line = readline()
230 text = zlib.decompress(''.join(dec))
230 text = zlib.decompress(''.join(dec))
231 if len(text) != size:
231 if len(text) != size:
232 raise util.Abort(_('binary patch is %d bytes, not %d') %
232 raise util.Abort(_('binary patch is %d bytes, not %d') %
233 (len(text), size))
233 (len(text), size))
234 return text, i[0]
234 return text, i[0]
235
235
236 pf = file(patchname)
236 pf = file(patchname)
237 pfline = 1
237 pfline = 1
238
238
239 fd, patchname = tempfile.mkstemp(prefix='hg-patch-')
239 fd, patchname = tempfile.mkstemp(prefix='hg-patch-')
240 tmpfp = os.fdopen(fd, 'w')
240 tmpfp = os.fdopen(fd, 'w')
241
241
242 try:
242 try:
243 for i in xrange(len(gitpatches)):
243 for i in xrange(len(gitpatches)):
244 p = gitpatches[i]
244 p = gitpatches[i]
245 if not p.copymod and not p.binary:
245 if not p.copymod and not p.binary:
246 continue
246 continue
247
247
248 # rewrite patch hunk
248 # rewrite patch hunk
249 while pfline < p.lineno:
249 while pfline < p.lineno:
250 tmpfp.write(pf.readline())
250 tmpfp.write(pf.readline())
251 pfline += 1
251 pfline += 1
252
252
253 if p.binary:
253 if p.binary:
254 text, delta = extractbin(pf)
254 text, delta = extractbin(pf)
255 if not text:
255 if not text:
256 raise util.Abort(_('binary patch extraction failed'))
256 raise util.Abort(_('binary patch extraction failed'))
257 pfline += delta
257 pfline += delta
258 if not cwd:
258 if not cwd:
259 cwd = os.getcwd()
259 cwd = os.getcwd()
260 absdst = os.path.join(cwd, p.path)
260 absdst = os.path.join(cwd, p.path)
261 basedir = os.path.dirname(absdst)
261 basedir = os.path.dirname(absdst)
262 if not os.path.isdir(basedir):
262 if not os.path.isdir(basedir):
263 os.makedirs(basedir)
263 os.makedirs(basedir)
264 out = file(absdst, 'wb')
264 out = file(absdst, 'wb')
265 out.write(text)
265 out.write(text)
266 out.close()
266 out.close()
267 elif p.copymod:
267 elif p.copymod:
268 copyfile(p.oldpath, p.path, basedir=cwd)
268 copyfile(p.oldpath, p.path, basedir=cwd)
269 tmpfp.write('diff --git a/%s b/%s\n' % (p.path, p.path))
269 tmpfp.write('diff --git a/%s b/%s\n' % (p.path, p.path))
270 line = pf.readline()
270 line = pf.readline()
271 pfline += 1
271 pfline += 1
272 while not line.startswith('--- a/'):
272 while not line.startswith('--- a/'):
273 tmpfp.write(line)
273 tmpfp.write(line)
274 line = pf.readline()
274 line = pf.readline()
275 pfline += 1
275 pfline += 1
276 tmpfp.write('--- a/%s\n' % p.path)
276 tmpfp.write('--- a/%s\n' % p.path)
277
277
278 line = pf.readline()
278 line = pf.readline()
279 while line:
279 while line:
280 tmpfp.write(line)
280 tmpfp.write(line)
281 line = pf.readline()
281 line = pf.readline()
282 except:
282 except:
283 tmpfp.close()
283 tmpfp.close()
284 os.unlink(patchname)
284 os.unlink(patchname)
285 raise
285 raise
286
286
287 tmpfp.close()
287 tmpfp.close()
288 return patchname
288 return patchname
289
289
290 def patch(patchname, ui, strip=1, cwd=None, files={}):
290 def patch(patchname, ui, strip=1, cwd=None, files={}):
291 """apply the patch <patchname> to the working directory.
291 """apply the patch <patchname> to the working directory.
292 a list of patched files is returned"""
292 a list of patched files is returned"""
293
293
294 # helper function
294 # helper function
295 def __patch(patchname):
295 def __patch(patchname):
296 """patch and updates the files and fuzz variables"""
296 """patch and updates the files and fuzz variables"""
297 fuzz = False
297 fuzz = False
298
298
299 args = []
299 args = []
300 patcher = ui.config('ui', 'patch')
300 patcher = ui.config('ui', 'patch')
301 if not patcher:
301 if not patcher:
302 patcher = util.find_exe('gpatch') or util.find_exe('patch')
302 patcher = util.find_exe('gpatch') or util.find_exe('patch')
303 # Try to be smart only if patch call was not supplied
303 # Try to be smart only if patch call was not supplied
304 if util.needbinarypatch():
304 if util.needbinarypatch():
305 args.append('--binary')
305 args.append('--binary')
306
306
307 if not patcher:
307 if not patcher:
308 raise util.Abort(_('no patch command found in hgrc or PATH'))
308 raise util.Abort(_('no patch command found in hgrc or PATH'))
309
309
310 if cwd:
310 if cwd:
311 args.append('-d %s' % util.shellquote(cwd))
311 args.append('-d %s' % util.shellquote(cwd))
312 fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
312 fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
313 util.shellquote(patchname)))
313 util.shellquote(patchname)))
314
314
315 for line in fp:
315 for line in fp:
316 line = line.rstrip()
316 line = line.rstrip()
317 ui.note(line + '\n')
317 ui.note(line + '\n')
318 if line.startswith('patching file '):
318 if line.startswith('patching file '):
319 pf = util.parse_patch_output(line)
319 pf = util.parse_patch_output(line)
320 printed_file = False
320 printed_file = False
321 files.setdefault(pf, (None, None))
321 files.setdefault(pf, (None, None))
322 elif line.find('with fuzz') >= 0:
322 elif line.find('with fuzz') >= 0:
323 fuzz = True
323 fuzz = True
324 if not printed_file:
324 if not printed_file:
325 ui.warn(pf + '\n')
325 ui.warn(pf + '\n')
326 printed_file = True
326 printed_file = True
327 ui.warn(line + '\n')
327 ui.warn(line + '\n')
328 elif line.find('saving rejects to file') >= 0:
328 elif line.find('saving rejects to file') >= 0:
329 ui.warn(line + '\n')
329 ui.warn(line + '\n')
330 elif line.find('FAILED') >= 0:
330 elif line.find('FAILED') >= 0:
331 if not printed_file:
331 if not printed_file:
332 ui.warn(pf + '\n')
332 ui.warn(pf + '\n')
333 printed_file = True
333 printed_file = True
334 ui.warn(line + '\n')
334 ui.warn(line + '\n')
335 code = fp.close()
335 code = fp.close()
336 if code:
336 if code:
337 raise util.Abort(_("patch command failed: %s") %
337 raise util.Abort(_("patch command failed: %s") %
338 util.explain_exit(code)[0])
338 util.explain_exit(code)[0])
339 return fuzz
339 return fuzz
340
340
341 (dopatch, gitpatches) = readgitpatch(patchname)
341 (dopatch, gitpatches) = readgitpatch(patchname)
342 for gp in gitpatches:
342 for gp in gitpatches:
343 files[gp.path] = (gp.op, gp)
343 files[gp.path] = (gp.op, gp)
344
344
345 fuzz = False
345 fuzz = False
346 if dopatch:
346 if dopatch:
347 filterpatch = dopatch & (GP_FILTER | GP_BINARY)
347 filterpatch = dopatch & (GP_FILTER | GP_BINARY)
348 if filterpatch:
348 if filterpatch:
349 patchname = dogitpatch(patchname, gitpatches, cwd=cwd)
349 patchname = dogitpatch(patchname, gitpatches, cwd=cwd)
350 try:
350 try:
351 if dopatch & GP_PATCH:
351 if dopatch & GP_PATCH:
352 fuzz = __patch(patchname)
352 fuzz = __patch(patchname)
353 finally:
353 finally:
354 if filterpatch:
354 if filterpatch:
355 os.unlink(patchname)
355 os.unlink(patchname)
356
356
357 return fuzz
357 return fuzz
358
358
359 def diffopts(ui, opts={}, untrusted=False):
359 def diffopts(ui, opts={}, untrusted=False):
360 def get(key, name=None):
360 def get(key, name=None):
361 return (opts.get(key) or
361 return (opts.get(key) or
362 ui.configbool('diff', name or key, None, untrusted=untrusted))
362 ui.configbool('diff', name or key, None, untrusted=untrusted))
363 return mdiff.diffopts(
363 return mdiff.diffopts(
364 text=opts.get('text'),
364 text=opts.get('text'),
365 git=get('git'),
365 git=get('git'),
366 nodates=get('nodates'),
366 nodates=get('nodates'),
367 showfunc=get('show_function', 'showfunc'),
367 showfunc=get('show_function', 'showfunc'),
368 ignorews=get('ignore_all_space', 'ignorews'),
368 ignorews=get('ignore_all_space', 'ignorews'),
369 ignorewsamount=get('ignore_space_change', 'ignorewsamount'),
369 ignorewsamount=get('ignore_space_change', 'ignorewsamount'),
370 ignoreblanklines=get('ignore_blank_lines', 'ignoreblanklines'))
370 ignoreblanklines=get('ignore_blank_lines', 'ignoreblanklines'))
371
371
372 def updatedir(ui, repo, patches, wlock=None):
372 def updatedir(ui, repo, patches, wlock=None):
373 '''Update dirstate after patch application according to metadata'''
373 '''Update dirstate after patch application according to metadata'''
374 if not patches:
374 if not patches:
375 return
375 return
376 copies = []
376 copies = []
377 removes = {}
377 removes = {}
378 cfiles = patches.keys()
378 cfiles = patches.keys()
379 cwd = repo.getcwd()
379 cwd = repo.getcwd()
380 if cwd:
380 if cwd:
381 cfiles = [util.pathto(repo.root, cwd, f) for f in patches.keys()]
381 cfiles = [util.pathto(repo.root, cwd, f) for f in patches.keys()]
382 for f in patches:
382 for f in patches:
383 ctype, gp = patches[f]
383 ctype, gp = patches[f]
384 if ctype == 'RENAME':
384 if ctype == 'RENAME':
385 copies.append((gp.oldpath, gp.path, gp.copymod))
385 copies.append((gp.oldpath, gp.path, gp.copymod))
386 removes[gp.oldpath] = 1
386 removes[gp.oldpath] = 1
387 elif ctype == 'COPY':
387 elif ctype == 'COPY':
388 copies.append((gp.oldpath, gp.path, gp.copymod))
388 copies.append((gp.oldpath, gp.path, gp.copymod))
389 elif ctype == 'DELETE':
389 elif ctype == 'DELETE':
390 removes[gp.path] = 1
390 removes[gp.path] = 1
391 for src, dst, after in copies:
391 for src, dst, after in copies:
392 if not after:
392 if not after:
393 copyfile(src, dst, repo.root)
393 copyfile(src, dst, repo.root)
394 repo.copy(src, dst, wlock=wlock)
394 repo.copy(src, dst, wlock=wlock)
395 removes = removes.keys()
395 removes = removes.keys()
396 if removes:
396 if removes:
397 removes.sort()
397 removes.sort()
398 repo.remove(removes, True, wlock=wlock)
398 repo.remove(removes, True, wlock=wlock)
399 for f in patches:
399 for f in patches:
400 ctype, gp = patches[f]
400 ctype, gp = patches[f]
401 if gp and gp.mode:
401 if gp and gp.mode:
402 x = gp.mode & 0100 != 0
402 x = gp.mode & 0100 != 0
403 dst = os.path.join(repo.root, gp.path)
403 dst = os.path.join(repo.root, gp.path)
404 # patch won't create empty files
404 # patch won't create empty files
405 if ctype == 'ADD' and not os.path.exists(dst):
405 if ctype == 'ADD' and not os.path.exists(dst):
406 repo.wwrite(gp.path, '', x and 'x' or '')
406 repo.wwrite(gp.path, '', x and 'x' or '')
407 else:
407 else:
408 util.set_exec(dst, x)
408 util.set_exec(dst, x)
409 cmdutil.addremove(repo, cfiles, wlock=wlock)
409 cmdutil.addremove(repo, cfiles, wlock=wlock)
410 files = patches.keys()
410 files = patches.keys()
411 files.extend([r for r in removes if r not in files])
411 files.extend([r for r in removes if r not in files])
412 files.sort()
412 files.sort()
413
413
414 return files
414 return files
415
415
416 def b85diff(fp, to, tn):
416 def b85diff(fp, to, tn):
417 '''print base85-encoded binary diff'''
417 '''print base85-encoded binary diff'''
418 def gitindex(text):
418 def gitindex(text):
419 if not text:
419 if not text:
420 return '0' * 40
420 return '0' * 40
421 l = len(text)
421 l = len(text)
422 s = sha.new('blob %d\0' % l)
422 s = sha.new('blob %d\0' % l)
423 s.update(text)
423 s.update(text)
424 return s.hexdigest()
424 return s.hexdigest()
425
425
426 def fmtline(line):
426 def fmtline(line):
427 l = len(line)
427 l = len(line)
428 if l <= 26:
428 if l <= 26:
429 l = chr(ord('A') + l - 1)
429 l = chr(ord('A') + l - 1)
430 else:
430 else:
431 l = chr(l - 26 + ord('a') - 1)
431 l = chr(l - 26 + ord('a') - 1)
432 return '%c%s\n' % (l, base85.b85encode(line, True))
432 return '%c%s\n' % (l, base85.b85encode(line, True))
433
433
434 def chunk(text, csize=52):
434 def chunk(text, csize=52):
435 l = len(text)
435 l = len(text)
436 i = 0
436 i = 0
437 while i < l:
437 while i < l:
438 yield text[i:i+csize]
438 yield text[i:i+csize]
439 i += csize
439 i += csize
440
440
441 tohash = gitindex(to)
441 tohash = gitindex(to)
442 tnhash = gitindex(tn)
442 tnhash = gitindex(tn)
443 if tohash == tnhash:
443 if tohash == tnhash:
444 return ""
444 return ""
445
445
446 # TODO: deltas
446 # TODO: deltas
447 ret = ['index %s..%s\nGIT binary patch\nliteral %s\n' %
447 ret = ['index %s..%s\nGIT binary patch\nliteral %s\n' %
448 (tohash, tnhash, len(tn))]
448 (tohash, tnhash, len(tn))]
449 for l in chunk(zlib.compress(tn)):
449 for l in chunk(zlib.compress(tn)):
450 ret.append(fmtline(l))
450 ret.append(fmtline(l))
451 ret.append('\n')
451 ret.append('\n')
452 return ''.join(ret)
452 return ''.join(ret)
453
453
454 def diff(repo, node1=None, node2=None, files=None, match=util.always,
454 def diff(repo, node1=None, node2=None, files=None, match=util.always,
455 fp=None, changes=None, opts=None):
455 fp=None, changes=None, opts=None):
456 '''print diff of changes to files between two nodes, or node and
456 '''print diff of changes to files between two nodes, or node and
457 working directory.
457 working directory.
458
458
459 if node1 is None, use first dirstate parent instead.
459 if node1 is None, use first dirstate parent instead.
460 if node2 is None, compare node1 with working directory.'''
460 if node2 is None, compare node1 with working directory.'''
461
461
462 if opts is None:
462 if opts is None:
463 opts = mdiff.defaultopts
463 opts = mdiff.defaultopts
464 if fp is None:
464 if fp is None:
465 fp = repo.ui
465 fp = repo.ui
466
466
467 if not node1:
467 if not node1:
468 node1 = repo.dirstate.parents()[0]
468 node1 = repo.dirstate.parents()[0]
469
469
470 ccache = {}
470 ccache = {}
471 def getctx(r):
471 def getctx(r):
472 if r not in ccache:
472 if r not in ccache:
473 ccache[r] = context.changectx(repo, r)
473 ccache[r] = context.changectx(repo, r)
474 return ccache[r]
474 return ccache[r]
475
475
476 flcache = {}
476 flcache = {}
477 def getfilectx(f, ctx):
477 def getfilectx(f, ctx):
478 flctx = ctx.filectx(f, filelog=flcache.get(f))
478 flctx = ctx.filectx(f, filelog=flcache.get(f))
479 if f not in flcache:
479 if f not in flcache:
480 flcache[f] = flctx._filelog
480 flcache[f] = flctx._filelog
481 return flctx
481 return flctx
482
482
483 # reading the data for node1 early allows it to play nicely
483 # reading the data for node1 early allows it to play nicely
484 # with repo.status and the revlog cache.
484 # with repo.status and the revlog cache.
485 ctx1 = context.changectx(repo, node1)
485 ctx1 = context.changectx(repo, node1)
486 # force manifest reading
486 # force manifest reading
487 man1 = ctx1.manifest()
487 man1 = ctx1.manifest()
488 date1 = util.datestr(ctx1.date())
488 date1 = util.datestr(ctx1.date())
489
489
490 if not changes:
490 if not changes:
491 changes = repo.status(node1, node2, files, match=match)[:5]
491 changes = repo.status(node1, node2, files, match=match)[:5]
492 modified, added, removed, deleted, unknown = changes
492 modified, added, removed, deleted, unknown = changes
493
493
494 if not modified and not added and not removed:
494 if not modified and not added and not removed:
495 return
495 return
496
496
497 if node2:
497 if node2:
498 ctx2 = context.changectx(repo, node2)
498 ctx2 = context.changectx(repo, node2)
499 execf2 = ctx2.manifest().execf
499 execf2 = ctx2.manifest().execf
500 else:
500 else:
501 ctx2 = context.workingctx(repo)
501 ctx2 = context.workingctx(repo)
502 execf2 = util.execfunc(repo.root, None)
502 execf2 = util.execfunc(repo.root, None)
503 if execf2 is None:
503 if execf2 is None:
504 execf2 = ctx2.parents()[0].manifest().copy().execf
504 execf2 = ctx2.parents()[0].manifest().copy().execf
505
505
506 # returns False if there was no rename between ctx1 and ctx2
506 # returns False if there was no rename between ctx1 and ctx2
507 # returns None if the file was created between ctx1 and ctx2
507 # returns None if the file was created between ctx1 and ctx2
508 # returns the (file, node) present in ctx1 that was renamed to f in ctx2
508 # returns the (file, node) present in ctx1 that was renamed to f in ctx2
509 def renamed(f):
509 def renamed(f):
510 startrev = ctx1.rev()
510 startrev = ctx1.rev()
511 c = ctx2
511 c = ctx2
512 crev = c.rev()
512 crev = c.rev()
513 if crev is None:
513 if crev is None:
514 crev = repo.changelog.count()
514 crev = repo.changelog.count()
515 orig = f
515 orig = f
516 while crev > startrev:
516 while crev > startrev:
517 if f in c.files():
517 if f in c.files():
518 try:
518 try:
519 src = getfilectx(f, c).renamed()
519 src = getfilectx(f, c).renamed()
520 except revlog.LookupError:
520 except revlog.LookupError:
521 return None
521 return None
522 if src:
522 if src:
523 f = src[0]
523 f = src[0]
524 crev = c.parents()[0].rev()
524 crev = c.parents()[0].rev()
525 # try to reuse
525 # try to reuse
526 c = getctx(crev)
526 c = getctx(crev)
527 if f not in man1:
527 if f not in man1:
528 return None
528 return None
529 if f == orig:
529 if f == orig:
530 return False
530 return False
531 return f
531 return f
532
532
533 if repo.ui.quiet:
533 if repo.ui.quiet:
534 r = None
534 r = None
535 else:
535 else:
536 hexfunc = repo.ui.debugflag and hex or short
536 hexfunc = repo.ui.debugflag and hex or short
537 r = [hexfunc(node) for node in [node1, node2] if node]
537 r = [hexfunc(node) for node in [node1, node2] if node]
538
538
539 if opts.git:
539 if opts.git:
540 copied = {}
540 copied = {}
541 for f in added:
541 for f in added:
542 src = renamed(f)
542 src = renamed(f)
543 if src:
543 if src:
544 copied[f] = src
544 copied[f] = src
545 srcs = [x[1] for x in copied.items()]
545 srcs = [x[1] for x in copied.items()]
546
546
547 all = modified + added + removed
547 all = modified + added + removed
548 all.sort()
548 all.sort()
549 gone = {}
549 gone = {}
550
550
551 for f in all:
551 for f in all:
552 to = None
552 to = None
553 tn = None
553 tn = None
554 dodiff = True
554 dodiff = True
555 header = []
555 header = []
556 if f in man1:
556 if f in man1:
557 to = getfilectx(f, ctx1).data()
557 to = getfilectx(f, ctx1).data()
558 if f not in removed:
558 if f not in removed:
559 tn = getfilectx(f, ctx2).data()
559 tn = getfilectx(f, ctx2).data()
560 if opts.git:
560 if opts.git:
561 def gitmode(x):
561 def gitmode(x):
562 return x and '100755' or '100644'
562 return x and '100755' or '100644'
563 def addmodehdr(header, omode, nmode):
563 def addmodehdr(header, omode, nmode):
564 if omode != nmode:
564 if omode != nmode:
565 header.append('old mode %s\n' % omode)
565 header.append('old mode %s\n' % omode)
566 header.append('new mode %s\n' % nmode)
566 header.append('new mode %s\n' % nmode)
567
567
568 a, b = f, f
568 a, b = f, f
569 if f in added:
569 if f in added:
570 mode = gitmode(execf2(f))
570 mode = gitmode(execf2(f))
571 if f in copied:
571 if f in copied:
572 a = copied[f]
572 a = copied[f]
573 omode = gitmode(man1.execf(a))
573 omode = gitmode(man1.execf(a))
574 addmodehdr(header, omode, mode)
574 addmodehdr(header, omode, mode)
575 if a in removed and a not in gone:
575 if a in removed and a not in gone:
576 op = 'rename'
576 op = 'rename'
577 gone[a] = 1
577 gone[a] = 1
578 else:
578 else:
579 op = 'copy'
579 op = 'copy'
580 header.append('%s from %s\n' % (op, a))
580 header.append('%s from %s\n' % (op, a))
581 header.append('%s to %s\n' % (op, f))
581 header.append('%s to %s\n' % (op, f))
582 to = getfilectx(a, ctx1).data()
582 to = getfilectx(a, ctx1).data()
583 else:
583 else:
584 header.append('new file mode %s\n' % mode)
584 header.append('new file mode %s\n' % mode)
585 if util.binary(tn):
585 if util.binary(tn):
586 dodiff = 'binary'
586 dodiff = 'binary'
587 elif f in removed:
587 elif f in removed:
588 if f in srcs:
588 if f in srcs:
589 dodiff = False
589 dodiff = False
590 else:
590 else:
591 mode = gitmode(man1.execf(f))
591 mode = gitmode(man1.execf(f))
592 header.append('deleted file mode %s\n' % mode)
592 header.append('deleted file mode %s\n' % mode)
593 else:
593 else:
594 omode = gitmode(man1.execf(f))
594 omode = gitmode(man1.execf(f))
595 nmode = gitmode(execf2(f))
595 nmode = gitmode(execf2(f))
596 addmodehdr(header, omode, nmode)
596 addmodehdr(header, omode, nmode)
597 if util.binary(to) or util.binary(tn):
597 if util.binary(to) or util.binary(tn):
598 dodiff = 'binary'
598 dodiff = 'binary'
599 r = None
599 r = None
600 header.insert(0, 'diff --git a/%s b/%s\n' % (a, b))
600 header.insert(0, 'diff --git a/%s b/%s\n' % (a, b))
601 if dodiff:
601 if dodiff:
602 if dodiff == 'binary':
602 if dodiff == 'binary':
603 text = b85diff(fp, to, tn)
603 text = b85diff(fp, to, tn)
604 else:
604 else:
605 text = mdiff.unidiff(to, date1,
605 text = mdiff.unidiff(to, date1,
606 # ctx2 date may be dynamic
606 # ctx2 date may be dynamic
607 tn, util.datestr(ctx2.date()),
607 tn, util.datestr(ctx2.date()),
608 f, r, opts=opts)
608 f, r, opts=opts)
609 if text or len(header) > 1:
609 if text or len(header) > 1:
610 fp.write(''.join(header))
610 fp.write(''.join(header))
611 fp.write(text)
611 fp.write(text)
612
612
613 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
613 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
614 opts=None):
614 opts=None):
615 '''export changesets as hg patches.'''
615 '''export changesets as hg patches.'''
616
616
617 total = len(revs)
617 total = len(revs)
618 revwidth = max([len(str(rev)) for rev in revs])
618 revwidth = max([len(str(rev)) for rev in revs])
619
619
620 def single(rev, seqno, fp):
620 def single(rev, seqno, fp):
621 ctx = repo.changectx(rev)
621 ctx = repo.changectx(rev)
622 node = ctx.node()
622 node = ctx.node()
623 parents = [p.node() for p in ctx.parents() if p]
623 parents = [p.node() for p in ctx.parents() if p]
624 branch = ctx.branch()
624 branch = ctx.branch()
625 if switch_parent:
625 if switch_parent:
626 parents.reverse()
626 parents.reverse()
627 prev = (parents and parents[0]) or nullid
627 prev = (parents and parents[0]) or nullid
628
628
629 if not fp:
629 if not fp:
630 fp = cmdutil.make_file(repo, template, node, total=total,
630 fp = cmdutil.make_file(repo, template, node, total=total,
631 seqno=seqno, revwidth=revwidth)
631 seqno=seqno, revwidth=revwidth)
632 if fp != sys.stdout and hasattr(fp, 'name'):
632 if fp != sys.stdout and hasattr(fp, 'name'):
633 repo.ui.note("%s\n" % fp.name)
633 repo.ui.note("%s\n" % fp.name)
634
634
635 fp.write("# HG changeset patch\n")
635 fp.write("# HG changeset patch\n")
636 fp.write("# User %s\n" % ctx.user())
636 fp.write("# User %s\n" % ctx.user())
637 fp.write("# Date %d %d\n" % ctx.date())
637 fp.write("# Date %d %d\n" % ctx.date())
638 if branch and (branch != 'default'):
638 if branch and (branch != 'default'):
639 fp.write("# Branch %s\n" % branch)
639 fp.write("# Branch %s\n" % branch)
640 fp.write("# Node ID %s\n" % hex(node))
640 fp.write("# Node ID %s\n" % hex(node))
641 fp.write("# Parent %s\n" % hex(prev))
641 fp.write("# Parent %s\n" % hex(prev))
642 if len(parents) > 1:
642 if len(parents) > 1:
643 fp.write("# Parent %s\n" % hex(parents[1]))
643 fp.write("# Parent %s\n" % hex(parents[1]))
644 fp.write(ctx.description().rstrip())
644 fp.write(ctx.description().rstrip())
645 fp.write("\n\n")
645 fp.write("\n\n")
646
646
647 diff(repo, prev, node, fp=fp, opts=opts)
647 diff(repo, prev, node, fp=fp, opts=opts)
648 if fp not in (sys.stdout, repo.ui):
648 if fp not in (sys.stdout, repo.ui):
649 fp.close()
649 fp.close()
650
650
651 for seqno, rev in enumerate(revs):
651 for seqno, rev in enumerate(revs):
652 single(rev, seqno+1, fp)
652 single(rev, seqno+1, fp)
653
653
654 def diffstat(patchlines):
654 def diffstat(patchlines):
655 if not util.find_exe('diffstat'):
655 if not util.find_exe('diffstat'):
656 return
656 return
657 fd, name = tempfile.mkstemp(prefix="hg-patchbomb-", suffix=".txt")
657 fd, name = tempfile.mkstemp(prefix="hg-patchbomb-", suffix=".txt")
658 try:
658 try:
659 p = popen2.Popen3('diffstat -p1 -w79 2>/dev/null > ' + name)
659 p = popen2.Popen3('diffstat -p1 -w79 2>/dev/null > ' + name)
660 try:
660 try:
661 for line in patchlines: print >> p.tochild, line
661 for line in patchlines: print >> p.tochild, line
662 p.tochild.close()
662 p.tochild.close()
663 if p.wait(): return
663 if p.wait(): return
664 fp = os.fdopen(fd, 'r')
664 fp = os.fdopen(fd, 'r')
665 stat = []
665 stat = []
666 for line in fp: stat.append(line.lstrip())
666 for line in fp: stat.append(line.lstrip())
667 last = stat.pop()
667 last = stat.pop()
668 stat.insert(0, last)
668 stat.insert(0, last)
669 stat = ''.join(stat)
669 stat = ''.join(stat)
670 if stat.startswith('0 files'): raise ValueError
670 if stat.startswith('0 files'): raise ValueError
671 return stat
671 return stat
672 except: raise
672 except: raise
673 finally:
673 finally:
674 try: os.unlink(name)
674 try: os.unlink(name)
675 except: pass
675 except: pass
@@ -1,57 +1,57 b''
1 default = 'summary'
1 default = 'summary'
2 header = header.tmpl
2 header = header.tmpl
3 footer = footer.tmpl
3 footer = footer.tmpl
4 search = search.tmpl
4 search = search.tmpl
5 changelog = changelog.tmpl
5 changelog = changelog.tmpl
6 summary = summary.tmpl
6 summary = summary.tmpl
7 error = error.tmpl
7 error = error.tmpl
8 naventry = '<a href="{url}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
8 naventry = '<a href="{url}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
9 navshortentry = '<a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
9 navshortentry = '<a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
10 filenaventry = '<a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{label|escape}</a> '
10 filenaventry = '<a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{label|escape}</a> '
11 filedifflink = '<a href="#url#diff/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#file|escape#</a> '
11 filedifflink = '<a href="#url#diff/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#file|escape#</a> '
12 filenodelink = '<tr class="parity#parity#"><td><a class="list" href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">#file|escape#</a></td><td></td><td class="link"><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">file</a> | <a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">annotate</a> | <a href="#url#diff/#node|short#/#file|urlescape#{sessionvars%urlparameter}">diff</a> | <a href="#url#log/#node|short#/#file|urlescape#{sessionvars%urlparameter}">revisions</a></td></tr>'
12 filenodelink = '<tr class="parity#parity#"><td><a class="list" href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">#file|escape#</a></td><td></td><td class="link"><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">file</a> | <a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">annotate</a> | <a href="#url#diff/#node|short#/#file|urlescape#{sessionvars%urlparameter}">diff</a> | <a href="#url#log/#node|short#/#file|urlescape#{sessionvars%urlparameter}">revisions</a></td></tr>'
13 fileellipses = '...'
13 fileellipses = '...'
14 changelogentry = changelogentry.tmpl
14 changelogentry = changelogentry.tmpl
15 searchentry = changelogentry.tmpl
15 searchentry = changelogentry.tmpl
16 changeset = changeset.tmpl
16 changeset = changeset.tmpl
17 manifest = manifest.tmpl
17 manifest = manifest.tmpl
18 manifestdirentry = '<tr class="parity#parity#"><td style="font-family:monospace">drwxr-xr-x</td><td style="font-family:monospace"></td><td><a href="#url#file/#node|short##path|urlescape#{sessionvars%urlparameter}">#basename|escape#</a></td><td class="link"><a href="#url#file/#node|short##path|urlescape#{sessionvars%urlparameter}">manifest</a></td></tr>'
18 manifestdirentry = '<tr class="parity#parity#"><td style="font-family:monospace">drwxr-xr-x</td><td style="font-family:monospace"></td><td><a href="#url#file/#node|short##path|urlescape#{sessionvars%urlparameter}">#basename|escape#</a></td><td class="link"><a href="#url#file/#node|short##path|urlescape#{sessionvars%urlparameter}">manifest</a></td></tr>'
19 manifestfileentry = '<tr class="parity#parity#"><td style="font-family:monospace">#permissions|permissions#</td><td style="font-family:monospace" align=right>#size#</td><td class="list"><a class="list" href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#basename|escape#</a></td><td class="link"><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">file</a> | <a href="#url#log/#node|short#/#file|urlescape#{sessionvars%urlparameter}">revisions</a> | <a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">annotate</a></td></tr>'
19 manifestfileentry = '<tr class="parity#parity#"><td style="font-family:monospace">#permissions|permissions#</td><td style="font-family:monospace" align=right>#size#</td><td class="list"><a class="list" href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#basename|escape#</a></td><td class="link"><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">file</a> | <a href="#url#log/#node|short#/#file|urlescape#{sessionvars%urlparameter}">revisions</a> | <a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">annotate</a></td></tr>'
20 filerevision = filerevision.tmpl
20 filerevision = filerevision.tmpl
21 fileannotate = fileannotate.tmpl
21 fileannotate = fileannotate.tmpl
22 filediff = filediff.tmpl
22 filediff = filediff.tmpl
23 filelog = filelog.tmpl
23 filelog = filelog.tmpl
24 fileline = '<div style="font-family:monospace" class="parity#parity#"><pre><span class="linenr"> #linenumber#</span> #line|escape#</pre></div>'
24 fileline = '<div style="font-family:monospace" class="parity#parity#"><pre><span class="linenr"> #linenumber#</span> #line|escape#</pre></div>'
25 annotateline = '<tr style="font-family:monospace" class="parity#parity#"><td class="linenr" style="text-align: right;"><a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#author|obfuscate#@#rev#</a></td><td><pre>#line|escape#</pre></td></tr>'
25 annotateline = '<tr style="font-family:monospace" class="parity#parity#"><td class="linenr" style="text-align: right;"><a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#author|obfuscate#@#rev#</a></td><td><pre>#line|escape#</pre></td></tr>'
26 difflineplus = '<div style="color:#008800;">#line|escape#</div>'
26 difflineplus = '<div style="color:#008800;">#line|escape#</div>'
27 difflineminus = '<div style="color:#cc0000;">#line|escape#</div>'
27 difflineminus = '<div style="color:#cc0000;">#line|escape#</div>'
28 difflineat = '<div style="color:#990099;">#line|escape#</div>'
28 difflineat = '<div style="color:#990099;">#line|escape#</div>'
29 diffline = '<div>#line|escape#</div>'
29 diffline = '<div>#line|escape#</div>'
30 changelogparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
30 changelogparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
31 changesetparent = '<tr><td>parent {rev}</td><td style="font-family:monospace"><a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
31 changesetparent = '<tr><td>parent {rev}</td><td style="font-family:monospace"><a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
32 filerevparent = '<tr><td>parent {rev}</td><td style="font-family:monospace"><a class="list" href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{rename%filerename}{node|short}</a></td></tr>'
32 filerevparent = '<tr><td>parent {rev}</td><td style="font-family:monospace"><a class="list" href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{rename%filerename}{node|short}</a></td></tr>'
33 filerename = '{file|escape}@'
33 filerename = '{file|escape}@'
34 filelogrename = '| <a href="{url}file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">base</a>'
34 filelogrename = '| <a href="{url}file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">base</a>'
35 fileannotateparent = '<tr><td>parent {rev}</td><td style="font-family:monospace"><a class="list" href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{rename%filerename}{node|short}</a></td></tr>'
35 fileannotateparent = '<tr><td>parent {rev}</td><td style="font-family:monospace"><a class="list" href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{rename%filerename}{node|short}</a></td></tr>'
36 changelogchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="{url}rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
36 changelogchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="{url}rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
37 changesetchild = '<tr><td>child {rev}</td><td style="font-family:monospace"><a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
37 changesetchild = '<tr><td>child {rev}</td><td style="font-family:monospace"><a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
38 filerevchild = '<tr><td>child {rev}</td><td style="font-family:monospace"><a class="list" href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
38 filerevchild = '<tr><td>child {rev}</td><td style="font-family:monospace"><a class="list" href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
39 fileannotatechild = '<tr><td>child {rev}</td><td style="font-family:monospace"><a class="list" href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
39 fileannotatechild = '<tr><td>child {rev}</td><td style="font-family:monospace"><a class="list" href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
40 tags = tags.tmpl
40 tags = tags.tmpl
41 tagentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}"><b>#tag|escape#</b></a></td><td class="link"><a href="{url}rev/#node|short#{sessionvars%urlparameter}">changeset</a> | <a href="{url}log/#node|short#{sessionvars%urlparameter}">changelog</a> | <a href="{url}file/#node|short#{sessionvars%urlparameter}">manifest</a></td></tr>'
41 tagentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}"><b>#tag|escape#</b></a></td><td class="link"><a href="{url}rev/#node|short#{sessionvars%urlparameter}">changeset</a> | <a href="{url}log/#node|short#{sessionvars%urlparameter}">changelog</a> | <a href="{url}file/#node|short#{sessionvars%urlparameter}">manifest</a></td></tr>'
42 branchentry = '<tr class="parity{parity}"><td class="age"><i>{date|age} ago</i></td><td><a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}"><b>{node|short}</b></td><td>{branch|escape}</td><td class="link"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a> | <a href="{url}log/{node|short}{sessionvars%urlparameter}">changelog</a> | <a href="{url}file/{node|short}{sessionvars%urlparameter}">manifest</a></td></tr>'
42 branchentry = '<tr class="parity{parity}"><td class="age"><i>{date|age} ago</i></td><td><a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}"><b>{node|short}</b></td><td>{branch|escape}</td><td class="link"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a> | <a href="{url}log/{node|short}{sessionvars%urlparameter}">changelog</a> | <a href="{url}file/{node|short}{sessionvars%urlparameter}">manifest</a></td></tr>'
43 diffblock = '<pre>#lines#</pre>'
43 diffblock = '<pre>#lines#</pre>'
44 filediffparent = '<tr><td>parent {rev}</td><td style="font-family:monospace"><a class="list" href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
44 filediffparent = '<tr><td>parent {rev}</td><td style="font-family:monospace"><a class="list" href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
45 filelogparent = '<tr><td align="right">parent #rev#:&nbsp;</td><td><a href="{url}file/{node|short}/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
45 filelogparent = '<tr><td align="right">parent #rev#:&nbsp;</td><td><a href="{url}file/{node|short}/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
46 filediffchild = '<tr><td>child {rev}</td><td style="font-family:monospace"><a class="list" href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
46 filediffchild = '<tr><td>child {rev}</td><td style="font-family:monospace"><a class="list" href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
47 filelogchild = '<tr><td align="right">child #rev#:&nbsp;</td><td><a href="{url}file{node|short}/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
47 filelogchild = '<tr><td align="right">child #rev#:&nbsp;</td><td><a href="{url}file{node|short}/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
48 shortlog = shortlog.tmpl
48 shortlog = shortlog.tmpl
49 tagtag = '<span class="tagtag" title="{name}">{name}</span> '
49 tagtag = '<span class="tagtag" title="{name}">{name}</span> '
50 branchtag = '<span class="branchtag" title="{name}">{name}</span> '
50 branchtag = '<span class="branchtag" title="{name}">{name}</span> '
51 shortlogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><i>#author#</i></td><td><a class="list" href="{url}rev/#node|short#{sessionvars%urlparameter}"><b>#desc|strip|firstline|escape#</b> <span class="logtags">{branches%branchtag}{tags%tagtag}</span></a></td><td class="link" nowrap><a href="{url}rev/#node|short#{sessionvars%urlparameter}">changeset</a> | <a href="{url}file/#node|short#{sessionvars%urlparameter}">manifest</a></td></tr>'
51 shortlogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><i>#author#</i></td><td><a class="list" href="{url}rev/#node|short#{sessionvars%urlparameter}"><b>#desc|strip|firstline|escape#</b> <span class="logtags">{branches%branchtag}{tags%tagtag}</span></a></td><td class="link" nowrap><a href="{url}rev/#node|short#{sessionvars%urlparameter}">changeset</a> | <a href="{url}file/#node|short#{sessionvars%urlparameter}">manifest</a></td></tr>'
52 filelogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><a class="list" href="{url}rev/#node|short#{sessionvars%urlparameter}"><b>#desc|strip|firstline|escape#</b></a></td><td class="link"><a href="{url}file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">file</a>&nbsp;|&nbsp;<a href="{url}diff/#node|short#/#file|urlescape#{sessionvars%urlparameter}">diff</a>&nbsp;|&nbsp;<a href="{url}annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">annotate</a> #rename%filelogrename#</td></tr>'
52 filelogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><a class="list" href="{url}rev/#node|short#{sessionvars%urlparameter}"><b>#desc|strip|firstline|escape#</b></a></td><td class="link"><a href="{url}file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">file</a>&nbsp;|&nbsp;<a href="{url}diff/#node|short#/#file|urlescape#{sessionvars%urlparameter}">diff</a>&nbsp;|&nbsp;<a href="{url}annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">annotate</a> #rename%filelogrename#</td></tr>'
53 archiveentry = ' | <a href="{url}archive/{node|short}{extension}">#type|escape#</a> '
53 archiveentry = ' | <a href="{url}archive/{node|short}{extension}">#type|escape#</a> '
54 indexentry = '<tr class="parity#parity#"><td><a class="list" href="#url#{sessionvars%urlparameter}"><b>#name|escape#</b></a></td><td>#description#</td><td>#contact|obfuscate#</td><td class="age">#lastchange|age# ago</td><td class="indexlinks"><a class="rss_logo" href="#url#rss-log">RSS</a> #archives%archiveentry#</td></tr>'
54 indexentry = '<tr class="parity#parity#"><td><a class="list" href="#url#{sessionvars%urlparameter}"><b>#name|escape#</b></a></td><td>#description#</td><td>#contact|obfuscate#</td><td class="age">#lastchange|age# ago</td><td class="indexlinks"><a class="rss_logo" href="#url#rss-log">RSS</a> #archives%archiveentry#</td></tr>'
55 index = index.tmpl
55 index = index.tmpl
56 urlparameter = '#separator##name#=#value|urlescape#'
56 urlparameter = '#separator##name#=#value|urlescape#'
57 hiddenformentry = '<input type="hidden" name="#name#" value="#value|escape#" />'
57 hiddenformentry = '<input type="hidden" name="#name#" value="#value|escape#" />'
@@ -1,78 +1,78 b''
1 a { text-decoration:none; }
1 a { text-decoration:none; }
2 .age { white-space:nowrap; }
2 .age { white-space:nowrap; }
3 .indexlinks { white-space:nowrap; }
3 .indexlinks { white-space:nowrap; }
4 .parity0 { background-color: #dddddd; }
4 .parity0 { background-color: #dddddd; }
5 .parity1 { background-color: #eeeeee; }
5 .parity1 { background-color: #eeeeee; }
6 .lineno { width: 60px; color: #aaaaaa; font-size: smaller;
6 .lineno { width: 60px; color: #aaaaaa; font-size: smaller;
7 text-align: right; padding-right:1em; }
7 text-align: right; padding-right:1em; }
8 .plusline { color: green; }
8 .plusline { color: green; }
9 .minusline { color: red; }
9 .minusline { color: red; }
10 .atline { color: purple; }
10 .atline { color: purple; }
11 .annotate { font-size: smaller; text-align: right; padding-right: 1em; }
11 .annotate { font-size: smaller; text-align: right; padding-right: 1em; }
12 .buttons a {
12 .buttons a {
13 background-color: #666666;
13 background-color: #666666;
14 padding: 2pt;
14 padding: 2pt;
15 color: white;
15 color: white;
16 font-family: sans;
16 font-family: sans;
17 font-weight: bold;
17 font-weight: bold;
18 }
18 }
19 .navigate a {
19 .navigate a {
20 background-color: #ccc;
20 background-color: #ccc;
21 padding: 2pt;
21 padding: 2pt;
22 font-family: sans;
22 font-family: sans;
23 color: black;
23 color: black;
24 }
24 }
25
25
26 .metatag {
26 .metatag {
27 background-color: #888888;
27 background-color: #888888;
28 color: white;
28 color: white;
29 text-align: right;
29 text-align: right;
30 }
30 }
31
31
32 /* Common */
32 /* Common */
33 pre { margin: 0; }
33 pre { margin: 0; }
34
34
35 .logo {
35 .logo {
36 background-color: #333;
36 background-color: #333;
37 padding: 4pt;
37 padding: 4pt;
38 margin: 8pt 0 8pt 8pt;
38 margin: 8pt 0 8pt 8pt;
39 font-family: sans;
39 font-family: sans;
40 font-size: 60%;
40 font-size: 60%;
41 color: white;
41 color: white;
42 float: right;
42 float: right;
43 clear: right;
43 clear: right;
44 text-align: left;
44 text-align: left;
45 }
45 }
46
46
47 .logo a {
47 .logo a {
48 font-weight: bold;
48 font-weight: bold;
49 font-size: 150%;
49 font-size: 150%;
50 color: #999;
50 color: #999;
51 }
51 }
52
52
53 /* Changelog/Filelog entries */
53 /* Changelog/Filelog entries */
54 .logEntry { width: 100%; }
54 .logEntry { width: 100%; }
55 .logEntry .age { width: 15%; }
55 .logEntry .age { width: 15%; }
56 .logEntry th { font-weight: normal; text-align: right; vertical-align: top; }
56 .logEntry th { font-weight: normal; text-align: right; vertical-align: top; }
57 .logEntry th.age, .logEntry th.firstline { font-weight: bold; }
57 .logEntry th.age, .logEntry th.firstline { font-weight: bold; }
58 .logEntry th.firstline { text-align: left; width: inherit; }
58 .logEntry th.firstline { text-align: left; width: inherit; }
59
59
60 /* Shortlog entries */
60 /* Shortlog entries */
61 .slogEntry { width: 100%; font-size: smaller; }
61 .slogEntry { width: 100%; font-size: smaller; }
62 .slogEntry .age { width: 7%; }
62 .slogEntry .age { width: 7%; }
63 .slogEntry td { font-weight: normal; text-align: left; vertical-align: top; }
63 .slogEntry td { font-weight: normal; text-align: left; vertical-align: top; }
64 .slogEntry td.author { width: 35%; }
64 .slogEntry td.author { width: 35%; }
65
65
66 /* Tag entries */
66 /* Tag entries */
67 #tagEntries { list-style: none; margin: 0; padding: 0; }
67 #tagEntries { list-style: none; margin: 0; padding: 0; }
68 #tagEntries .tagEntry { list-style: none; margin: 0; padding: 0; }
68 #tagEntries .tagEntry { list-style: none; margin: 0; padding: 0; }
69
69
70 /* Changeset entry */
70 /* Changeset entry */
71 #changesetEntry { }
71 #changesetEntry { }
72 #changesetEntry th { font-weight: normal; background-color: #888; color: #fff; text-align: right; }
72 #changesetEntry th { font-weight: normal; background-color: #888; color: #fff; text-align: right; }
73 #changesetEntry th.files, #changesetEntry th.description { vertical-align: top; }
73 #changesetEntry th.files, #changesetEntry th.description { vertical-align: top; }
74
74
75 /* File diff view */
75 /* File diff view */
76 #filediffEntry { }
76 #filediffEntry { }
77 #filediffEntry th { font-weight: normal; background-color: #888; color: #fff; text-align: right; }
77 #filediffEntry th { font-weight: normal; background-color: #888; color: #fff; text-align: right; }
78
78
@@ -1,47 +1,47 b''
1 # simple script to be used in hooks
1 # simple script to be used in hooks
2 # copy it to the current directory when the test starts:
2 # copy it to the current directory when the test starts:
3 #
3 #
4 # cp "$TESTDIR"/printenv.py .
4 # cp "$TESTDIR"/printenv.py .
5 #
5 #
6 # put something like this in the repo .hg/hgrc:
6 # put something like this in the repo .hg/hgrc:
7 #
7 #
8 # [hooks]
8 # [hooks]
9 # changegroup = python ../printenv.py <hookname> [exit] [output]
9 # changegroup = python ../printenv.py <hookname> [exit] [output]
10 #
10 #
11 # - <hookname> is a mandatory argument (e.g. "changegroup")
11 # - <hookname> is a mandatory argument (e.g. "changegroup")
12 # - [exit] is the exit code of the hook (default: 0)
12 # - [exit] is the exit code of the hook (default: 0)
13 # - [output] is the name of the output file (default: use sys.stdout)
13 # - [output] is the name of the output file (default: use sys.stdout)
14 # the file will be opened in append mode.
14 # the file will be opened in append mode.
15 #
15 #
16 import os
16 import os
17 import sys
17 import sys
18
18
19 exitcode = 0
19 exitcode = 0
20 out = sys.stdout
20 out = sys.stdout
21
21
22 name = sys.argv[1]
22 name = sys.argv[1]
23 if len(sys.argv) > 2:
23 if len(sys.argv) > 2:
24 exitcode = int(sys.argv[2])
24 exitcode = int(sys.argv[2])
25 if len(sys.argv) > 3:
25 if len(sys.argv) > 3:
26 out = open(sys.argv[3], "ab")
26 out = open(sys.argv[3], "ab")
27
27
28 # variables with empty values may not exist on all platforms, filter
28 # variables with empty values may not exist on all platforms, filter
29 # them now for portability sake.
29 # them now for portability sake.
30 env = [k for k,v in os.environ.iteritems()
30 env = [k for k, v in os.environ.iteritems()
31 if k.startswith("HG_") and v]
31 if k.startswith("HG_") and v]
32 env.sort()
32 env.sort()
33
33
34 # edit the variable part of the variable
34 # edit the variable part of the variable
35 url = os.environ.get("HG_URL", "")
35 url = os.environ.get("HG_URL", "")
36 if url.startswith("file:"):
36 if url.startswith("file:"):
37 os.environ["HG_URL"] = "file:"
37 os.environ["HG_URL"] = "file:"
38 elif url.startswith("remote:http"):
38 elif url.startswith("remote:http"):
39 os.environ["HG_URL"] = "remote:http"
39 os.environ["HG_URL"] = "remote:http"
40
40
41 out.write("%s hook: " % name)
41 out.write("%s hook: " % name)
42 for v in env:
42 for v in env:
43 out.write("%s=%s " % (v, os.environ[v]))
43 out.write("%s=%s " % (v, os.environ[v]))
44 out.write("\n")
44 out.write("\n")
45 out.close()
45 out.close()
46
46
47 sys.exit(exitcode)
47 sys.exit(exitcode)
@@ -1,94 +1,94 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 HGMERGE=true; export HGMERGE
3 HGMERGE=true; export HGMERGE
4
4
5 echo % init
5 echo % init
6 hg init
6 hg init
7
7
8 echo % commit
8 echo % commit
9 echo 'a' > a
9 echo 'a' > a
10 hg ci -A -m test -u nobody -d '1 0'
10 hg ci -A -m test -u nobody -d '1 0'
11
11
12 echo % annotate -c
12 echo % annotate -c
13 hg annotate -c a
13 hg annotate -c a
14
14
15 echo % annotate -d
15 echo % annotate -d
16 hg annotate -d a
16 hg annotate -d a
17
17
18 echo % annotate -n
18 echo % annotate -n
19 hg annotate -n a
19 hg annotate -n a
20
20
21 echo % annotate -u
21 echo % annotate -u
22 hg annotate -u a
22 hg annotate -u a
23
23
24 echo % annotate -cdnu
24 echo % annotate -cdnu
25 hg annotate -cdnu a
25 hg annotate -cdnu a
26
26
27 cat <<EOF >>a
27 cat <<EOF >>a
28 a
28 a
29 a
29 a
30 EOF
30 EOF
31 hg ci -ma1 -d '1 0'
31 hg ci -ma1 -d '1 0'
32 hg cp a b
32 hg cp a b
33 hg ci -mb -d '1 0'
33 hg ci -mb -d '1 0'
34 cat <<EOF >> b
34 cat <<EOF >> b
35 b
35 b
36 b
36 b
37 b
37 b
38 EOF
38 EOF
39 hg ci -mb2 -d '2 0'
39 hg ci -mb2 -d '2 0'
40
40
41 echo % annotate b
41 echo % annotate b
42 hg annotate b
42 hg annotate b
43 echo % annotate -nf b
43 echo % annotate -nf b
44 hg annotate -nf b
44 hg annotate -nf b
45
45
46 hg up -C 2
46 hg up -C 2
47 cat <<EOF >> b
47 cat <<EOF >> b
48 b
48 b
49 c
49 c
50 b
50 b
51 EOF
51 EOF
52 hg ci -mb2.1 -d '2 0'
52 hg ci -mb2.1 -d '2 0'
53 hg merge
53 hg merge
54 hg ci -mmergeb -d '3 0'
54 hg ci -mmergeb -d '3 0'
55 echo % annotate after merge
55 echo % annotate after merge
56 hg annotate -nf b
56 hg annotate -nf b
57
57
58 hg up -C 1
58 hg up -C 1
59 hg cp a b
59 hg cp a b
60 cat <<EOF > b
60 cat <<EOF > b
61 a
61 a
62 z
62 z
63 a
63 a
64 EOF
64 EOF
65 hg ci -mc -d '3 0'
65 hg ci -mc -d '3 0'
66 hg merge
66 hg merge
67 cat <<EOF >> b
67 cat <<EOF >> b
68 b
68 b
69 c
69 c
70 b
70 b
71 EOF
71 EOF
72 echo d >> b
72 echo d >> b
73 hg ci -mmerge2 -d '4 0'
73 hg ci -mmerge2 -d '4 0'
74 echo % annotate after rename merge
74 echo % annotate after rename merge
75 hg annotate -nf b
75 hg annotate -nf b
76
76
77 echo % linkrev vs rev
77 echo % linkrev vs rev
78 hg annotate -r tip a
78 hg annotate -r tip a
79
79
80 # test issue 589
80 # test issue 589
81 # annotate was crashing when trying to --follow something
81 # annotate was crashing when trying to --follow something
82 # like A -> B -> A
82 # like A -> B -> A
83 echo % generate ABA rename configuration
83 echo % generate ABA rename configuration
84 echo foo > foo
84 echo foo > foo
85 hg add foo
85 hg add foo
86 hg ci -m addfoo
86 hg ci -m addfoo
87 hg rename foo bar
87 hg rename foo bar
88 hg ci -m renamefoo
88 hg ci -m renamefoo
89 hg rename bar foo
89 hg rename bar foo
90 hg ci -m renamebar
90 hg ci -m renamebar
91
91
92 echo % annotate after ABA with follow
92 echo % annotate after ABA with follow
93 hg annotate --follow foo
93 hg annotate --follow foo
94
94
@@ -1,25 +1,25 b''
1 #!/bin/sh
1 #!/bin/sh
2 # test command parsing and dispatch
2 # test command parsing and dispatch
3
3
4 hg init a
4 hg init a
5 cd a
5 cd a
6 echo a > a
6 echo a > a
7 hg ci -Ama -d '0 0'
7 hg ci -Ama -d '0 0'
8
8
9 echo "# missing arg"
9 echo "# missing arg"
10 hg cat
10 hg cat
11
11
12 echo '% [defaults]'
12 echo '% [defaults]'
13 hg cat a
13 hg cat a
14 cat > $HGRCPATH <<EOF
14 cat > $HGRCPATH <<EOF
15 [defaults]
15 [defaults]
16 cat = -v
16 cat = -v
17 EOF
17 EOF
18 hg cat a
18 hg cat a
19
19
20 echo '% no repo'
20 echo '% no repo'
21 cd ..
21 cd ..
22 hg cat
22 hg cat
23
23
24 exit 0
24 exit 0
25 No newline at end of file
25
@@ -1,25 +1,25 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 hg init a
3 hg init a
4 cd a
4 cd a
5 touch empty1
5 touch empty1
6 hg add empty1
6 hg add empty1
7 hg commit -m 'add empty1' -d '1000000 0'
7 hg commit -m 'add empty1' -d '1000000 0'
8
8
9 touch empty2
9 touch empty2
10 hg add empty2
10 hg add empty2
11 hg commit -m 'add empty2' -d '1000000 0'
11 hg commit -m 'add empty2' -d '1000000 0'
12
12
13 hg up -C 0
13 hg up -C 0
14 touch empty3
14 touch empty3
15 hg add empty3
15 hg add empty3
16 hg commit -m 'add empty3' -d '1000000 0'
16 hg commit -m 'add empty3' -d '1000000 0'
17
17
18 hg heads
18 hg heads
19
19
20 hg merge 1
20 hg merge 1
21 # before changeset 05257fd28591, we didn't notice the
21 # before changeset 05257fd28591, we didn't notice the
22 # empty file that came from rev 1.
22 # empty file that came from rev 1.
23 hg status
23 hg status
24 hg commit -m merge -d '1000000 0'
24 hg commit -m merge -d '1000000 0'
25 hg manifest --debug tip
25 hg manifest --debug tip
@@ -1,49 +1,49 b''
1 #!/bin/sh
1 #!/bin/sh
2 #
2 #
3 # A B
3 # A B
4 #
4 #
5 # 3 4 3
5 # 3 4 3
6 # |\/| |\
6 # |\/| |\
7 # |/\| | \
7 # |/\| | \
8 # 1 2 1 2
8 # 1 2 1 2
9 # \ / \ /
9 # \ / \ /
10 # 0 0
10 # 0 0
11 #
11 #
12 # if the result of the merge of 1 and 2
12 # if the result of the merge of 1 and 2
13 # is the same in 3 and 4, no new manifest
13 # is the same in 3 and 4, no new manifest
14 # will be created and the manifest group
14 # will be created and the manifest group
15 # will be empty during the pull
15 # will be empty during the pull
16 #
16 #
17 # (plus we test a failure where outgoing
17 # (plus we test a failure where outgoing
18 # wrongly reported the number of csets)
18 # wrongly reported the number of csets)
19 #
19 #
20
20
21 hg init a
21 hg init a
22 cd a
22 cd a
23 touch init
23 touch init
24 hg ci -A -m 0 -d "1000000 0"
24 hg ci -A -m 0 -d "1000000 0"
25 touch x y
25 touch x y
26 hg ci -A -m 1 -d "1000000 0"
26 hg ci -A -m 1 -d "1000000 0"
27 hg update 0
27 hg update 0
28 touch x y
28 touch x y
29 hg ci -A -m 2 -d "1000000 0"
29 hg ci -A -m 2 -d "1000000 0"
30 hg merge 1
30 hg merge 1
31 hg ci -A -m m1 -d "1000000 0"
31 hg ci -A -m m1 -d "1000000 0"
32 #hg log
32 #hg log
33 #hg debugindex .hg/store/00manifest.i
33 #hg debugindex .hg/store/00manifest.i
34 hg update -C 1
34 hg update -C 1
35 hg merge 2
35 hg merge 2
36 hg ci -A -m m2 -d "1000000 0"
36 hg ci -A -m m2 -d "1000000 0"
37 #hg log
37 #hg log
38 #hg debugindex .hg/store/00manifest.i
38 #hg debugindex .hg/store/00manifest.i
39
39
40 cd ..
40 cd ..
41 hg clone -r 3 a b
41 hg clone -r 3 a b
42 hg clone -r 4 a c
42 hg clone -r 4 a c
43 hg -R a outgoing b
43 hg -R a outgoing b
44 hg -R a outgoing c
44 hg -R a outgoing c
45 hg -R b outgoing c
45 hg -R b outgoing c
46 hg -R c outgoing b
46 hg -R c outgoing b
47
47
48 hg -R b pull a
48 hg -R b pull a
49 hg -R c pull a
49 hg -R c pull a
@@ -1,7 +1,7 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 mkdir t
3 mkdir t
4 cd t
4 cd t
5 hg init
5 hg init
6 echo "invalid" > .hg/hgrc
6 echo "invalid" > .hg/hgrc
7 hg status 2>&1 |sed -e "s:/.*\(/t/.*\):...\1:"
7 hg status 2>&1 |sed -e "s:/.*\(/t/.*\):...\1:"
@@ -1,220 +1,220 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 cp "$TESTDIR"/printenv.py .
3 cp "$TESTDIR"/printenv.py .
4
4
5 # commit hooks can see env vars
5 # commit hooks can see env vars
6 hg init a
6 hg init a
7 cd a
7 cd a
8 echo "[hooks]" > .hg/hgrc
8 echo "[hooks]" > .hg/hgrc
9 echo 'commit = unset HG_LOCAL HG_TAG; python ../printenv.py commit' >> .hg/hgrc
9 echo 'commit = unset HG_LOCAL HG_TAG; python ../printenv.py commit' >> .hg/hgrc
10 echo 'commit.b = unset HG_LOCAL HG_TAG; python ../printenv.py commit.b' >> .hg/hgrc
10 echo 'commit.b = unset HG_LOCAL HG_TAG; python ../printenv.py commit.b' >> .hg/hgrc
11 echo 'precommit = unset HG_LOCAL HG_NODE HG_TAG; python ../printenv.py precommit' >> .hg/hgrc
11 echo 'precommit = unset HG_LOCAL HG_NODE HG_TAG; python ../printenv.py precommit' >> .hg/hgrc
12 echo 'pretxncommit = unset HG_LOCAL HG_TAG; python ../printenv.py pretxncommit' >> .hg/hgrc
12 echo 'pretxncommit = unset HG_LOCAL HG_TAG; python ../printenv.py pretxncommit' >> .hg/hgrc
13 echo 'pretxncommit.tip = hg -q tip' >> .hg/hgrc
13 echo 'pretxncommit.tip = hg -q tip' >> .hg/hgrc
14 echo 'pre-identify = python ../printenv.py pre-identify 1' >> .hg/hgrc
14 echo 'pre-identify = python ../printenv.py pre-identify 1' >> .hg/hgrc
15 echo 'pre-cat = python ../printenv.py pre-cat' >> .hg/hgrc
15 echo 'pre-cat = python ../printenv.py pre-cat' >> .hg/hgrc
16 echo 'post-cat = python ../printenv.py post-cat' >> .hg/hgrc
16 echo 'post-cat = python ../printenv.py post-cat' >> .hg/hgrc
17 echo a > a
17 echo a > a
18 hg add a
18 hg add a
19 hg commit -m a -d "1000000 0"
19 hg commit -m a -d "1000000 0"
20
20
21 hg clone . ../b
21 hg clone . ../b
22 cd ../b
22 cd ../b
23
23
24 # changegroup hooks can see env vars
24 # changegroup hooks can see env vars
25 echo '[hooks]' > .hg/hgrc
25 echo '[hooks]' > .hg/hgrc
26 echo 'prechangegroup = python ../printenv.py prechangegroup' >> .hg/hgrc
26 echo 'prechangegroup = python ../printenv.py prechangegroup' >> .hg/hgrc
27 echo 'changegroup = python ../printenv.py changegroup' >> .hg/hgrc
27 echo 'changegroup = python ../printenv.py changegroup' >> .hg/hgrc
28 echo 'incoming = python ../printenv.py incoming' >> .hg/hgrc
28 echo 'incoming = python ../printenv.py incoming' >> .hg/hgrc
29
29
30 # pretxncommit and commit hooks can see both parents of merge
30 # pretxncommit and commit hooks can see both parents of merge
31 cd ../a
31 cd ../a
32 echo b >> a
32 echo b >> a
33 hg commit -m a1 -d "1 0"
33 hg commit -m a1 -d "1 0"
34 hg update -C 0
34 hg update -C 0
35 echo b > b
35 echo b > b
36 hg add b
36 hg add b
37 hg commit -m b -d '1 0'
37 hg commit -m b -d '1 0'
38 hg merge 1
38 hg merge 1
39 hg commit -m merge -d '2 0'
39 hg commit -m merge -d '2 0'
40
40
41 # test generic hooks
41 # test generic hooks
42 hg id
42 hg id
43 hg cat b
43 hg cat b
44
44
45 cd ../b
45 cd ../b
46 hg pull ../a
46 hg pull ../a
47
47
48 # tag hooks can see env vars
48 # tag hooks can see env vars
49 cd ../a
49 cd ../a
50 echo 'pretag = python ../printenv.py pretag' >> .hg/hgrc
50 echo 'pretag = python ../printenv.py pretag' >> .hg/hgrc
51 echo 'tag = unset HG_PARENT1 HG_PARENT2; python ../printenv.py tag' >> .hg/hgrc
51 echo 'tag = unset HG_PARENT1 HG_PARENT2; python ../printenv.py tag' >> .hg/hgrc
52 hg tag -d '3 0' a
52 hg tag -d '3 0' a
53 hg tag -l la
53 hg tag -l la
54
54
55 # pretag hook can forbid tagging
55 # pretag hook can forbid tagging
56 echo 'pretag.forbid = python ../printenv.py pretag.forbid 1' >> .hg/hgrc
56 echo 'pretag.forbid = python ../printenv.py pretag.forbid 1' >> .hg/hgrc
57 hg tag -d '4 0' fa
57 hg tag -d '4 0' fa
58 hg tag -l fla
58 hg tag -l fla
59
59
60 # pretxncommit hook can see changeset, can roll back txn, changeset
60 # pretxncommit hook can see changeset, can roll back txn, changeset
61 # no more there after
61 # no more there after
62 echo 'pretxncommit.forbid0 = hg tip -q' >> .hg/hgrc
62 echo 'pretxncommit.forbid0 = hg tip -q' >> .hg/hgrc
63 echo 'pretxncommit.forbid1 = python ../printenv.py pretxncommit.forbid 1' >> .hg/hgrc
63 echo 'pretxncommit.forbid1 = python ../printenv.py pretxncommit.forbid 1' >> .hg/hgrc
64 echo z > z
64 echo z > z
65 hg add z
65 hg add z
66 hg -q tip
66 hg -q tip
67 hg commit -m 'fail' -d '4 0'
67 hg commit -m 'fail' -d '4 0'
68 hg -q tip
68 hg -q tip
69
69
70 # precommit hook can prevent commit
70 # precommit hook can prevent commit
71 echo 'precommit.forbid = python ../printenv.py precommit.forbid 1' >> .hg/hgrc
71 echo 'precommit.forbid = python ../printenv.py precommit.forbid 1' >> .hg/hgrc
72 hg commit -m 'fail' -d '4 0'
72 hg commit -m 'fail' -d '4 0'
73 hg -q tip
73 hg -q tip
74
74
75 # preupdate hook can prevent update
75 # preupdate hook can prevent update
76 echo 'preupdate = python ../printenv.py preupdate' >> .hg/hgrc
76 echo 'preupdate = python ../printenv.py preupdate' >> .hg/hgrc
77 hg update 1
77 hg update 1
78
78
79 # update hook
79 # update hook
80 echo 'update = python ../printenv.py update' >> .hg/hgrc
80 echo 'update = python ../printenv.py update' >> .hg/hgrc
81 hg update
81 hg update
82
82
83 # prechangegroup hook can prevent incoming changes
83 # prechangegroup hook can prevent incoming changes
84 cd ../b
84 cd ../b
85 hg -q tip
85 hg -q tip
86 echo '[hooks]' > .hg/hgrc
86 echo '[hooks]' > .hg/hgrc
87 echo 'prechangegroup.forbid = python ../printenv.py prechangegroup.forbid 1' >> .hg/hgrc
87 echo 'prechangegroup.forbid = python ../printenv.py prechangegroup.forbid 1' >> .hg/hgrc
88 hg pull ../a
88 hg pull ../a
89
89
90 # pretxnchangegroup hook can see incoming changes, can roll back txn,
90 # pretxnchangegroup hook can see incoming changes, can roll back txn,
91 # incoming changes no longer there after
91 # incoming changes no longer there after
92 echo '[hooks]' > .hg/hgrc
92 echo '[hooks]' > .hg/hgrc
93 echo 'pretxnchangegroup.forbid0 = hg tip -q' >> .hg/hgrc
93 echo 'pretxnchangegroup.forbid0 = hg tip -q' >> .hg/hgrc
94 echo 'pretxnchangegroup.forbid1 = python ../printenv.py pretxnchangegroup.forbid 1' >> .hg/hgrc
94 echo 'pretxnchangegroup.forbid1 = python ../printenv.py pretxnchangegroup.forbid 1' >> .hg/hgrc
95 hg pull ../a
95 hg pull ../a
96 hg -q tip
96 hg -q tip
97
97
98 # outgoing hooks can see env vars
98 # outgoing hooks can see env vars
99 rm .hg/hgrc
99 rm .hg/hgrc
100 echo '[hooks]' > ../a/.hg/hgrc
100 echo '[hooks]' > ../a/.hg/hgrc
101 echo 'preoutgoing = python ../printenv.py preoutgoing' >> ../a/.hg/hgrc
101 echo 'preoutgoing = python ../printenv.py preoutgoing' >> ../a/.hg/hgrc
102 echo 'outgoing = python ../printenv.py outgoing' >> ../a/.hg/hgrc
102 echo 'outgoing = python ../printenv.py outgoing' >> ../a/.hg/hgrc
103 hg pull ../a
103 hg pull ../a
104 hg rollback
104 hg rollback
105
105
106 # preoutgoing hook can prevent outgoing changes
106 # preoutgoing hook can prevent outgoing changes
107 echo 'preoutgoing.forbid = python ../printenv.py preoutgoing.forbid 1' >> ../a/.hg/hgrc
107 echo 'preoutgoing.forbid = python ../printenv.py preoutgoing.forbid 1' >> ../a/.hg/hgrc
108 hg pull ../a
108 hg pull ../a
109
109
110 cat > hooktests.py <<EOF
110 cat > hooktests.py <<EOF
111 from mercurial import util
111 from mercurial import util
112
112
113 uncallable = 0
113 uncallable = 0
114
114
115 def printargs(args):
115 def printargs(args):
116 args.pop('ui', None)
116 args.pop('ui', None)
117 args.pop('repo', None)
117 args.pop('repo', None)
118 a = list(args.items())
118 a = list(args.items())
119 a.sort()
119 a.sort()
120 print 'hook args:'
120 print 'hook args:'
121 for k, v in a:
121 for k, v in a:
122 print ' ', k, v
122 print ' ', k, v
123
123
124 def passhook(**args):
124 def passhook(**args):
125 printargs(args)
125 printargs(args)
126
126
127 def failhook(**args):
127 def failhook(**args):
128 printargs(args)
128 printargs(args)
129 return True
129 return True
130
130
131 class LocalException(Exception):
131 class LocalException(Exception):
132 pass
132 pass
133
133
134 def raisehook(**args):
134 def raisehook(**args):
135 raise LocalException('exception from hook')
135 raise LocalException('exception from hook')
136
136
137 def aborthook(**args):
137 def aborthook(**args):
138 raise util.Abort('raise abort from hook')
138 raise util.Abort('raise abort from hook')
139
139
140 def brokenhook(**args):
140 def brokenhook(**args):
141 return 1 + {}
141 return 1 + {}
142
142
143 class container:
143 class container:
144 unreachable = 1
144 unreachable = 1
145 EOF
145 EOF
146
146
147 echo '# test python hooks'
147 echo '# test python hooks'
148 PYTHONPATH="`pwd`:$PYTHONPATH"
148 PYTHONPATH="`pwd`:$PYTHONPATH"
149 export PYTHONPATH
149 export PYTHONPATH
150
150
151 echo '[hooks]' > ../a/.hg/hgrc
151 echo '[hooks]' > ../a/.hg/hgrc
152 echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
152 echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
153 hg pull ../a 2>&1 | grep 'raised an exception'
153 hg pull ../a 2>&1 | grep 'raised an exception'
154
154
155 echo '[hooks]' > ../a/.hg/hgrc
155 echo '[hooks]' > ../a/.hg/hgrc
156 echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
156 echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
157 hg pull ../a 2>&1 | grep 'raised an exception'
157 hg pull ../a 2>&1 | grep 'raised an exception'
158
158
159 echo '[hooks]' > ../a/.hg/hgrc
159 echo '[hooks]' > ../a/.hg/hgrc
160 echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
160 echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
161 hg pull ../a
161 hg pull ../a
162
162
163 echo '[hooks]' > ../a/.hg/hgrc
163 echo '[hooks]' > ../a/.hg/hgrc
164 echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
164 echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
165 hg pull ../a
165 hg pull ../a
166
166
167 echo '[hooks]' > ../a/.hg/hgrc
167 echo '[hooks]' > ../a/.hg/hgrc
168 echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
168 echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
169 hg pull ../a
169 hg pull ../a
170
170
171 echo '[hooks]' > ../a/.hg/hgrc
171 echo '[hooks]' > ../a/.hg/hgrc
172 echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
172 echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
173 hg pull ../a
173 hg pull ../a
174
174
175 echo '[hooks]' > ../a/.hg/hgrc
175 echo '[hooks]' > ../a/.hg/hgrc
176 echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
176 echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
177 hg pull ../a
177 hg pull ../a
178
178
179 echo '[hooks]' > ../a/.hg/hgrc
179 echo '[hooks]' > ../a/.hg/hgrc
180 echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
180 echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
181 hg pull ../a
181 hg pull ../a
182
182
183 echo '[hooks]' > ../a/.hg/hgrc
183 echo '[hooks]' > ../a/.hg/hgrc
184 echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
184 echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
185 hg pull ../a
185 hg pull ../a
186
186
187 echo '[hooks]' > ../a/.hg/hgrc
187 echo '[hooks]' > ../a/.hg/hgrc
188 echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
188 echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
189 hg pull ../a
189 hg pull ../a
190
190
191 echo '# make sure --traceback works'
191 echo '# make sure --traceback works'
192 echo '[hooks]' > .hg/hgrc
192 echo '[hooks]' > .hg/hgrc
193 echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
193 echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
194
194
195 echo a >> a
195 echo a >> a
196 hg --traceback commit -A -m a 2>&1 | grep '^Traceback'
196 hg --traceback commit -A -m a 2>&1 | grep '^Traceback'
197
197
198 cd ..
198 cd ..
199 hg init c
199 hg init c
200 cd c
200 cd c
201
201
202 cat > hookext.py <<EOF
202 cat > hookext.py <<EOF
203 def autohook(**args):
203 def autohook(**args):
204 print "Automatically installed hook"
204 print "Automatically installed hook"
205
205
206 def reposetup(ui, repo):
206 def reposetup(ui, repo):
207 repo.ui.setconfig("hooks", "commit.auto", autohook)
207 repo.ui.setconfig("hooks", "commit.auto", autohook)
208 EOF
208 EOF
209 echo '[extensions]' >> .hg/hgrc
209 echo '[extensions]' >> .hg/hgrc
210 echo 'hookext = hookext.py' >> .hg/hgrc
210 echo 'hookext = hookext.py' >> .hg/hgrc
211
211
212 touch foo
212 touch foo
213 hg add foo
213 hg add foo
214 hg ci -m 'add foo'
214 hg ci -m 'add foo'
215 echo >> foo
215 echo >> foo
216 hg ci --debug -m 'change foo' | sed -e 's/ at .*>/>/'
216 hg ci --debug -m 'change foo' | sed -e 's/ at .*>/>/'
217
217
218 hg showconfig hooks | sed -e 's/ at .*>/>/'
218 hg showconfig hooks | sed -e 's/ at .*>/>/'
219
219
220 exit 0
220 exit 0
@@ -1,49 +1,49 b''
1 #!/bin/sh
1 #!/bin/sh
2 # http://www.selenic.com/mercurial/bts/issue322
2 # http://www.selenic.com/mercurial/bts/issue322
3
3
4 echo % file replaced with directory
4 echo % file replaced with directory
5
5
6 hg init a
6 hg init a
7 cd a
7 cd a
8 echo a > a
8 echo a > a
9 hg commit -Ama
9 hg commit -Ama
10 rm a
10 rm a
11 mkdir a
11 mkdir a
12 echo a > a/a
12 echo a > a/a
13
13
14 echo % should fail - would corrupt dirstate
14 echo % should fail - would corrupt dirstate
15 hg add a/a
15 hg add a/a
16
16
17 cd ..
17 cd ..
18
18
19 echo % directory replaced with file
19 echo % directory replaced with file
20
20
21 hg init c
21 hg init c
22 cd c
22 cd c
23 mkdir a
23 mkdir a
24 echo a > a/a
24 echo a > a/a
25 hg commit -Ama
25 hg commit -Ama
26
26
27 rm -r a
27 rm -r a
28 echo a > a
28 echo a > a
29
29
30 echo % should fail - would corrupt dirstate
30 echo % should fail - would corrupt dirstate
31 hg add a
31 hg add a
32
32
33 cd ..
33 cd ..
34
34
35 echo % directory replaced with file
35 echo % directory replaced with file
36
36
37 hg init d
37 hg init d
38 cd d
38 cd d
39 mkdir b
39 mkdir b
40 mkdir b/c
40 mkdir b/c
41 echo a > b/c/d
41 echo a > b/c/d
42 hg commit -Ama
42 hg commit -Ama
43 rm -r b
43 rm -r b
44 echo a > b
44 echo a > b
45
45
46 echo % should fail - would corrupt dirstate
46 echo % should fail - would corrupt dirstate
47 hg add b
47 hg add b
48
48
49 exit 0
49 exit 0
@@ -1,10 +1,10 b''
1 #!/bin/sh
1 #!/bin/sh
2 # http://www.selenic.com/mercurial/bts/issue433
2 # http://www.selenic.com/mercurial/bts/issue433
3
3
4 hg init a
4 hg init a
5 cd a
5 cd a
6 echo a > a
6 echo a > a
7 hg commit -Ama
7 hg commit -Ama
8
8
9 hg parents -r 0 doesnotexist
9 hg parents -r 0 doesnotexist
10 true
10 true
@@ -1,50 +1,50 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 # Environement setup for MQ
3 # Environement setup for MQ
4 echo "[extensions]" >> $HGRCPATH
4 echo "[extensions]" >> $HGRCPATH
5 echo "mq=" >> $HGRCPATH
5 echo "mq=" >> $HGRCPATH
6
6
7 #Repo init
7 #Repo init
8 hg init
8 hg init
9 hg qinit
9 hg qinit
10
10
11 hg qnew -m "First commit message" first-patch
11 hg qnew -m "First commit message" first-patch
12 echo aaaa > file
12 echo aaaa > file
13 hg add file
13 hg add file
14 hg qrefresh
14 hg qrefresh
15 echo =======================
15 echo =======================
16 echo "Should display 'First commit message'"
16 echo "Should display 'First commit message'"
17 hg log -l1 -v | sed -n '/description/,$p'
17 hg log -l1 -v | sed -n '/description/,$p'
18 echo
18 echo
19
19
20 # Testing changing message with -m
20 # Testing changing message with -m
21 echo bbbb > file
21 echo bbbb > file
22 hg qrefresh -m "Second commit message"
22 hg qrefresh -m "Second commit message"
23 echo =======================
23 echo =======================
24 echo "Should display 'Second commit message'"
24 echo "Should display 'Second commit message'"
25 hg log -l1 -v | sed -n '/description/,$p'
25 hg log -l1 -v | sed -n '/description/,$p'
26 echo
26 echo
27
27
28
28
29 # Testing changing message with -l
29 # Testing changing message with -l
30 echo "Third commit message" > logfile
30 echo "Third commit message" > logfile
31 echo " This is the 3rd log message" >> logfile
31 echo " This is the 3rd log message" >> logfile
32 echo bbbb > file
32 echo bbbb > file
33 hg qrefresh -l logfile
33 hg qrefresh -l logfile
34 echo =======================
34 echo =======================
35 printf "Should display 'Third commit message\\\n This is the 3rd log message'\n"
35 printf "Should display 'Third commit message\\\n This is the 3rd log message'\n"
36 hg log -l1 -v | sed -n '/description/,$p'
36 hg log -l1 -v | sed -n '/description/,$p'
37 echo
37 echo
38
38
39 # Testing changing message with -l-
39 # Testing changing message with -l-
40 hg qnew -m "First commit message" second-patch
40 hg qnew -m "First commit message" second-patch
41 echo aaaa > file2
41 echo aaaa > file2
42 hg add file2
42 hg add file2
43 echo bbbb > file2
43 echo bbbb > file2
44 (echo "Fifth commit message"
44 (echo "Fifth commit message"
45 echo " This is the 5th log message" >> logfile) |\
45 echo " This is the 5th log message" >> logfile) |\
46 hg qrefresh -l-
46 hg qrefresh -l-
47 echo =======================
47 echo =======================
48 printf "Should display 'Fifth commit message\\\n This is the 5th log message'\n"
48 printf "Should display 'Fifth commit message\\\n This is the 5th log message'\n"
49 hg log -l1 -v | sed -n '/description/,$p'
49 hg log -l1 -v | sed -n '/description/,$p'
50 echo
50 echo
@@ -1,104 +1,104 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 mkdir -p t
3 mkdir -p t
4 cd t
4 cd t
5
5
6 cat <<EOF > merge
6 cat <<EOF > merge
7 import sys, os
7 import sys, os
8 f = open(sys.argv[1], "wb")
8 f = open(sys.argv[1], "wb")
9 f.write("merge %s %s %s" % (sys.argv[1], sys.argv[2], sys.argv[3]))
9 f.write("merge %s %s %s" % (sys.argv[1], sys.argv[2], sys.argv[3]))
10 f.close()
10 f.close()
11 EOF
11 EOF
12 HGMERGE="python ../merge"; export HGMERGE
12 HGMERGE="python ../merge"; export HGMERGE
13
13
14 # perform a test merge with possible renaming
14 # perform a test merge with possible renaming
15 #
15 #
16 # args:
16 # args:
17 # $1 = action in local branch
17 # $1 = action in local branch
18 # $2 = action in remote branch
18 # $2 = action in remote branch
19 # $3 = action in working dir
19 # $3 = action in working dir
20 # $4 = expected result
20 # $4 = expected result
21 tm()
21 tm()
22 {
22 {
23 mkdir t
23 mkdir t
24 cd t
24 cd t
25 hg init
25 hg init
26 echo "[merge]" >> .hg/hgrc
26 echo "[merge]" >> .hg/hgrc
27 echo "followcopies = 1" >> .hg/hgrc
27 echo "followcopies = 1" >> .hg/hgrc
28
28
29 # base
29 # base
30 echo base > a
30 echo base > a
31 echo base > rev # used to force commits
31 echo base > rev # used to force commits
32 hg add a rev
32 hg add a rev
33 hg ci -m "base" -d "0 0"
33 hg ci -m "base" -d "0 0"
34
34
35 # remote
35 # remote
36 echo remote > rev
36 echo remote > rev
37 if [ "$2" != "" ] ; then $2 ; fi
37 if [ "$2" != "" ] ; then $2 ; fi
38 hg ci -m "remote" -d "0 0"
38 hg ci -m "remote" -d "0 0"
39
39
40 # local
40 # local
41 hg co -q 0
41 hg co -q 0
42 echo local > rev
42 echo local > rev
43 if [ "$1" != "" ] ; then $1 ; fi
43 if [ "$1" != "" ] ; then $1 ; fi
44 hg ci -m "local" -d "0 0"
44 hg ci -m "local" -d "0 0"
45
45
46 # working dir
46 # working dir
47 echo local > rev
47 echo local > rev
48 if [ "$3" != "" ] ; then $3 ; fi
48 if [ "$3" != "" ] ; then $3 ; fi
49
49
50 # merge
50 # merge
51 echo "--------------"
51 echo "--------------"
52 echo "test L:$1 R:$2 W:$3 - $4"
52 echo "test L:$1 R:$2 W:$3 - $4"
53 echo "--------------"
53 echo "--------------"
54 hg merge -y --debug --traceback
54 hg merge -y --debug --traceback
55
55
56 echo "--------------"
56 echo "--------------"
57 hg status -camC -X rev
57 hg status -camC -X rev
58
58
59 hg ci -m "merge" -d "0 0"
59 hg ci -m "merge" -d "0 0"
60
60
61 echo "--------------"
61 echo "--------------"
62 echo
62 echo
63
63
64 cd ..
64 cd ..
65 rm -r t
65 rm -r t
66 }
66 }
67
67
68 up() {
68 up() {
69 cp rev $1
69 cp rev $1
70 hg add $1 2> /dev/null
70 hg add $1 2> /dev/null
71 if [ "$2" != "" ] ; then
71 if [ "$2" != "" ] ; then
72 cp rev $2
72 cp rev $2
73 hg add $2 2> /dev/null
73 hg add $2 2> /dev/null
74 fi
74 fi
75 }
75 }
76
76
77 uc() { up $1; hg cp $1 $2; } # update + copy
77 uc() { up $1; hg cp $1 $2; } # update + copy
78 um() { up $1; hg mv $1 $2; }
78 um() { up $1; hg mv $1 $2; }
79 nc() { hg cp $1 $2; } # just copy
79 nc() { hg cp $1 $2; } # just copy
80 nm() { hg mv $1 $2; } # just move
80 nm() { hg mv $1 $2; } # just move
81
81
82 tm "up a " "nc a b" " " "1 get local a to b"
82 tm "up a " "nc a b" " " "1 get local a to b"
83 tm "nc a b" "up a " " " "2 get rem change to a and b"
83 tm "nc a b" "up a " " " "2 get rem change to a and b"
84 tm "up a " "nm a b" " " "3 get local a change to b, remove a"
84 tm "up a " "nm a b" " " "3 get local a change to b, remove a"
85 tm "nm a b" "up a " " " "4 get remote change to b"
85 tm "nm a b" "up a " " " "4 get remote change to b"
86 tm " " "nc a b" " " "5 get b"
86 tm " " "nc a b" " " "5 get b"
87 tm "nc a b" " " " " "6 nothing"
87 tm "nc a b" " " " " "6 nothing"
88 tm " " "nm a b" " " "7 get b"
88 tm " " "nm a b" " " "7 get b"
89 tm "nm a b" " " " " "8 nothing"
89 tm "nm a b" " " " " "8 nothing"
90 tm "um a b" "um a b" " " "9 do merge with ancestor in a"
90 tm "um a b" "um a b" " " "9 do merge with ancestor in a"
91 #tm "um a c" "um x c" " " "10 do merge with no ancestor"
91 #tm "um a c" "um x c" " " "10 do merge with no ancestor"
92 tm "nm a b" "nm a c" " " "11 get c, keep b"
92 tm "nm a b" "nm a c" " " "11 get c, keep b"
93 tm "nc a b" "up b " " " "12 merge b no ancestor"
93 tm "nc a b" "up b " " " "12 merge b no ancestor"
94 tm "up b " "nm a b" " " "13 merge b no ancestor"
94 tm "up b " "nm a b" " " "13 merge b no ancestor"
95 tm "nc a b" "up a b" " " "14 merge b no ancestor"
95 tm "nc a b" "up a b" " " "14 merge b no ancestor"
96 tm "up b " "nm a b" " " "15 merge b no ancestor, remove a"
96 tm "up b " "nm a b" " " "15 merge b no ancestor, remove a"
97 tm "nc a b" "up a b" " " "16 get a, merge b no ancestor"
97 tm "nc a b" "up a b" " " "16 get a, merge b no ancestor"
98 tm "up a b" "nc a b" " " "17 keep a, merge b no ancestor"
98 tm "up a b" "nc a b" " " "17 keep a, merge b no ancestor"
99 tm "nm a b" "up a b" " " "18 merge b no ancestor"
99 tm "nm a b" "up a b" " " "18 merge b no ancestor"
100 tm "up a b" "nm a b" " " "19 merge b no ancestor, prompt remove a"
100 tm "up a b" "nm a b" " " "19 merge b no ancestor, prompt remove a"
101 tm "up a " "um a b" " " "20 merge a and b to b, remove a"
101 tm "up a " "um a b" " " "20 merge a and b to b, remove a"
102 tm "um a b" "up a " " " "21 merge a and b to b"
102 tm "um a b" "up a " " " "21 merge a and b to b"
103 #tm "nm a b" "um x a" " " "22 get a, keep b"
103 #tm "nm a b" "um x a" " " "22 get a, keep b"
104 tm "nm a b" "up a c" " " "23 get c, keep b"
104 tm "nm a b" "up a c" " " "23 get c, keep b"
@@ -1,128 +1,128 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 mkdir t
3 mkdir t
4 cd t
4 cd t
5 hg init
5 hg init
6 hg id
6 hg id
7 echo a > a
7 echo a > a
8 hg add a
8 hg add a
9 hg commit -m "test" -d "1000000 0"
9 hg commit -m "test" -d "1000000 0"
10 hg co
10 hg co
11 hg identify
11 hg identify
12 T=`hg tip --debug | head -n 1 | cut -d : -f 3`
12 T=`hg tip --debug | head -n 1 | cut -d : -f 3`
13 hg tag -l "This is a local tag with a really long name!"
13 hg tag -l "This is a local tag with a really long name!"
14 hg tags
14 hg tags
15 rm .hg/localtags
15 rm .hg/localtags
16 echo "$T first" > .hgtags
16 echo "$T first" > .hgtags
17 cat .hgtags
17 cat .hgtags
18 hg add .hgtags
18 hg add .hgtags
19 hg commit -m "add tags" -d "1000000 0"
19 hg commit -m "add tags" -d "1000000 0"
20 hg tags
20 hg tags
21 hg identify
21 hg identify
22 echo bb > a
22 echo bb > a
23 hg status
23 hg status
24 hg identify
24 hg identify
25 hg co first
25 hg co first
26 hg id
26 hg id
27 hg -v id
27 hg -v id
28 hg status
28 hg status
29 echo 1 > b
29 echo 1 > b
30 hg add b
30 hg add b
31 hg commit -m "branch" -d "1000000 0"
31 hg commit -m "branch" -d "1000000 0"
32 hg id
32 hg id
33 hg merge 1
33 hg merge 1
34 hg id
34 hg id
35 hg status
35 hg status
36
36
37 hg commit -m "merge" -d "1000000 0"
37 hg commit -m "merge" -d "1000000 0"
38
38
39 # create fake head, make sure tag not visible afterwards
39 # create fake head, make sure tag not visible afterwards
40 cp .hgtags tags
40 cp .hgtags tags
41 hg tag -d "1000000 0" last
41 hg tag -d "1000000 0" last
42 hg rm .hgtags
42 hg rm .hgtags
43 hg commit -m "remove" -d "1000000 0"
43 hg commit -m "remove" -d "1000000 0"
44
44
45 mv tags .hgtags
45 mv tags .hgtags
46 hg add .hgtags
46 hg add .hgtags
47 hg commit -m "readd" -d "1000000 0"
47 hg commit -m "readd" -d "1000000 0"
48
48
49 hg tags
49 hg tags
50
50
51 # invalid tags
51 # invalid tags
52 echo "spam" >> .hgtags
52 echo "spam" >> .hgtags
53 echo >> .hgtags
53 echo >> .hgtags
54 echo "foo bar" >> .hgtags
54 echo "foo bar" >> .hgtags
55 echo "$T invalid" | sed "s/..../a5a5/" >> .hg/localtags
55 echo "$T invalid" | sed "s/..../a5a5/" >> .hg/localtags
56 hg commit -m "tags" -d "1000000 0"
56 hg commit -m "tags" -d "1000000 0"
57
57
58 # report tag parse error on other head
58 # report tag parse error on other head
59 hg up 3
59 hg up 3
60 echo 'x y' >> .hgtags
60 echo 'x y' >> .hgtags
61 hg commit -m "head" -d "1000000 0"
61 hg commit -m "head" -d "1000000 0"
62
62
63 hg tags
63 hg tags
64 hg tip
64 hg tip
65
65
66 # test tag precedence rules
66 # test tag precedence rules
67 cd ..
67 cd ..
68 hg init t2
68 hg init t2
69 cd t2
69 cd t2
70 echo foo > foo
70 echo foo > foo
71 hg add foo
71 hg add foo
72 hg ci -m 'add foo' -d '1000000 0' # rev 0
72 hg ci -m 'add foo' -d '1000000 0' # rev 0
73 hg tag -d '1000000 0' bar # rev 1
73 hg tag -d '1000000 0' bar # rev 1
74 echo >> foo
74 echo >> foo
75 hg ci -m 'change foo 1' -d '1000000 0' # rev 2
75 hg ci -m 'change foo 1' -d '1000000 0' # rev 2
76 hg up -C 1
76 hg up -C 1
77 hg tag -r 1 -d '1000000 0' -f bar # rev 3
77 hg tag -r 1 -d '1000000 0' -f bar # rev 3
78 hg up -C 1
78 hg up -C 1
79 echo >> foo
79 echo >> foo
80 hg ci -m 'change foo 2' -d '1000000 0' # rev 4
80 hg ci -m 'change foo 2' -d '1000000 0' # rev 4
81 hg tags
81 hg tags
82
82
83 # test tag removal
83 # test tag removal
84 hg tag --remove -d '1000000 0' bar
84 hg tag --remove -d '1000000 0' bar
85 hg tip
85 hg tip
86 hg tags
86 hg tags
87
87
88 echo '% remove nonexistent tag'
88 echo '% remove nonexistent tag'
89 hg tag --remove -d '1000000 0' foobar
89 hg tag --remove -d '1000000 0' foobar
90 hg tip
90 hg tip
91
91
92 # test tag rank
92 # test tag rank
93 cd ..
93 cd ..
94 hg init t3
94 hg init t3
95 cd t3
95 cd t3
96 echo foo > foo
96 echo foo > foo
97 hg add foo
97 hg add foo
98 hg ci -m 'add foo' -d '1000000 0' # rev 0
98 hg ci -m 'add foo' -d '1000000 0' # rev 0
99 hg tag -d '1000000 0' -f bar # rev 1 bar -> 0
99 hg tag -d '1000000 0' -f bar # rev 1 bar -> 0
100 hg tag -d '1000000 0' -f bar # rev 2 bar -> 1
100 hg tag -d '1000000 0' -f bar # rev 2 bar -> 1
101 hg tag -d '1000000 0' -fr 0 bar # rev 3 bar -> 0
101 hg tag -d '1000000 0' -fr 0 bar # rev 3 bar -> 0
102 hg tag -d '1000000 0' -fr 1 bar # rev 3 bar -> 1
102 hg tag -d '1000000 0' -fr 1 bar # rev 3 bar -> 1
103 hg tag -d '1000000 0' -fr 0 bar # rev 4 bar -> 0
103 hg tag -d '1000000 0' -fr 0 bar # rev 4 bar -> 0
104 hg tags
104 hg tags
105 hg co 3
105 hg co 3
106 echo barbar > foo
106 echo barbar > foo
107 hg ci -m 'change foo' -d '1000000 0' # rev 0
107 hg ci -m 'change foo' -d '1000000 0' # rev 0
108 hg tags
108 hg tags
109
109
110 hg tag -d '1000000 0' -r 3 bar # should complain
110 hg tag -d '1000000 0' -r 3 bar # should complain
111 hg tags
111 hg tags
112
112
113 # test tag rank with 3 heads
113 # test tag rank with 3 heads
114 cd ..
114 cd ..
115 hg init t4
115 hg init t4
116 cd t4
116 cd t4
117 echo foo > foo
117 echo foo > foo
118 hg add
118 hg add
119 hg ci -m 'add foo' -d '0 0' # rev 0
119 hg ci -m 'add foo' -d '0 0' # rev 0
120 hg tag -d '0 0' bar # rev 1 bar -> 0
120 hg tag -d '0 0' bar # rev 1 bar -> 0
121 hg tag -d '0 0' -f bar # rev 2 bar -> 1
121 hg tag -d '0 0' -f bar # rev 2 bar -> 1
122 hg up -qC 0
122 hg up -qC 0
123 hg tag -d '0 0' -fr 2 bar # rev 3 bar -> 2
123 hg tag -d '0 0' -fr 2 bar # rev 3 bar -> 2
124 hg tags
124 hg tags
125 hg up -qC 0
125 hg up -qC 0
126 hg tag -d '0 0' -m 'retag rev 0' -fr 0 bar # rev 4 bar -> 0, but bar stays at 2
126 hg tag -d '0 0' -m 'retag rev 0' -fr 0 bar # rev 4 bar -> 0, but bar stays at 2
127 echo % bar should still point to rev 2
127 echo % bar should still point to rev 2
128 hg tags
128 hg tags
@@ -1,68 +1,68 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 HGMERGE=true; export HGMERGE
3 HGMERGE=true; export HGMERGE
4
4
5 set -e
5 set -e
6 mkdir r1
6 mkdir r1
7 cd r1
7 cd r1
8 hg init
8 hg init
9 echo a > a
9 echo a > a
10 hg addremove
10 hg addremove
11 hg commit -m "1" -d "1000000 0"
11 hg commit -m "1" -d "1000000 0"
12
12
13 hg clone . ../r2
13 hg clone . ../r2
14 cd ../r2
14 cd ../r2
15 hg up
15 hg up
16 echo abc > a
16 echo abc > a
17 hg diff --nodates
17 hg diff --nodates
18
18
19 cd ../r1
19 cd ../r1
20 echo b > b
20 echo b > b
21 echo a2 > a
21 echo a2 > a
22 hg addremove
22 hg addremove
23 hg commit -m "2" -d "1000000 0"
23 hg commit -m "2" -d "1000000 0"
24
24
25 cd ../r2
25 cd ../r2
26 hg -q pull ../r1
26 hg -q pull ../r1
27 hg status
27 hg status
28 hg parents
28 hg parents
29 hg --debug up
29 hg --debug up
30 hg parents
30 hg parents
31 hg --debug up 0
31 hg --debug up 0
32 hg parents
32 hg parents
33 hg --debug merge || echo failed
33 hg --debug merge || echo failed
34 hg parents
34 hg parents
35 hg --debug up
35 hg --debug up
36 hg parents
36 hg parents
37 hg -v history
37 hg -v history
38 hg diff --nodates
38 hg diff --nodates
39
39
40 # create a second head
40 # create a second head
41 cd ../r1
41 cd ../r1
42 hg up 0
42 hg up 0
43 echo b2 > b
43 echo b2 > b
44 echo a3 > a
44 echo a3 > a
45 hg addremove
45 hg addremove
46 hg commit -m "3" -d "1000000 0"
46 hg commit -m "3" -d "1000000 0"
47
47
48 cd ../r2
48 cd ../r2
49 hg -q pull ../r1
49 hg -q pull ../r1
50 hg status
50 hg status
51 hg parents
51 hg parents
52 hg --debug up || echo failed
52 hg --debug up || echo failed
53 hg --debug merge || echo failed
53 hg --debug merge || echo failed
54 hg --debug merge -f
54 hg --debug merge -f
55 hg parents
55 hg parents
56 hg diff --nodates
56 hg diff --nodates
57
57
58 # test a local add
58 # test a local add
59 cd ..
59 cd ..
60 hg init a
60 hg init a
61 hg init b
61 hg init b
62 echo a > a/a
62 echo a > a/a
63 echo a > b/a
63 echo a > b/a
64 hg --cwd a commit -A -m a
64 hg --cwd a commit -A -m a
65 cd b
65 cd b
66 hg add a
66 hg add a
67 hg pull -u ../a
67 hg pull -u ../a
68 hg st
68 hg st
General Comments 0
You need to be logged in to leave comments. Login now