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