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