##// END OF EJS Templates
commands: say "working directory" in full spelling
Yuya Nishihara -
r24365:f1eaf03d default
parent child Browse files
Show More
@@ -1,150 +1,150 b''
1 # fetch.py - pull and merge remote changes
1 # fetch.py - pull and merge remote changes
2 #
2 #
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 '''pull, update and merge in one command (DEPRECATED)'''
8 '''pull, update and merge in one command (DEPRECATED)'''
9
9
10 from mercurial.i18n import _
10 from mercurial.i18n import _
11 from mercurial.node import short
11 from mercurial.node import short
12 from mercurial import commands, cmdutil, hg, util, error
12 from mercurial import commands, cmdutil, hg, util, error
13 from mercurial.lock import release
13 from mercurial.lock import release
14 from mercurial import exchange
14 from mercurial import exchange
15
15
16 cmdtable = {}
16 cmdtable = {}
17 command = cmdutil.command(cmdtable)
17 command = cmdutil.command(cmdtable)
18 testedwith = 'internal'
18 testedwith = 'internal'
19
19
20 @command('fetch',
20 @command('fetch',
21 [('r', 'rev', [],
21 [('r', 'rev', [],
22 _('a specific revision you would like to pull'), _('REV')),
22 _('a specific revision you would like to pull'), _('REV')),
23 ('e', 'edit', None, _('invoke editor on commit messages')),
23 ('e', 'edit', None, _('invoke editor on commit messages')),
24 ('', 'force-editor', None, _('edit commit message (DEPRECATED)')),
24 ('', 'force-editor', None, _('edit commit message (DEPRECATED)')),
25 ('', 'switch-parent', None, _('switch parents when merging')),
25 ('', 'switch-parent', None, _('switch parents when merging')),
26 ] + commands.commitopts + commands.commitopts2 + commands.remoteopts,
26 ] + commands.commitopts + commands.commitopts2 + commands.remoteopts,
27 _('hg fetch [SOURCE]'))
27 _('hg fetch [SOURCE]'))
28 def fetch(ui, repo, source='default', **opts):
28 def fetch(ui, repo, source='default', **opts):
29 '''pull changes from a remote repository, merge new changes if needed.
29 '''pull changes from a remote repository, merge new changes if needed.
30
30
31 This finds all changes from the repository at the specified path
31 This finds all changes from the repository at the specified path
32 or URL and adds them to the local repository.
32 or URL and adds them to the local repository.
33
33
34 If the pulled changes add a new branch head, the head is
34 If the pulled changes add a new branch head, the head is
35 automatically merged, and the result of the merge is committed.
35 automatically merged, and the result of the merge is committed.
36 Otherwise, the working directory is updated to include the new
36 Otherwise, the working directory is updated to include the new
37 changes.
37 changes.
38
38
39 When a merge is needed, the working directory is first updated to
39 When a merge is needed, the working directory is first updated to
40 the newly pulled changes. Local changes are then merged into the
40 the newly pulled changes. Local changes are then merged into the
41 pulled changes. To switch the merge order, use --switch-parent.
41 pulled changes. To switch the merge order, use --switch-parent.
42
42
43 See :hg:`help dates` for a list of formats valid for -d/--date.
43 See :hg:`help dates` for a list of formats valid for -d/--date.
44
44
45 Returns 0 on success.
45 Returns 0 on success.
46 '''
46 '''
47
47
48 date = opts.get('date')
48 date = opts.get('date')
49 if date:
49 if date:
50 opts['date'] = util.parsedate(date)
50 opts['date'] = util.parsedate(date)
51
51
52 parent, _p2 = repo.dirstate.parents()
52 parent, _p2 = repo.dirstate.parents()
53 branch = repo.dirstate.branch()
53 branch = repo.dirstate.branch()
54 try:
54 try:
55 branchnode = repo.branchtip(branch)
55 branchnode = repo.branchtip(branch)
56 except error.RepoLookupError:
56 except error.RepoLookupError:
57 branchnode = None
57 branchnode = None
58 if parent != branchnode:
58 if parent != branchnode:
59 raise util.Abort(_('working dir not at branch tip '
59 raise util.Abort(_('working directory not at branch tip '
60 '(use "hg update" to check out branch tip)'))
60 '(use "hg update" to check out branch tip)'))
61
61
62 wlock = lock = None
62 wlock = lock = None
63 try:
63 try:
64 wlock = repo.wlock()
64 wlock = repo.wlock()
65 lock = repo.lock()
65 lock = repo.lock()
66
66
67 cmdutil.bailifchanged(repo)
67 cmdutil.bailifchanged(repo)
68
68
69 bheads = repo.branchheads(branch)
69 bheads = repo.branchheads(branch)
70 bheads = [head for head in bheads if len(repo[head].children()) == 0]
70 bheads = [head for head in bheads if len(repo[head].children()) == 0]
71 if len(bheads) > 1:
71 if len(bheads) > 1:
72 raise util.Abort(_('multiple heads in this branch '
72 raise util.Abort(_('multiple heads in this branch '
73 '(use "hg heads ." and "hg merge" to merge)'))
73 '(use "hg heads ." and "hg merge" to merge)'))
74
74
75 other = hg.peer(repo, opts, ui.expandpath(source))
75 other = hg.peer(repo, opts, ui.expandpath(source))
76 ui.status(_('pulling from %s\n') %
76 ui.status(_('pulling from %s\n') %
77 util.hidepassword(ui.expandpath(source)))
77 util.hidepassword(ui.expandpath(source)))
78 revs = None
78 revs = None
79 if opts['rev']:
79 if opts['rev']:
80 try:
80 try:
81 revs = [other.lookup(rev) for rev in opts['rev']]
81 revs = [other.lookup(rev) for rev in opts['rev']]
82 except error.CapabilityError:
82 except error.CapabilityError:
83 err = _("other repository doesn't support revision lookup, "
83 err = _("other repository doesn't support revision lookup, "
84 "so a rev cannot be specified.")
84 "so a rev cannot be specified.")
85 raise util.Abort(err)
85 raise util.Abort(err)
86
86
87 # Are there any changes at all?
87 # Are there any changes at all?
88 modheads = exchange.pull(repo, other, heads=revs).cgresult
88 modheads = exchange.pull(repo, other, heads=revs).cgresult
89 if modheads == 0:
89 if modheads == 0:
90 return 0
90 return 0
91
91
92 # Is this a simple fast-forward along the current branch?
92 # Is this a simple fast-forward along the current branch?
93 newheads = repo.branchheads(branch)
93 newheads = repo.branchheads(branch)
94 newchildren = repo.changelog.nodesbetween([parent], newheads)[2]
94 newchildren = repo.changelog.nodesbetween([parent], newheads)[2]
95 if len(newheads) == 1 and len(newchildren):
95 if len(newheads) == 1 and len(newchildren):
96 if newchildren[0] != parent:
96 if newchildren[0] != parent:
97 return hg.update(repo, newchildren[0])
97 return hg.update(repo, newchildren[0])
98 else:
98 else:
99 return 0
99 return 0
100
100
101 # Are there more than one additional branch heads?
101 # Are there more than one additional branch heads?
102 newchildren = [n for n in newchildren if n != parent]
102 newchildren = [n for n in newchildren if n != parent]
103 newparent = parent
103 newparent = parent
104 if newchildren:
104 if newchildren:
105 newparent = newchildren[0]
105 newparent = newchildren[0]
106 hg.clean(repo, newparent)
106 hg.clean(repo, newparent)
107 newheads = [n for n in newheads if n != newparent]
107 newheads = [n for n in newheads if n != newparent]
108 if len(newheads) > 1:
108 if len(newheads) > 1:
109 ui.status(_('not merging with %d other new branch heads '
109 ui.status(_('not merging with %d other new branch heads '
110 '(use "hg heads ." and "hg merge" to merge them)\n') %
110 '(use "hg heads ." and "hg merge" to merge them)\n') %
111 (len(newheads) - 1))
111 (len(newheads) - 1))
112 return 1
112 return 1
113
113
114 if not newheads:
114 if not newheads:
115 return 0
115 return 0
116
116
117 # Otherwise, let's merge.
117 # Otherwise, let's merge.
118 err = False
118 err = False
119 if newheads:
119 if newheads:
120 # By default, we consider the repository we're pulling
120 # By default, we consider the repository we're pulling
121 # *from* as authoritative, so we merge our changes into
121 # *from* as authoritative, so we merge our changes into
122 # theirs.
122 # theirs.
123 if opts['switch_parent']:
123 if opts['switch_parent']:
124 firstparent, secondparent = newparent, newheads[0]
124 firstparent, secondparent = newparent, newheads[0]
125 else:
125 else:
126 firstparent, secondparent = newheads[0], newparent
126 firstparent, secondparent = newheads[0], newparent
127 ui.status(_('updating to %d:%s\n') %
127 ui.status(_('updating to %d:%s\n') %
128 (repo.changelog.rev(firstparent),
128 (repo.changelog.rev(firstparent),
129 short(firstparent)))
129 short(firstparent)))
130 hg.clean(repo, firstparent)
130 hg.clean(repo, firstparent)
131 ui.status(_('merging with %d:%s\n') %
131 ui.status(_('merging with %d:%s\n') %
132 (repo.changelog.rev(secondparent), short(secondparent)))
132 (repo.changelog.rev(secondparent), short(secondparent)))
133 err = hg.merge(repo, secondparent, remind=False)
133 err = hg.merge(repo, secondparent, remind=False)
134
134
135 if not err:
135 if not err:
136 # we don't translate commit messages
136 # we don't translate commit messages
137 message = (cmdutil.logmessage(ui, opts) or
137 message = (cmdutil.logmessage(ui, opts) or
138 ('Automated merge with %s' %
138 ('Automated merge with %s' %
139 util.removeauth(other.url())))
139 util.removeauth(other.url())))
140 editopt = opts.get('edit') or opts.get('force_editor')
140 editopt = opts.get('edit') or opts.get('force_editor')
141 editor = cmdutil.getcommiteditor(edit=editopt, editform='fetch')
141 editor = cmdutil.getcommiteditor(edit=editopt, editform='fetch')
142 n = repo.commit(message, opts['user'], opts['date'], editor=editor)
142 n = repo.commit(message, opts['user'], opts['date'], editor=editor)
143 ui.status(_('new changeset %d:%s merges remote changes '
143 ui.status(_('new changeset %d:%s merges remote changes '
144 'with local\n') % (repo.changelog.rev(n),
144 'with local\n') % (repo.changelog.rev(n),
145 short(n)))
145 short(n)))
146
146
147 return err
147 return err
148
148
149 finally:
149 finally:
150 release(lock, wlock)
150 release(lock, wlock)
@@ -1,3570 +1,3571 b''
1 # mq.py - patch queues for mercurial
1 # mq.py - patch queues for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 '''manage a stack of patches
8 '''manage a stack of patches
9
9
10 This extension lets you work with a stack of patches in a Mercurial
10 This extension lets you work with a stack of patches in a Mercurial
11 repository. It manages two stacks of patches - all known patches, and
11 repository. It manages two stacks of patches - all known patches, and
12 applied patches (subset of known patches).
12 applied patches (subset of known patches).
13
13
14 Known patches are represented as patch files in the .hg/patches
14 Known patches are represented as patch files in the .hg/patches
15 directory. Applied patches are both patch files and changesets.
15 directory. Applied patches are both patch files and changesets.
16
16
17 Common tasks (use :hg:`help command` for more details)::
17 Common tasks (use :hg:`help command` for more details)::
18
18
19 create new patch qnew
19 create new patch qnew
20 import existing patch qimport
20 import existing patch qimport
21
21
22 print patch series qseries
22 print patch series qseries
23 print applied patches qapplied
23 print applied patches qapplied
24
24
25 add known patch to applied stack qpush
25 add known patch to applied stack qpush
26 remove patch from applied stack qpop
26 remove patch from applied stack qpop
27 refresh contents of top applied patch qrefresh
27 refresh contents of top applied patch qrefresh
28
28
29 By default, mq will automatically use git patches when required to
29 By default, mq will automatically use git patches when required to
30 avoid losing file mode changes, copy records, binary files or empty
30 avoid losing file mode changes, copy records, binary files or empty
31 files creations or deletions. This behaviour can be configured with::
31 files creations or deletions. This behaviour can be configured with::
32
32
33 [mq]
33 [mq]
34 git = auto/keep/yes/no
34 git = auto/keep/yes/no
35
35
36 If set to 'keep', mq will obey the [diff] section configuration while
36 If set to 'keep', mq will obey the [diff] section configuration while
37 preserving existing git patches upon qrefresh. If set to 'yes' or
37 preserving existing git patches upon qrefresh. If set to 'yes' or
38 'no', mq will override the [diff] section and always generate git or
38 'no', mq will override the [diff] section and always generate git or
39 regular patches, possibly losing data in the second case.
39 regular patches, possibly losing data in the second case.
40
40
41 It may be desirable for mq changesets to be kept in the secret phase (see
41 It may be desirable for mq changesets to be kept in the secret phase (see
42 :hg:`help phases`), which can be enabled with the following setting::
42 :hg:`help phases`), which can be enabled with the following setting::
43
43
44 [mq]
44 [mq]
45 secret = True
45 secret = True
46
46
47 You will by default be managing a patch queue named "patches". You can
47 You will by default be managing a patch queue named "patches". You can
48 create other, independent patch queues with the :hg:`qqueue` command.
48 create other, independent patch queues with the :hg:`qqueue` command.
49
49
50 If the working directory contains uncommitted files, qpush, qpop and
50 If the working directory contains uncommitted files, qpush, qpop and
51 qgoto abort immediately. If -f/--force is used, the changes are
51 qgoto abort immediately. If -f/--force is used, the changes are
52 discarded. Setting::
52 discarded. Setting::
53
53
54 [mq]
54 [mq]
55 keepchanges = True
55 keepchanges = True
56
56
57 make them behave as if --keep-changes were passed, and non-conflicting
57 make them behave as if --keep-changes were passed, and non-conflicting
58 local changes will be tolerated and preserved. If incompatible options
58 local changes will be tolerated and preserved. If incompatible options
59 such as -f/--force or --exact are passed, this setting is ignored.
59 such as -f/--force or --exact are passed, this setting is ignored.
60
60
61 This extension used to provide a strip command. This command now lives
61 This extension used to provide a strip command. This command now lives
62 in the strip extension.
62 in the strip extension.
63 '''
63 '''
64
64
65 from mercurial.i18n import _
65 from mercurial.i18n import _
66 from mercurial.node import bin, hex, short, nullid, nullrev
66 from mercurial.node import bin, hex, short, nullid, nullrev
67 from mercurial.lock import release
67 from mercurial.lock import release
68 from mercurial import commands, cmdutil, hg, scmutil, util, revset
68 from mercurial import commands, cmdutil, hg, scmutil, util, revset
69 from mercurial import extensions, error, phases
69 from mercurial import extensions, error, phases
70 from mercurial import patch as patchmod
70 from mercurial import patch as patchmod
71 from mercurial import localrepo
71 from mercurial import localrepo
72 from mercurial import subrepo
72 from mercurial import subrepo
73 import os, re, errno, shutil
73 import os, re, errno, shutil
74
74
75 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
75 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
76
76
77 cmdtable = {}
77 cmdtable = {}
78 command = cmdutil.command(cmdtable)
78 command = cmdutil.command(cmdtable)
79 testedwith = 'internal'
79 testedwith = 'internal'
80
80
81 # force load strip extension formerly included in mq and import some utility
81 # force load strip extension formerly included in mq and import some utility
82 try:
82 try:
83 stripext = extensions.find('strip')
83 stripext = extensions.find('strip')
84 except KeyError:
84 except KeyError:
85 # note: load is lazy so we could avoid the try-except,
85 # note: load is lazy so we could avoid the try-except,
86 # but I (marmoute) prefer this explicit code.
86 # but I (marmoute) prefer this explicit code.
87 class dummyui(object):
87 class dummyui(object):
88 def debug(self, msg):
88 def debug(self, msg):
89 pass
89 pass
90 stripext = extensions.load(dummyui(), 'strip', '')
90 stripext = extensions.load(dummyui(), 'strip', '')
91
91
92 strip = stripext.strip
92 strip = stripext.strip
93 checksubstate = stripext.checksubstate
93 checksubstate = stripext.checksubstate
94 checklocalchanges = stripext.checklocalchanges
94 checklocalchanges = stripext.checklocalchanges
95
95
96
96
97 # Patch names looks like unix-file names.
97 # Patch names looks like unix-file names.
98 # They must be joinable with queue directory and result in the patch path.
98 # They must be joinable with queue directory and result in the patch path.
99 normname = util.normpath
99 normname = util.normpath
100
100
101 class statusentry(object):
101 class statusentry(object):
102 def __init__(self, node, name):
102 def __init__(self, node, name):
103 self.node, self.name = node, name
103 self.node, self.name = node, name
104 def __repr__(self):
104 def __repr__(self):
105 return hex(self.node) + ':' + self.name
105 return hex(self.node) + ':' + self.name
106
106
107 # The order of the headers in 'hg export' HG patches:
107 # The order of the headers in 'hg export' HG patches:
108 HGHEADERS = [
108 HGHEADERS = [
109 # '# HG changeset patch',
109 # '# HG changeset patch',
110 '# User ',
110 '# User ',
111 '# Date ',
111 '# Date ',
112 '# ',
112 '# ',
113 '# Branch ',
113 '# Branch ',
114 '# Node ID ',
114 '# Node ID ',
115 '# Parent ', # can occur twice for merges - but that is not relevant for mq
115 '# Parent ', # can occur twice for merges - but that is not relevant for mq
116 ]
116 ]
117 # The order of headers in plain 'mail style' patches:
117 # The order of headers in plain 'mail style' patches:
118 PLAINHEADERS = {
118 PLAINHEADERS = {
119 'from': 0,
119 'from': 0,
120 'date': 1,
120 'date': 1,
121 'subject': 2,
121 'subject': 2,
122 }
122 }
123
123
124 def inserthgheader(lines, header, value):
124 def inserthgheader(lines, header, value):
125 """Assuming lines contains a HG patch header, add a header line with value.
125 """Assuming lines contains a HG patch header, add a header line with value.
126 >>> try: inserthgheader([], '# Date ', 'z')
126 >>> try: inserthgheader([], '# Date ', 'z')
127 ... except ValueError, inst: print "oops"
127 ... except ValueError, inst: print "oops"
128 oops
128 oops
129 >>> inserthgheader(['# HG changeset patch'], '# Date ', 'z')
129 >>> inserthgheader(['# HG changeset patch'], '# Date ', 'z')
130 ['# HG changeset patch', '# Date z']
130 ['# HG changeset patch', '# Date z']
131 >>> inserthgheader(['# HG changeset patch', ''], '# Date ', 'z')
131 >>> inserthgheader(['# HG changeset patch', ''], '# Date ', 'z')
132 ['# HG changeset patch', '# Date z', '']
132 ['# HG changeset patch', '# Date z', '']
133 >>> inserthgheader(['# HG changeset patch', '# User y'], '# Date ', 'z')
133 >>> inserthgheader(['# HG changeset patch', '# User y'], '# Date ', 'z')
134 ['# HG changeset patch', '# User y', '# Date z']
134 ['# HG changeset patch', '# User y', '# Date z']
135 >>> inserthgheader(['# HG changeset patch', '# Date x', '# User y'],
135 >>> inserthgheader(['# HG changeset patch', '# Date x', '# User y'],
136 ... '# User ', 'z')
136 ... '# User ', 'z')
137 ['# HG changeset patch', '# Date x', '# User z']
137 ['# HG changeset patch', '# Date x', '# User z']
138 >>> inserthgheader(['# HG changeset patch', '# Date y'], '# Date ', 'z')
138 >>> inserthgheader(['# HG changeset patch', '# Date y'], '# Date ', 'z')
139 ['# HG changeset patch', '# Date z']
139 ['# HG changeset patch', '# Date z']
140 >>> inserthgheader(['# HG changeset patch', '', '# Date y'], '# Date ', 'z')
140 >>> inserthgheader(['# HG changeset patch', '', '# Date y'], '# Date ', 'z')
141 ['# HG changeset patch', '# Date z', '', '# Date y']
141 ['# HG changeset patch', '# Date z', '', '# Date y']
142 >>> inserthgheader(['# HG changeset patch', '# Parent y'], '# Date ', 'z')
142 >>> inserthgheader(['# HG changeset patch', '# Parent y'], '# Date ', 'z')
143 ['# HG changeset patch', '# Date z', '# Parent y']
143 ['# HG changeset patch', '# Date z', '# Parent y']
144 """
144 """
145 start = lines.index('# HG changeset patch') + 1
145 start = lines.index('# HG changeset patch') + 1
146 newindex = HGHEADERS.index(header)
146 newindex = HGHEADERS.index(header)
147 bestpos = len(lines)
147 bestpos = len(lines)
148 for i in range(start, len(lines)):
148 for i in range(start, len(lines)):
149 line = lines[i]
149 line = lines[i]
150 if not line.startswith('# '):
150 if not line.startswith('# '):
151 bestpos = min(bestpos, i)
151 bestpos = min(bestpos, i)
152 break
152 break
153 for lineindex, h in enumerate(HGHEADERS):
153 for lineindex, h in enumerate(HGHEADERS):
154 if line.startswith(h):
154 if line.startswith(h):
155 if lineindex == newindex:
155 if lineindex == newindex:
156 lines[i] = header + value
156 lines[i] = header + value
157 return lines
157 return lines
158 if lineindex > newindex:
158 if lineindex > newindex:
159 bestpos = min(bestpos, i)
159 bestpos = min(bestpos, i)
160 break # next line
160 break # next line
161 lines.insert(bestpos, header + value)
161 lines.insert(bestpos, header + value)
162 return lines
162 return lines
163
163
164 def insertplainheader(lines, header, value):
164 def insertplainheader(lines, header, value):
165 """For lines containing a plain patch header, add a header line with value.
165 """For lines containing a plain patch header, add a header line with value.
166 >>> insertplainheader([], 'Date', 'z')
166 >>> insertplainheader([], 'Date', 'z')
167 ['Date: z']
167 ['Date: z']
168 >>> insertplainheader([''], 'Date', 'z')
168 >>> insertplainheader([''], 'Date', 'z')
169 ['Date: z', '']
169 ['Date: z', '']
170 >>> insertplainheader(['x'], 'Date', 'z')
170 >>> insertplainheader(['x'], 'Date', 'z')
171 ['Date: z', '', 'x']
171 ['Date: z', '', 'x']
172 >>> insertplainheader(['From: y', 'x'], 'Date', 'z')
172 >>> insertplainheader(['From: y', 'x'], 'Date', 'z')
173 ['From: y', 'Date: z', '', 'x']
173 ['From: y', 'Date: z', '', 'x']
174 >>> insertplainheader([' date : x', ' from : y', ''], 'From', 'z')
174 >>> insertplainheader([' date : x', ' from : y', ''], 'From', 'z')
175 [' date : x', 'From: z', '']
175 [' date : x', 'From: z', '']
176 >>> insertplainheader(['', 'Date: y'], 'Date', 'z')
176 >>> insertplainheader(['', 'Date: y'], 'Date', 'z')
177 ['Date: z', '', 'Date: y']
177 ['Date: z', '', 'Date: y']
178 >>> insertplainheader(['foo: bar', 'DATE: z', 'x'], 'From', 'y')
178 >>> insertplainheader(['foo: bar', 'DATE: z', 'x'], 'From', 'y')
179 ['From: y', 'foo: bar', 'DATE: z', '', 'x']
179 ['From: y', 'foo: bar', 'DATE: z', '', 'x']
180 """
180 """
181 newprio = PLAINHEADERS[header.lower()]
181 newprio = PLAINHEADERS[header.lower()]
182 bestpos = len(lines)
182 bestpos = len(lines)
183 for i, line in enumerate(lines):
183 for i, line in enumerate(lines):
184 if ':' in line:
184 if ':' in line:
185 lheader = line.split(':', 1)[0].strip().lower()
185 lheader = line.split(':', 1)[0].strip().lower()
186 lprio = PLAINHEADERS.get(lheader, newprio + 1)
186 lprio = PLAINHEADERS.get(lheader, newprio + 1)
187 if lprio == newprio:
187 if lprio == newprio:
188 lines[i] = '%s: %s' % (header, value)
188 lines[i] = '%s: %s' % (header, value)
189 return lines
189 return lines
190 if lprio > newprio and i < bestpos:
190 if lprio > newprio and i < bestpos:
191 bestpos = i
191 bestpos = i
192 else:
192 else:
193 if line:
193 if line:
194 lines.insert(i, '')
194 lines.insert(i, '')
195 if i < bestpos:
195 if i < bestpos:
196 bestpos = i
196 bestpos = i
197 break
197 break
198 lines.insert(bestpos, '%s: %s' % (header, value))
198 lines.insert(bestpos, '%s: %s' % (header, value))
199 return lines
199 return lines
200
200
201 class patchheader(object):
201 class patchheader(object):
202 def __init__(self, pf, plainmode=False):
202 def __init__(self, pf, plainmode=False):
203 def eatdiff(lines):
203 def eatdiff(lines):
204 while lines:
204 while lines:
205 l = lines[-1]
205 l = lines[-1]
206 if (l.startswith("diff -") or
206 if (l.startswith("diff -") or
207 l.startswith("Index:") or
207 l.startswith("Index:") or
208 l.startswith("===========")):
208 l.startswith("===========")):
209 del lines[-1]
209 del lines[-1]
210 else:
210 else:
211 break
211 break
212 def eatempty(lines):
212 def eatempty(lines):
213 while lines:
213 while lines:
214 if not lines[-1].strip():
214 if not lines[-1].strip():
215 del lines[-1]
215 del lines[-1]
216 else:
216 else:
217 break
217 break
218
218
219 message = []
219 message = []
220 comments = []
220 comments = []
221 user = None
221 user = None
222 date = None
222 date = None
223 parent = None
223 parent = None
224 format = None
224 format = None
225 subject = None
225 subject = None
226 branch = None
226 branch = None
227 nodeid = None
227 nodeid = None
228 diffstart = 0
228 diffstart = 0
229
229
230 for line in file(pf):
230 for line in file(pf):
231 line = line.rstrip()
231 line = line.rstrip()
232 if (line.startswith('diff --git')
232 if (line.startswith('diff --git')
233 or (diffstart and line.startswith('+++ '))):
233 or (diffstart and line.startswith('+++ '))):
234 diffstart = 2
234 diffstart = 2
235 break
235 break
236 diffstart = 0 # reset
236 diffstart = 0 # reset
237 if line.startswith("--- "):
237 if line.startswith("--- "):
238 diffstart = 1
238 diffstart = 1
239 continue
239 continue
240 elif format == "hgpatch":
240 elif format == "hgpatch":
241 # parse values when importing the result of an hg export
241 # parse values when importing the result of an hg export
242 if line.startswith("# User "):
242 if line.startswith("# User "):
243 user = line[7:]
243 user = line[7:]
244 elif line.startswith("# Date "):
244 elif line.startswith("# Date "):
245 date = line[7:]
245 date = line[7:]
246 elif line.startswith("# Parent "):
246 elif line.startswith("# Parent "):
247 parent = line[9:].lstrip() # handle double trailing space
247 parent = line[9:].lstrip() # handle double trailing space
248 elif line.startswith("# Branch "):
248 elif line.startswith("# Branch "):
249 branch = line[9:]
249 branch = line[9:]
250 elif line.startswith("# Node ID "):
250 elif line.startswith("# Node ID "):
251 nodeid = line[10:]
251 nodeid = line[10:]
252 elif not line.startswith("# ") and line:
252 elif not line.startswith("# ") and line:
253 message.append(line)
253 message.append(line)
254 format = None
254 format = None
255 elif line == '# HG changeset patch':
255 elif line == '# HG changeset patch':
256 message = []
256 message = []
257 format = "hgpatch"
257 format = "hgpatch"
258 elif (format != "tagdone" and (line.startswith("Subject: ") or
258 elif (format != "tagdone" and (line.startswith("Subject: ") or
259 line.startswith("subject: "))):
259 line.startswith("subject: "))):
260 subject = line[9:]
260 subject = line[9:]
261 format = "tag"
261 format = "tag"
262 elif (format != "tagdone" and (line.startswith("From: ") or
262 elif (format != "tagdone" and (line.startswith("From: ") or
263 line.startswith("from: "))):
263 line.startswith("from: "))):
264 user = line[6:]
264 user = line[6:]
265 format = "tag"
265 format = "tag"
266 elif (format != "tagdone" and (line.startswith("Date: ") or
266 elif (format != "tagdone" and (line.startswith("Date: ") or
267 line.startswith("date: "))):
267 line.startswith("date: "))):
268 date = line[6:]
268 date = line[6:]
269 format = "tag"
269 format = "tag"
270 elif format == "tag" and line == "":
270 elif format == "tag" and line == "":
271 # when looking for tags (subject: from: etc) they
271 # when looking for tags (subject: from: etc) they
272 # end once you find a blank line in the source
272 # end once you find a blank line in the source
273 format = "tagdone"
273 format = "tagdone"
274 elif message or line:
274 elif message or line:
275 message.append(line)
275 message.append(line)
276 comments.append(line)
276 comments.append(line)
277
277
278 eatdiff(message)
278 eatdiff(message)
279 eatdiff(comments)
279 eatdiff(comments)
280 # Remember the exact starting line of the patch diffs before consuming
280 # Remember the exact starting line of the patch diffs before consuming
281 # empty lines, for external use by TortoiseHg and others
281 # empty lines, for external use by TortoiseHg and others
282 self.diffstartline = len(comments)
282 self.diffstartline = len(comments)
283 eatempty(message)
283 eatempty(message)
284 eatempty(comments)
284 eatempty(comments)
285
285
286 # make sure message isn't empty
286 # make sure message isn't empty
287 if format and format.startswith("tag") and subject:
287 if format and format.startswith("tag") and subject:
288 message.insert(0, subject)
288 message.insert(0, subject)
289
289
290 self.message = message
290 self.message = message
291 self.comments = comments
291 self.comments = comments
292 self.user = user
292 self.user = user
293 self.date = date
293 self.date = date
294 self.parent = parent
294 self.parent = parent
295 # nodeid and branch are for external use by TortoiseHg and others
295 # nodeid and branch are for external use by TortoiseHg and others
296 self.nodeid = nodeid
296 self.nodeid = nodeid
297 self.branch = branch
297 self.branch = branch
298 self.haspatch = diffstart > 1
298 self.haspatch = diffstart > 1
299 self.plainmode = (plainmode or
299 self.plainmode = (plainmode or
300 '# HG changeset patch' not in self.comments and
300 '# HG changeset patch' not in self.comments and
301 util.any(c.startswith('Date: ') or
301 util.any(c.startswith('Date: ') or
302 c.startswith('From: ')
302 c.startswith('From: ')
303 for c in self.comments))
303 for c in self.comments))
304
304
305 def setuser(self, user):
305 def setuser(self, user):
306 try:
306 try:
307 inserthgheader(self.comments, '# User ', user)
307 inserthgheader(self.comments, '# User ', user)
308 except ValueError:
308 except ValueError:
309 if self.plainmode:
309 if self.plainmode:
310 insertplainheader(self.comments, 'From', user)
310 insertplainheader(self.comments, 'From', user)
311 else:
311 else:
312 tmp = ['# HG changeset patch', '# User ' + user]
312 tmp = ['# HG changeset patch', '# User ' + user]
313 self.comments = tmp + self.comments
313 self.comments = tmp + self.comments
314 self.user = user
314 self.user = user
315
315
316 def setdate(self, date):
316 def setdate(self, date):
317 try:
317 try:
318 inserthgheader(self.comments, '# Date ', date)
318 inserthgheader(self.comments, '# Date ', date)
319 except ValueError:
319 except ValueError:
320 if self.plainmode:
320 if self.plainmode:
321 insertplainheader(self.comments, 'Date', date)
321 insertplainheader(self.comments, 'Date', date)
322 else:
322 else:
323 tmp = ['# HG changeset patch', '# Date ' + date]
323 tmp = ['# HG changeset patch', '# Date ' + date]
324 self.comments = tmp + self.comments
324 self.comments = tmp + self.comments
325 self.date = date
325 self.date = date
326
326
327 def setparent(self, parent):
327 def setparent(self, parent):
328 try:
328 try:
329 inserthgheader(self.comments, '# Parent ', parent)
329 inserthgheader(self.comments, '# Parent ', parent)
330 except ValueError:
330 except ValueError:
331 if not self.plainmode:
331 if not self.plainmode:
332 tmp = ['# HG changeset patch', '# Parent ' + parent]
332 tmp = ['# HG changeset patch', '# Parent ' + parent]
333 self.comments = tmp + self.comments
333 self.comments = tmp + self.comments
334 self.parent = parent
334 self.parent = parent
335
335
336 def setmessage(self, message):
336 def setmessage(self, message):
337 if self.comments:
337 if self.comments:
338 self._delmsg()
338 self._delmsg()
339 self.message = [message]
339 self.message = [message]
340 if message:
340 if message:
341 if self.plainmode and self.comments and self.comments[-1]:
341 if self.plainmode and self.comments and self.comments[-1]:
342 self.comments.append('')
342 self.comments.append('')
343 self.comments.append(message)
343 self.comments.append(message)
344
344
345 def __str__(self):
345 def __str__(self):
346 s = '\n'.join(self.comments).rstrip()
346 s = '\n'.join(self.comments).rstrip()
347 if not s:
347 if not s:
348 return ''
348 return ''
349 return s + '\n\n'
349 return s + '\n\n'
350
350
351 def _delmsg(self):
351 def _delmsg(self):
352 '''Remove existing message, keeping the rest of the comments fields.
352 '''Remove existing message, keeping the rest of the comments fields.
353 If comments contains 'subject: ', message will prepend
353 If comments contains 'subject: ', message will prepend
354 the field and a blank line.'''
354 the field and a blank line.'''
355 if self.message:
355 if self.message:
356 subj = 'subject: ' + self.message[0].lower()
356 subj = 'subject: ' + self.message[0].lower()
357 for i in xrange(len(self.comments)):
357 for i in xrange(len(self.comments)):
358 if subj == self.comments[i].lower():
358 if subj == self.comments[i].lower():
359 del self.comments[i]
359 del self.comments[i]
360 self.message = self.message[2:]
360 self.message = self.message[2:]
361 break
361 break
362 ci = 0
362 ci = 0
363 for mi in self.message:
363 for mi in self.message:
364 while mi != self.comments[ci]:
364 while mi != self.comments[ci]:
365 ci += 1
365 ci += 1
366 del self.comments[ci]
366 del self.comments[ci]
367
367
368 def newcommit(repo, phase, *args, **kwargs):
368 def newcommit(repo, phase, *args, **kwargs):
369 """helper dedicated to ensure a commit respect mq.secret setting
369 """helper dedicated to ensure a commit respect mq.secret setting
370
370
371 It should be used instead of repo.commit inside the mq source for operation
371 It should be used instead of repo.commit inside the mq source for operation
372 creating new changeset.
372 creating new changeset.
373 """
373 """
374 repo = repo.unfiltered()
374 repo = repo.unfiltered()
375 if phase is None:
375 if phase is None:
376 if repo.ui.configbool('mq', 'secret', False):
376 if repo.ui.configbool('mq', 'secret', False):
377 phase = phases.secret
377 phase = phases.secret
378 if phase is not None:
378 if phase is not None:
379 backup = repo.ui.backupconfig('phases', 'new-commit')
379 backup = repo.ui.backupconfig('phases', 'new-commit')
380 try:
380 try:
381 if phase is not None:
381 if phase is not None:
382 repo.ui.setconfig('phases', 'new-commit', phase, 'mq')
382 repo.ui.setconfig('phases', 'new-commit', phase, 'mq')
383 return repo.commit(*args, **kwargs)
383 return repo.commit(*args, **kwargs)
384 finally:
384 finally:
385 if phase is not None:
385 if phase is not None:
386 repo.ui.restoreconfig(backup)
386 repo.ui.restoreconfig(backup)
387
387
388 class AbortNoCleanup(error.Abort):
388 class AbortNoCleanup(error.Abort):
389 pass
389 pass
390
390
391 class queue(object):
391 class queue(object):
392 def __init__(self, ui, baseui, path, patchdir=None):
392 def __init__(self, ui, baseui, path, patchdir=None):
393 self.basepath = path
393 self.basepath = path
394 try:
394 try:
395 fh = open(os.path.join(path, 'patches.queue'))
395 fh = open(os.path.join(path, 'patches.queue'))
396 cur = fh.read().rstrip()
396 cur = fh.read().rstrip()
397 fh.close()
397 fh.close()
398 if not cur:
398 if not cur:
399 curpath = os.path.join(path, 'patches')
399 curpath = os.path.join(path, 'patches')
400 else:
400 else:
401 curpath = os.path.join(path, 'patches-' + cur)
401 curpath = os.path.join(path, 'patches-' + cur)
402 except IOError:
402 except IOError:
403 curpath = os.path.join(path, 'patches')
403 curpath = os.path.join(path, 'patches')
404 self.path = patchdir or curpath
404 self.path = patchdir or curpath
405 self.opener = scmutil.opener(self.path)
405 self.opener = scmutil.opener(self.path)
406 self.ui = ui
406 self.ui = ui
407 self.baseui = baseui
407 self.baseui = baseui
408 self.applieddirty = False
408 self.applieddirty = False
409 self.seriesdirty = False
409 self.seriesdirty = False
410 self.added = []
410 self.added = []
411 self.seriespath = "series"
411 self.seriespath = "series"
412 self.statuspath = "status"
412 self.statuspath = "status"
413 self.guardspath = "guards"
413 self.guardspath = "guards"
414 self.activeguards = None
414 self.activeguards = None
415 self.guardsdirty = False
415 self.guardsdirty = False
416 # Handle mq.git as a bool with extended values
416 # Handle mq.git as a bool with extended values
417 try:
417 try:
418 gitmode = ui.configbool('mq', 'git', None)
418 gitmode = ui.configbool('mq', 'git', None)
419 if gitmode is None:
419 if gitmode is None:
420 raise error.ConfigError
420 raise error.ConfigError
421 if gitmode:
421 if gitmode:
422 self.gitmode = 'yes'
422 self.gitmode = 'yes'
423 else:
423 else:
424 self.gitmode = 'no'
424 self.gitmode = 'no'
425 except error.ConfigError:
425 except error.ConfigError:
426 self.gitmode = ui.config('mq', 'git', 'auto').lower()
426 self.gitmode = ui.config('mq', 'git', 'auto').lower()
427 self.plainmode = ui.configbool('mq', 'plain', False)
427 self.plainmode = ui.configbool('mq', 'plain', False)
428 self.checkapplied = True
428 self.checkapplied = True
429
429
430 @util.propertycache
430 @util.propertycache
431 def applied(self):
431 def applied(self):
432 def parselines(lines):
432 def parselines(lines):
433 for l in lines:
433 for l in lines:
434 entry = l.split(':', 1)
434 entry = l.split(':', 1)
435 if len(entry) > 1:
435 if len(entry) > 1:
436 n, name = entry
436 n, name = entry
437 yield statusentry(bin(n), name)
437 yield statusentry(bin(n), name)
438 elif l.strip():
438 elif l.strip():
439 self.ui.warn(_('malformated mq status line: %s\n') % entry)
439 self.ui.warn(_('malformated mq status line: %s\n') % entry)
440 # else we ignore empty lines
440 # else we ignore empty lines
441 try:
441 try:
442 lines = self.opener.read(self.statuspath).splitlines()
442 lines = self.opener.read(self.statuspath).splitlines()
443 return list(parselines(lines))
443 return list(parselines(lines))
444 except IOError, e:
444 except IOError, e:
445 if e.errno == errno.ENOENT:
445 if e.errno == errno.ENOENT:
446 return []
446 return []
447 raise
447 raise
448
448
449 @util.propertycache
449 @util.propertycache
450 def fullseries(self):
450 def fullseries(self):
451 try:
451 try:
452 return self.opener.read(self.seriespath).splitlines()
452 return self.opener.read(self.seriespath).splitlines()
453 except IOError, e:
453 except IOError, e:
454 if e.errno == errno.ENOENT:
454 if e.errno == errno.ENOENT:
455 return []
455 return []
456 raise
456 raise
457
457
458 @util.propertycache
458 @util.propertycache
459 def series(self):
459 def series(self):
460 self.parseseries()
460 self.parseseries()
461 return self.series
461 return self.series
462
462
463 @util.propertycache
463 @util.propertycache
464 def seriesguards(self):
464 def seriesguards(self):
465 self.parseseries()
465 self.parseseries()
466 return self.seriesguards
466 return self.seriesguards
467
467
468 def invalidate(self):
468 def invalidate(self):
469 for a in 'applied fullseries series seriesguards'.split():
469 for a in 'applied fullseries series seriesguards'.split():
470 if a in self.__dict__:
470 if a in self.__dict__:
471 delattr(self, a)
471 delattr(self, a)
472 self.applieddirty = False
472 self.applieddirty = False
473 self.seriesdirty = False
473 self.seriesdirty = False
474 self.guardsdirty = False
474 self.guardsdirty = False
475 self.activeguards = None
475 self.activeguards = None
476
476
477 def diffopts(self, opts={}, patchfn=None):
477 def diffopts(self, opts={}, patchfn=None):
478 diffopts = patchmod.diffopts(self.ui, opts)
478 diffopts = patchmod.diffopts(self.ui, opts)
479 if self.gitmode == 'auto':
479 if self.gitmode == 'auto':
480 diffopts.upgrade = True
480 diffopts.upgrade = True
481 elif self.gitmode == 'keep':
481 elif self.gitmode == 'keep':
482 pass
482 pass
483 elif self.gitmode in ('yes', 'no'):
483 elif self.gitmode in ('yes', 'no'):
484 diffopts.git = self.gitmode == 'yes'
484 diffopts.git = self.gitmode == 'yes'
485 else:
485 else:
486 raise util.Abort(_('mq.git option can be auto/keep/yes/no'
486 raise util.Abort(_('mq.git option can be auto/keep/yes/no'
487 ' got %s') % self.gitmode)
487 ' got %s') % self.gitmode)
488 if patchfn:
488 if patchfn:
489 diffopts = self.patchopts(diffopts, patchfn)
489 diffopts = self.patchopts(diffopts, patchfn)
490 return diffopts
490 return diffopts
491
491
492 def patchopts(self, diffopts, *patches):
492 def patchopts(self, diffopts, *patches):
493 """Return a copy of input diff options with git set to true if
493 """Return a copy of input diff options with git set to true if
494 referenced patch is a git patch and should be preserved as such.
494 referenced patch is a git patch and should be preserved as such.
495 """
495 """
496 diffopts = diffopts.copy()
496 diffopts = diffopts.copy()
497 if not diffopts.git and self.gitmode == 'keep':
497 if not diffopts.git and self.gitmode == 'keep':
498 for patchfn in patches:
498 for patchfn in patches:
499 patchf = self.opener(patchfn, 'r')
499 patchf = self.opener(patchfn, 'r')
500 # if the patch was a git patch, refresh it as a git patch
500 # if the patch was a git patch, refresh it as a git patch
501 for line in patchf:
501 for line in patchf:
502 if line.startswith('diff --git'):
502 if line.startswith('diff --git'):
503 diffopts.git = True
503 diffopts.git = True
504 break
504 break
505 patchf.close()
505 patchf.close()
506 return diffopts
506 return diffopts
507
507
508 def join(self, *p):
508 def join(self, *p):
509 return os.path.join(self.path, *p)
509 return os.path.join(self.path, *p)
510
510
511 def findseries(self, patch):
511 def findseries(self, patch):
512 def matchpatch(l):
512 def matchpatch(l):
513 l = l.split('#', 1)[0]
513 l = l.split('#', 1)[0]
514 return l.strip() == patch
514 return l.strip() == patch
515 for index, l in enumerate(self.fullseries):
515 for index, l in enumerate(self.fullseries):
516 if matchpatch(l):
516 if matchpatch(l):
517 return index
517 return index
518 return None
518 return None
519
519
520 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
520 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
521
521
522 def parseseries(self):
522 def parseseries(self):
523 self.series = []
523 self.series = []
524 self.seriesguards = []
524 self.seriesguards = []
525 for l in self.fullseries:
525 for l in self.fullseries:
526 h = l.find('#')
526 h = l.find('#')
527 if h == -1:
527 if h == -1:
528 patch = l
528 patch = l
529 comment = ''
529 comment = ''
530 elif h == 0:
530 elif h == 0:
531 continue
531 continue
532 else:
532 else:
533 patch = l[:h]
533 patch = l[:h]
534 comment = l[h:]
534 comment = l[h:]
535 patch = patch.strip()
535 patch = patch.strip()
536 if patch:
536 if patch:
537 if patch in self.series:
537 if patch in self.series:
538 raise util.Abort(_('%s appears more than once in %s') %
538 raise util.Abort(_('%s appears more than once in %s') %
539 (patch, self.join(self.seriespath)))
539 (patch, self.join(self.seriespath)))
540 self.series.append(patch)
540 self.series.append(patch)
541 self.seriesguards.append(self.guard_re.findall(comment))
541 self.seriesguards.append(self.guard_re.findall(comment))
542
542
543 def checkguard(self, guard):
543 def checkguard(self, guard):
544 if not guard:
544 if not guard:
545 return _('guard cannot be an empty string')
545 return _('guard cannot be an empty string')
546 bad_chars = '# \t\r\n\f'
546 bad_chars = '# \t\r\n\f'
547 first = guard[0]
547 first = guard[0]
548 if first in '-+':
548 if first in '-+':
549 return (_('guard %r starts with invalid character: %r') %
549 return (_('guard %r starts with invalid character: %r') %
550 (guard, first))
550 (guard, first))
551 for c in bad_chars:
551 for c in bad_chars:
552 if c in guard:
552 if c in guard:
553 return _('invalid character in guard %r: %r') % (guard, c)
553 return _('invalid character in guard %r: %r') % (guard, c)
554
554
555 def setactive(self, guards):
555 def setactive(self, guards):
556 for guard in guards:
556 for guard in guards:
557 bad = self.checkguard(guard)
557 bad = self.checkguard(guard)
558 if bad:
558 if bad:
559 raise util.Abort(bad)
559 raise util.Abort(bad)
560 guards = sorted(set(guards))
560 guards = sorted(set(guards))
561 self.ui.debug('active guards: %s\n' % ' '.join(guards))
561 self.ui.debug('active guards: %s\n' % ' '.join(guards))
562 self.activeguards = guards
562 self.activeguards = guards
563 self.guardsdirty = True
563 self.guardsdirty = True
564
564
565 def active(self):
565 def active(self):
566 if self.activeguards is None:
566 if self.activeguards is None:
567 self.activeguards = []
567 self.activeguards = []
568 try:
568 try:
569 guards = self.opener.read(self.guardspath).split()
569 guards = self.opener.read(self.guardspath).split()
570 except IOError, err:
570 except IOError, err:
571 if err.errno != errno.ENOENT:
571 if err.errno != errno.ENOENT:
572 raise
572 raise
573 guards = []
573 guards = []
574 for i, guard in enumerate(guards):
574 for i, guard in enumerate(guards):
575 bad = self.checkguard(guard)
575 bad = self.checkguard(guard)
576 if bad:
576 if bad:
577 self.ui.warn('%s:%d: %s\n' %
577 self.ui.warn('%s:%d: %s\n' %
578 (self.join(self.guardspath), i + 1, bad))
578 (self.join(self.guardspath), i + 1, bad))
579 else:
579 else:
580 self.activeguards.append(guard)
580 self.activeguards.append(guard)
581 return self.activeguards
581 return self.activeguards
582
582
583 def setguards(self, idx, guards):
583 def setguards(self, idx, guards):
584 for g in guards:
584 for g in guards:
585 if len(g) < 2:
585 if len(g) < 2:
586 raise util.Abort(_('guard %r too short') % g)
586 raise util.Abort(_('guard %r too short') % g)
587 if g[0] not in '-+':
587 if g[0] not in '-+':
588 raise util.Abort(_('guard %r starts with invalid char') % g)
588 raise util.Abort(_('guard %r starts with invalid char') % g)
589 bad = self.checkguard(g[1:])
589 bad = self.checkguard(g[1:])
590 if bad:
590 if bad:
591 raise util.Abort(bad)
591 raise util.Abort(bad)
592 drop = self.guard_re.sub('', self.fullseries[idx])
592 drop = self.guard_re.sub('', self.fullseries[idx])
593 self.fullseries[idx] = drop + ''.join([' #' + g for g in guards])
593 self.fullseries[idx] = drop + ''.join([' #' + g for g in guards])
594 self.parseseries()
594 self.parseseries()
595 self.seriesdirty = True
595 self.seriesdirty = True
596
596
597 def pushable(self, idx):
597 def pushable(self, idx):
598 if isinstance(idx, str):
598 if isinstance(idx, str):
599 idx = self.series.index(idx)
599 idx = self.series.index(idx)
600 patchguards = self.seriesguards[idx]
600 patchguards = self.seriesguards[idx]
601 if not patchguards:
601 if not patchguards:
602 return True, None
602 return True, None
603 guards = self.active()
603 guards = self.active()
604 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
604 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
605 if exactneg:
605 if exactneg:
606 return False, repr(exactneg[0])
606 return False, repr(exactneg[0])
607 pos = [g for g in patchguards if g[0] == '+']
607 pos = [g for g in patchguards if g[0] == '+']
608 exactpos = [g for g in pos if g[1:] in guards]
608 exactpos = [g for g in pos if g[1:] in guards]
609 if pos:
609 if pos:
610 if exactpos:
610 if exactpos:
611 return True, repr(exactpos[0])
611 return True, repr(exactpos[0])
612 return False, ' '.join(map(repr, pos))
612 return False, ' '.join(map(repr, pos))
613 return True, ''
613 return True, ''
614
614
615 def explainpushable(self, idx, all_patches=False):
615 def explainpushable(self, idx, all_patches=False):
616 if all_patches:
616 if all_patches:
617 write = self.ui.write
617 write = self.ui.write
618 else:
618 else:
619 write = self.ui.warn
619 write = self.ui.warn
620
620
621 if all_patches or self.ui.verbose:
621 if all_patches or self.ui.verbose:
622 if isinstance(idx, str):
622 if isinstance(idx, str):
623 idx = self.series.index(idx)
623 idx = self.series.index(idx)
624 pushable, why = self.pushable(idx)
624 pushable, why = self.pushable(idx)
625 if all_patches and pushable:
625 if all_patches and pushable:
626 if why is None:
626 if why is None:
627 write(_('allowing %s - no guards in effect\n') %
627 write(_('allowing %s - no guards in effect\n') %
628 self.series[idx])
628 self.series[idx])
629 else:
629 else:
630 if not why:
630 if not why:
631 write(_('allowing %s - no matching negative guards\n') %
631 write(_('allowing %s - no matching negative guards\n') %
632 self.series[idx])
632 self.series[idx])
633 else:
633 else:
634 write(_('allowing %s - guarded by %s\n') %
634 write(_('allowing %s - guarded by %s\n') %
635 (self.series[idx], why))
635 (self.series[idx], why))
636 if not pushable:
636 if not pushable:
637 if why:
637 if why:
638 write(_('skipping %s - guarded by %s\n') %
638 write(_('skipping %s - guarded by %s\n') %
639 (self.series[idx], why))
639 (self.series[idx], why))
640 else:
640 else:
641 write(_('skipping %s - no matching guards\n') %
641 write(_('skipping %s - no matching guards\n') %
642 self.series[idx])
642 self.series[idx])
643
643
644 def savedirty(self):
644 def savedirty(self):
645 def writelist(items, path):
645 def writelist(items, path):
646 fp = self.opener(path, 'w')
646 fp = self.opener(path, 'w')
647 for i in items:
647 for i in items:
648 fp.write("%s\n" % i)
648 fp.write("%s\n" % i)
649 fp.close()
649 fp.close()
650 if self.applieddirty:
650 if self.applieddirty:
651 writelist(map(str, self.applied), self.statuspath)
651 writelist(map(str, self.applied), self.statuspath)
652 self.applieddirty = False
652 self.applieddirty = False
653 if self.seriesdirty:
653 if self.seriesdirty:
654 writelist(self.fullseries, self.seriespath)
654 writelist(self.fullseries, self.seriespath)
655 self.seriesdirty = False
655 self.seriesdirty = False
656 if self.guardsdirty:
656 if self.guardsdirty:
657 writelist(self.activeguards, self.guardspath)
657 writelist(self.activeguards, self.guardspath)
658 self.guardsdirty = False
658 self.guardsdirty = False
659 if self.added:
659 if self.added:
660 qrepo = self.qrepo()
660 qrepo = self.qrepo()
661 if qrepo:
661 if qrepo:
662 qrepo[None].add(f for f in self.added if f not in qrepo[None])
662 qrepo[None].add(f for f in self.added if f not in qrepo[None])
663 self.added = []
663 self.added = []
664
664
665 def removeundo(self, repo):
665 def removeundo(self, repo):
666 undo = repo.sjoin('undo')
666 undo = repo.sjoin('undo')
667 if not os.path.exists(undo):
667 if not os.path.exists(undo):
668 return
668 return
669 try:
669 try:
670 os.unlink(undo)
670 os.unlink(undo)
671 except OSError, inst:
671 except OSError, inst:
672 self.ui.warn(_('error removing undo: %s\n') % str(inst))
672 self.ui.warn(_('error removing undo: %s\n') % str(inst))
673
673
674 def backup(self, repo, files, copy=False):
674 def backup(self, repo, files, copy=False):
675 # backup local changes in --force case
675 # backup local changes in --force case
676 for f in sorted(files):
676 for f in sorted(files):
677 absf = repo.wjoin(f)
677 absf = repo.wjoin(f)
678 if os.path.lexists(absf):
678 if os.path.lexists(absf):
679 self.ui.note(_('saving current version of %s as %s\n') %
679 self.ui.note(_('saving current version of %s as %s\n') %
680 (f, f + '.orig'))
680 (f, f + '.orig'))
681 if copy:
681 if copy:
682 util.copyfile(absf, absf + '.orig')
682 util.copyfile(absf, absf + '.orig')
683 else:
683 else:
684 util.rename(absf, absf + '.orig')
684 util.rename(absf, absf + '.orig')
685
685
686 def printdiff(self, repo, diffopts, node1, node2=None, files=None,
686 def printdiff(self, repo, diffopts, node1, node2=None, files=None,
687 fp=None, changes=None, opts={}):
687 fp=None, changes=None, opts={}):
688 stat = opts.get('stat')
688 stat = opts.get('stat')
689 m = scmutil.match(repo[node1], files, opts)
689 m = scmutil.match(repo[node1], files, opts)
690 cmdutil.diffordiffstat(self.ui, repo, diffopts, node1, node2, m,
690 cmdutil.diffordiffstat(self.ui, repo, diffopts, node1, node2, m,
691 changes, stat, fp)
691 changes, stat, fp)
692
692
693 def mergeone(self, repo, mergeq, head, patch, rev, diffopts):
693 def mergeone(self, repo, mergeq, head, patch, rev, diffopts):
694 # first try just applying the patch
694 # first try just applying the patch
695 (err, n) = self.apply(repo, [patch], update_status=False,
695 (err, n) = self.apply(repo, [patch], update_status=False,
696 strict=True, merge=rev)
696 strict=True, merge=rev)
697
697
698 if err == 0:
698 if err == 0:
699 return (err, n)
699 return (err, n)
700
700
701 if n is None:
701 if n is None:
702 raise util.Abort(_("apply failed for patch %s") % patch)
702 raise util.Abort(_("apply failed for patch %s") % patch)
703
703
704 self.ui.warn(_("patch didn't work out, merging %s\n") % patch)
704 self.ui.warn(_("patch didn't work out, merging %s\n") % patch)
705
705
706 # apply failed, strip away that rev and merge.
706 # apply failed, strip away that rev and merge.
707 hg.clean(repo, head)
707 hg.clean(repo, head)
708 strip(self.ui, repo, [n], update=False, backup=False)
708 strip(self.ui, repo, [n], update=False, backup=False)
709
709
710 ctx = repo[rev]
710 ctx = repo[rev]
711 ret = hg.merge(repo, rev)
711 ret = hg.merge(repo, rev)
712 if ret:
712 if ret:
713 raise util.Abort(_("update returned %d") % ret)
713 raise util.Abort(_("update returned %d") % ret)
714 n = newcommit(repo, None, ctx.description(), ctx.user(), force=True)
714 n = newcommit(repo, None, ctx.description(), ctx.user(), force=True)
715 if n is None:
715 if n is None:
716 raise util.Abort(_("repo commit failed"))
716 raise util.Abort(_("repo commit failed"))
717 try:
717 try:
718 ph = patchheader(mergeq.join(patch), self.plainmode)
718 ph = patchheader(mergeq.join(patch), self.plainmode)
719 except Exception:
719 except Exception:
720 raise util.Abort(_("unable to read %s") % patch)
720 raise util.Abort(_("unable to read %s") % patch)
721
721
722 diffopts = self.patchopts(diffopts, patch)
722 diffopts = self.patchopts(diffopts, patch)
723 patchf = self.opener(patch, "w")
723 patchf = self.opener(patch, "w")
724 comments = str(ph)
724 comments = str(ph)
725 if comments:
725 if comments:
726 patchf.write(comments)
726 patchf.write(comments)
727 self.printdiff(repo, diffopts, head, n, fp=patchf)
727 self.printdiff(repo, diffopts, head, n, fp=patchf)
728 patchf.close()
728 patchf.close()
729 self.removeundo(repo)
729 self.removeundo(repo)
730 return (0, n)
730 return (0, n)
731
731
732 def qparents(self, repo, rev=None):
732 def qparents(self, repo, rev=None):
733 """return the mq handled parent or p1
733 """return the mq handled parent or p1
734
734
735 In some case where mq get himself in being the parent of a merge the
735 In some case where mq get himself in being the parent of a merge the
736 appropriate parent may be p2.
736 appropriate parent may be p2.
737 (eg: an in progress merge started with mq disabled)
737 (eg: an in progress merge started with mq disabled)
738
738
739 If no parent are managed by mq, p1 is returned.
739 If no parent are managed by mq, p1 is returned.
740 """
740 """
741 if rev is None:
741 if rev is None:
742 (p1, p2) = repo.dirstate.parents()
742 (p1, p2) = repo.dirstate.parents()
743 if p2 == nullid:
743 if p2 == nullid:
744 return p1
744 return p1
745 if not self.applied:
745 if not self.applied:
746 return None
746 return None
747 return self.applied[-1].node
747 return self.applied[-1].node
748 p1, p2 = repo.changelog.parents(rev)
748 p1, p2 = repo.changelog.parents(rev)
749 if p2 != nullid and p2 in [x.node for x in self.applied]:
749 if p2 != nullid and p2 in [x.node for x in self.applied]:
750 return p2
750 return p2
751 return p1
751 return p1
752
752
753 def mergepatch(self, repo, mergeq, series, diffopts):
753 def mergepatch(self, repo, mergeq, series, diffopts):
754 if not self.applied:
754 if not self.applied:
755 # each of the patches merged in will have two parents. This
755 # each of the patches merged in will have two parents. This
756 # can confuse the qrefresh, qdiff, and strip code because it
756 # can confuse the qrefresh, qdiff, and strip code because it
757 # needs to know which parent is actually in the patch queue.
757 # needs to know which parent is actually in the patch queue.
758 # so, we insert a merge marker with only one parent. This way
758 # so, we insert a merge marker with only one parent. This way
759 # the first patch in the queue is never a merge patch
759 # the first patch in the queue is never a merge patch
760 #
760 #
761 pname = ".hg.patches.merge.marker"
761 pname = ".hg.patches.merge.marker"
762 n = newcommit(repo, None, '[mq]: merge marker', force=True)
762 n = newcommit(repo, None, '[mq]: merge marker', force=True)
763 self.removeundo(repo)
763 self.removeundo(repo)
764 self.applied.append(statusentry(n, pname))
764 self.applied.append(statusentry(n, pname))
765 self.applieddirty = True
765 self.applieddirty = True
766
766
767 head = self.qparents(repo)
767 head = self.qparents(repo)
768
768
769 for patch in series:
769 for patch in series:
770 patch = mergeq.lookup(patch, strict=True)
770 patch = mergeq.lookup(patch, strict=True)
771 if not patch:
771 if not patch:
772 self.ui.warn(_("patch %s does not exist\n") % patch)
772 self.ui.warn(_("patch %s does not exist\n") % patch)
773 return (1, None)
773 return (1, None)
774 pushable, reason = self.pushable(patch)
774 pushable, reason = self.pushable(patch)
775 if not pushable:
775 if not pushable:
776 self.explainpushable(patch, all_patches=True)
776 self.explainpushable(patch, all_patches=True)
777 continue
777 continue
778 info = mergeq.isapplied(patch)
778 info = mergeq.isapplied(patch)
779 if not info:
779 if not info:
780 self.ui.warn(_("patch %s is not applied\n") % patch)
780 self.ui.warn(_("patch %s is not applied\n") % patch)
781 return (1, None)
781 return (1, None)
782 rev = info[1]
782 rev = info[1]
783 err, head = self.mergeone(repo, mergeq, head, patch, rev, diffopts)
783 err, head = self.mergeone(repo, mergeq, head, patch, rev, diffopts)
784 if head:
784 if head:
785 self.applied.append(statusentry(head, patch))
785 self.applied.append(statusentry(head, patch))
786 self.applieddirty = True
786 self.applieddirty = True
787 if err:
787 if err:
788 return (err, head)
788 return (err, head)
789 self.savedirty()
789 self.savedirty()
790 return (0, head)
790 return (0, head)
791
791
792 def patch(self, repo, patchfile):
792 def patch(self, repo, patchfile):
793 '''Apply patchfile to the working directory.
793 '''Apply patchfile to the working directory.
794 patchfile: name of patch file'''
794 patchfile: name of patch file'''
795 files = set()
795 files = set()
796 try:
796 try:
797 fuzz = patchmod.patch(self.ui, repo, patchfile, strip=1,
797 fuzz = patchmod.patch(self.ui, repo, patchfile, strip=1,
798 files=files, eolmode=None)
798 files=files, eolmode=None)
799 return (True, list(files), fuzz)
799 return (True, list(files), fuzz)
800 except Exception, inst:
800 except Exception, inst:
801 self.ui.note(str(inst) + '\n')
801 self.ui.note(str(inst) + '\n')
802 if not self.ui.verbose:
802 if not self.ui.verbose:
803 self.ui.warn(_("patch failed, unable to continue (try -v)\n"))
803 self.ui.warn(_("patch failed, unable to continue (try -v)\n"))
804 self.ui.traceback()
804 self.ui.traceback()
805 return (False, list(files), False)
805 return (False, list(files), False)
806
806
807 def apply(self, repo, series, list=False, update_status=True,
807 def apply(self, repo, series, list=False, update_status=True,
808 strict=False, patchdir=None, merge=None, all_files=None,
808 strict=False, patchdir=None, merge=None, all_files=None,
809 tobackup=None, keepchanges=False):
809 tobackup=None, keepchanges=False):
810 wlock = lock = tr = None
810 wlock = lock = tr = None
811 try:
811 try:
812 wlock = repo.wlock()
812 wlock = repo.wlock()
813 lock = repo.lock()
813 lock = repo.lock()
814 tr = repo.transaction("qpush")
814 tr = repo.transaction("qpush")
815 try:
815 try:
816 ret = self._apply(repo, series, list, update_status,
816 ret = self._apply(repo, series, list, update_status,
817 strict, patchdir, merge, all_files=all_files,
817 strict, patchdir, merge, all_files=all_files,
818 tobackup=tobackup, keepchanges=keepchanges)
818 tobackup=tobackup, keepchanges=keepchanges)
819 tr.close()
819 tr.close()
820 self.savedirty()
820 self.savedirty()
821 return ret
821 return ret
822 except AbortNoCleanup:
822 except AbortNoCleanup:
823 tr.close()
823 tr.close()
824 self.savedirty()
824 self.savedirty()
825 return 2, repo.dirstate.p1()
825 return 2, repo.dirstate.p1()
826 except: # re-raises
826 except: # re-raises
827 try:
827 try:
828 tr.abort()
828 tr.abort()
829 finally:
829 finally:
830 repo.invalidate()
830 repo.invalidate()
831 repo.dirstate.invalidate()
831 repo.dirstate.invalidate()
832 self.invalidate()
832 self.invalidate()
833 raise
833 raise
834 finally:
834 finally:
835 release(tr, lock, wlock)
835 release(tr, lock, wlock)
836 self.removeundo(repo)
836 self.removeundo(repo)
837
837
838 def _apply(self, repo, series, list=False, update_status=True,
838 def _apply(self, repo, series, list=False, update_status=True,
839 strict=False, patchdir=None, merge=None, all_files=None,
839 strict=False, patchdir=None, merge=None, all_files=None,
840 tobackup=None, keepchanges=False):
840 tobackup=None, keepchanges=False):
841 """returns (error, hash)
841 """returns (error, hash)
842
842
843 error = 1 for unable to read, 2 for patch failed, 3 for patch
843 error = 1 for unable to read, 2 for patch failed, 3 for patch
844 fuzz. tobackup is None or a set of files to backup before they
844 fuzz. tobackup is None or a set of files to backup before they
845 are modified by a patch.
845 are modified by a patch.
846 """
846 """
847 # TODO unify with commands.py
847 # TODO unify with commands.py
848 if not patchdir:
848 if not patchdir:
849 patchdir = self.path
849 patchdir = self.path
850 err = 0
850 err = 0
851 n = None
851 n = None
852 for patchname in series:
852 for patchname in series:
853 pushable, reason = self.pushable(patchname)
853 pushable, reason = self.pushable(patchname)
854 if not pushable:
854 if not pushable:
855 self.explainpushable(patchname, all_patches=True)
855 self.explainpushable(patchname, all_patches=True)
856 continue
856 continue
857 self.ui.status(_("applying %s\n") % patchname)
857 self.ui.status(_("applying %s\n") % patchname)
858 pf = os.path.join(patchdir, patchname)
858 pf = os.path.join(patchdir, patchname)
859
859
860 try:
860 try:
861 ph = patchheader(self.join(patchname), self.plainmode)
861 ph = patchheader(self.join(patchname), self.plainmode)
862 except IOError:
862 except IOError:
863 self.ui.warn(_("unable to read %s\n") % patchname)
863 self.ui.warn(_("unable to read %s\n") % patchname)
864 err = 1
864 err = 1
865 break
865 break
866
866
867 message = ph.message
867 message = ph.message
868 if not message:
868 if not message:
869 # The commit message should not be translated
869 # The commit message should not be translated
870 message = "imported patch %s\n" % patchname
870 message = "imported patch %s\n" % patchname
871 else:
871 else:
872 if list:
872 if list:
873 # The commit message should not be translated
873 # The commit message should not be translated
874 message.append("\nimported patch %s" % patchname)
874 message.append("\nimported patch %s" % patchname)
875 message = '\n'.join(message)
875 message = '\n'.join(message)
876
876
877 if ph.haspatch:
877 if ph.haspatch:
878 if tobackup:
878 if tobackup:
879 touched = patchmod.changedfiles(self.ui, repo, pf)
879 touched = patchmod.changedfiles(self.ui, repo, pf)
880 touched = set(touched) & tobackup
880 touched = set(touched) & tobackup
881 if touched and keepchanges:
881 if touched and keepchanges:
882 raise AbortNoCleanup(
882 raise AbortNoCleanup(
883 _("local changes found, refresh first"))
883 _("local changes found, refresh first"))
884 self.backup(repo, touched, copy=True)
884 self.backup(repo, touched, copy=True)
885 tobackup = tobackup - touched
885 tobackup = tobackup - touched
886 (patcherr, files, fuzz) = self.patch(repo, pf)
886 (patcherr, files, fuzz) = self.patch(repo, pf)
887 if all_files is not None:
887 if all_files is not None:
888 all_files.update(files)
888 all_files.update(files)
889 patcherr = not patcherr
889 patcherr = not patcherr
890 else:
890 else:
891 self.ui.warn(_("patch %s is empty\n") % patchname)
891 self.ui.warn(_("patch %s is empty\n") % patchname)
892 patcherr, files, fuzz = 0, [], 0
892 patcherr, files, fuzz = 0, [], 0
893
893
894 if merge and files:
894 if merge and files:
895 # Mark as removed/merged and update dirstate parent info
895 # Mark as removed/merged and update dirstate parent info
896 removed = []
896 removed = []
897 merged = []
897 merged = []
898 for f in files:
898 for f in files:
899 if os.path.lexists(repo.wjoin(f)):
899 if os.path.lexists(repo.wjoin(f)):
900 merged.append(f)
900 merged.append(f)
901 else:
901 else:
902 removed.append(f)
902 removed.append(f)
903 repo.dirstate.beginparentchange()
903 repo.dirstate.beginparentchange()
904 for f in removed:
904 for f in removed:
905 repo.dirstate.remove(f)
905 repo.dirstate.remove(f)
906 for f in merged:
906 for f in merged:
907 repo.dirstate.merge(f)
907 repo.dirstate.merge(f)
908 p1, p2 = repo.dirstate.parents()
908 p1, p2 = repo.dirstate.parents()
909 repo.setparents(p1, merge)
909 repo.setparents(p1, merge)
910 repo.dirstate.endparentchange()
910 repo.dirstate.endparentchange()
911
911
912 if all_files and '.hgsubstate' in all_files:
912 if all_files and '.hgsubstate' in all_files:
913 wctx = repo[None]
913 wctx = repo[None]
914 pctx = repo['.']
914 pctx = repo['.']
915 overwrite = False
915 overwrite = False
916 mergedsubstate = subrepo.submerge(repo, pctx, wctx, wctx,
916 mergedsubstate = subrepo.submerge(repo, pctx, wctx, wctx,
917 overwrite)
917 overwrite)
918 files += mergedsubstate.keys()
918 files += mergedsubstate.keys()
919
919
920 match = scmutil.matchfiles(repo, files or [])
920 match = scmutil.matchfiles(repo, files or [])
921 oldtip = repo['tip']
921 oldtip = repo['tip']
922 n = newcommit(repo, None, message, ph.user, ph.date, match=match,
922 n = newcommit(repo, None, message, ph.user, ph.date, match=match,
923 force=True)
923 force=True)
924 if repo['tip'] == oldtip:
924 if repo['tip'] == oldtip:
925 raise util.Abort(_("qpush exactly duplicates child changeset"))
925 raise util.Abort(_("qpush exactly duplicates child changeset"))
926 if n is None:
926 if n is None:
927 raise util.Abort(_("repository commit failed"))
927 raise util.Abort(_("repository commit failed"))
928
928
929 if update_status:
929 if update_status:
930 self.applied.append(statusentry(n, patchname))
930 self.applied.append(statusentry(n, patchname))
931
931
932 if patcherr:
932 if patcherr:
933 self.ui.warn(_("patch failed, rejects left in working dir\n"))
933 self.ui.warn(_("patch failed, rejects left in working "
934 "directory\n"))
934 err = 2
935 err = 2
935 break
936 break
936
937
937 if fuzz and strict:
938 if fuzz and strict:
938 self.ui.warn(_("fuzz found when applying patch, stopping\n"))
939 self.ui.warn(_("fuzz found when applying patch, stopping\n"))
939 err = 3
940 err = 3
940 break
941 break
941 return (err, n)
942 return (err, n)
942
943
943 def _cleanup(self, patches, numrevs, keep=False):
944 def _cleanup(self, patches, numrevs, keep=False):
944 if not keep:
945 if not keep:
945 r = self.qrepo()
946 r = self.qrepo()
946 if r:
947 if r:
947 r[None].forget(patches)
948 r[None].forget(patches)
948 for p in patches:
949 for p in patches:
949 try:
950 try:
950 os.unlink(self.join(p))
951 os.unlink(self.join(p))
951 except OSError, inst:
952 except OSError, inst:
952 if inst.errno != errno.ENOENT:
953 if inst.errno != errno.ENOENT:
953 raise
954 raise
954
955
955 qfinished = []
956 qfinished = []
956 if numrevs:
957 if numrevs:
957 qfinished = self.applied[:numrevs]
958 qfinished = self.applied[:numrevs]
958 del self.applied[:numrevs]
959 del self.applied[:numrevs]
959 self.applieddirty = True
960 self.applieddirty = True
960
961
961 unknown = []
962 unknown = []
962
963
963 for (i, p) in sorted([(self.findseries(p), p) for p in patches],
964 for (i, p) in sorted([(self.findseries(p), p) for p in patches],
964 reverse=True):
965 reverse=True):
965 if i is not None:
966 if i is not None:
966 del self.fullseries[i]
967 del self.fullseries[i]
967 else:
968 else:
968 unknown.append(p)
969 unknown.append(p)
969
970
970 if unknown:
971 if unknown:
971 if numrevs:
972 if numrevs:
972 rev = dict((entry.name, entry.node) for entry in qfinished)
973 rev = dict((entry.name, entry.node) for entry in qfinished)
973 for p in unknown:
974 for p in unknown:
974 msg = _('revision %s refers to unknown patches: %s\n')
975 msg = _('revision %s refers to unknown patches: %s\n')
975 self.ui.warn(msg % (short(rev[p]), p))
976 self.ui.warn(msg % (short(rev[p]), p))
976 else:
977 else:
977 msg = _('unknown patches: %s\n')
978 msg = _('unknown patches: %s\n')
978 raise util.Abort(''.join(msg % p for p in unknown))
979 raise util.Abort(''.join(msg % p for p in unknown))
979
980
980 self.parseseries()
981 self.parseseries()
981 self.seriesdirty = True
982 self.seriesdirty = True
982 return [entry.node for entry in qfinished]
983 return [entry.node for entry in qfinished]
983
984
984 def _revpatches(self, repo, revs):
985 def _revpatches(self, repo, revs):
985 firstrev = repo[self.applied[0].node].rev()
986 firstrev = repo[self.applied[0].node].rev()
986 patches = []
987 patches = []
987 for i, rev in enumerate(revs):
988 for i, rev in enumerate(revs):
988
989
989 if rev < firstrev:
990 if rev < firstrev:
990 raise util.Abort(_('revision %d is not managed') % rev)
991 raise util.Abort(_('revision %d is not managed') % rev)
991
992
992 ctx = repo[rev]
993 ctx = repo[rev]
993 base = self.applied[i].node
994 base = self.applied[i].node
994 if ctx.node() != base:
995 if ctx.node() != base:
995 msg = _('cannot delete revision %d above applied patches')
996 msg = _('cannot delete revision %d above applied patches')
996 raise util.Abort(msg % rev)
997 raise util.Abort(msg % rev)
997
998
998 patch = self.applied[i].name
999 patch = self.applied[i].name
999 for fmt in ('[mq]: %s', 'imported patch %s'):
1000 for fmt in ('[mq]: %s', 'imported patch %s'):
1000 if ctx.description() == fmt % patch:
1001 if ctx.description() == fmt % patch:
1001 msg = _('patch %s finalized without changeset message\n')
1002 msg = _('patch %s finalized without changeset message\n')
1002 repo.ui.status(msg % patch)
1003 repo.ui.status(msg % patch)
1003 break
1004 break
1004
1005
1005 patches.append(patch)
1006 patches.append(patch)
1006 return patches
1007 return patches
1007
1008
1008 def finish(self, repo, revs):
1009 def finish(self, repo, revs):
1009 # Manually trigger phase computation to ensure phasedefaults is
1010 # Manually trigger phase computation to ensure phasedefaults is
1010 # executed before we remove the patches.
1011 # executed before we remove the patches.
1011 repo._phasecache
1012 repo._phasecache
1012 patches = self._revpatches(repo, sorted(revs))
1013 patches = self._revpatches(repo, sorted(revs))
1013 qfinished = self._cleanup(patches, len(patches))
1014 qfinished = self._cleanup(patches, len(patches))
1014 if qfinished and repo.ui.configbool('mq', 'secret', False):
1015 if qfinished and repo.ui.configbool('mq', 'secret', False):
1015 # only use this logic when the secret option is added
1016 # only use this logic when the secret option is added
1016 oldqbase = repo[qfinished[0]]
1017 oldqbase = repo[qfinished[0]]
1017 tphase = repo.ui.config('phases', 'new-commit', phases.draft)
1018 tphase = repo.ui.config('phases', 'new-commit', phases.draft)
1018 if oldqbase.phase() > tphase and oldqbase.p1().phase() <= tphase:
1019 if oldqbase.phase() > tphase and oldqbase.p1().phase() <= tphase:
1019 tr = repo.transaction('qfinish')
1020 tr = repo.transaction('qfinish')
1020 try:
1021 try:
1021 phases.advanceboundary(repo, tr, tphase, qfinished)
1022 phases.advanceboundary(repo, tr, tphase, qfinished)
1022 tr.close()
1023 tr.close()
1023 finally:
1024 finally:
1024 tr.release()
1025 tr.release()
1025
1026
1026 def delete(self, repo, patches, opts):
1027 def delete(self, repo, patches, opts):
1027 if not patches and not opts.get('rev'):
1028 if not patches and not opts.get('rev'):
1028 raise util.Abort(_('qdelete requires at least one revision or '
1029 raise util.Abort(_('qdelete requires at least one revision or '
1029 'patch name'))
1030 'patch name'))
1030
1031
1031 realpatches = []
1032 realpatches = []
1032 for patch in patches:
1033 for patch in patches:
1033 patch = self.lookup(patch, strict=True)
1034 patch = self.lookup(patch, strict=True)
1034 info = self.isapplied(patch)
1035 info = self.isapplied(patch)
1035 if info:
1036 if info:
1036 raise util.Abort(_("cannot delete applied patch %s") % patch)
1037 raise util.Abort(_("cannot delete applied patch %s") % patch)
1037 if patch not in self.series:
1038 if patch not in self.series:
1038 raise util.Abort(_("patch %s not in series file") % patch)
1039 raise util.Abort(_("patch %s not in series file") % patch)
1039 if patch not in realpatches:
1040 if patch not in realpatches:
1040 realpatches.append(patch)
1041 realpatches.append(patch)
1041
1042
1042 numrevs = 0
1043 numrevs = 0
1043 if opts.get('rev'):
1044 if opts.get('rev'):
1044 if not self.applied:
1045 if not self.applied:
1045 raise util.Abort(_('no patches applied'))
1046 raise util.Abort(_('no patches applied'))
1046 revs = scmutil.revrange(repo, opts.get('rev'))
1047 revs = scmutil.revrange(repo, opts.get('rev'))
1047 revs.sort()
1048 revs.sort()
1048 revpatches = self._revpatches(repo, revs)
1049 revpatches = self._revpatches(repo, revs)
1049 realpatches += revpatches
1050 realpatches += revpatches
1050 numrevs = len(revpatches)
1051 numrevs = len(revpatches)
1051
1052
1052 self._cleanup(realpatches, numrevs, opts.get('keep'))
1053 self._cleanup(realpatches, numrevs, opts.get('keep'))
1053
1054
1054 def checktoppatch(self, repo):
1055 def checktoppatch(self, repo):
1055 '''check that working directory is at qtip'''
1056 '''check that working directory is at qtip'''
1056 if self.applied:
1057 if self.applied:
1057 top = self.applied[-1].node
1058 top = self.applied[-1].node
1058 patch = self.applied[-1].name
1059 patch = self.applied[-1].name
1059 if repo.dirstate.p1() != top:
1060 if repo.dirstate.p1() != top:
1060 raise util.Abort(_("working directory revision is not qtip"))
1061 raise util.Abort(_("working directory revision is not qtip"))
1061 return top, patch
1062 return top, patch
1062 return None, None
1063 return None, None
1063
1064
1064 def putsubstate2changes(self, substatestate, changes):
1065 def putsubstate2changes(self, substatestate, changes):
1065 for files in changes[:3]:
1066 for files in changes[:3]:
1066 if '.hgsubstate' in files:
1067 if '.hgsubstate' in files:
1067 return # already listed up
1068 return # already listed up
1068 # not yet listed up
1069 # not yet listed up
1069 if substatestate in 'a?':
1070 if substatestate in 'a?':
1070 changes[1].append('.hgsubstate')
1071 changes[1].append('.hgsubstate')
1071 elif substatestate in 'r':
1072 elif substatestate in 'r':
1072 changes[2].append('.hgsubstate')
1073 changes[2].append('.hgsubstate')
1073 else: # modified
1074 else: # modified
1074 changes[0].append('.hgsubstate')
1075 changes[0].append('.hgsubstate')
1075
1076
1076 def checklocalchanges(self, repo, force=False, refresh=True):
1077 def checklocalchanges(self, repo, force=False, refresh=True):
1077 excsuffix = ''
1078 excsuffix = ''
1078 if refresh:
1079 if refresh:
1079 excsuffix = ', refresh first'
1080 excsuffix = ', refresh first'
1080 # plain versions for i18n tool to detect them
1081 # plain versions for i18n tool to detect them
1081 _("local changes found, refresh first")
1082 _("local changes found, refresh first")
1082 _("local changed subrepos found, refresh first")
1083 _("local changed subrepos found, refresh first")
1083 return checklocalchanges(repo, force, excsuffix)
1084 return checklocalchanges(repo, force, excsuffix)
1084
1085
1085 _reserved = ('series', 'status', 'guards', '.', '..')
1086 _reserved = ('series', 'status', 'guards', '.', '..')
1086 def checkreservedname(self, name):
1087 def checkreservedname(self, name):
1087 if name in self._reserved:
1088 if name in self._reserved:
1088 raise util.Abort(_('"%s" cannot be used as the name of a patch')
1089 raise util.Abort(_('"%s" cannot be used as the name of a patch')
1089 % name)
1090 % name)
1090 for prefix in ('.hg', '.mq'):
1091 for prefix in ('.hg', '.mq'):
1091 if name.startswith(prefix):
1092 if name.startswith(prefix):
1092 raise util.Abort(_('patch name cannot begin with "%s"')
1093 raise util.Abort(_('patch name cannot begin with "%s"')
1093 % prefix)
1094 % prefix)
1094 for c in ('#', ':'):
1095 for c in ('#', ':'):
1095 if c in name:
1096 if c in name:
1096 raise util.Abort(_('"%s" cannot be used in the name of a patch')
1097 raise util.Abort(_('"%s" cannot be used in the name of a patch')
1097 % c)
1098 % c)
1098
1099
1099 def checkpatchname(self, name, force=False):
1100 def checkpatchname(self, name, force=False):
1100 self.checkreservedname(name)
1101 self.checkreservedname(name)
1101 if not force and os.path.exists(self.join(name)):
1102 if not force and os.path.exists(self.join(name)):
1102 if os.path.isdir(self.join(name)):
1103 if os.path.isdir(self.join(name)):
1103 raise util.Abort(_('"%s" already exists as a directory')
1104 raise util.Abort(_('"%s" already exists as a directory')
1104 % name)
1105 % name)
1105 else:
1106 else:
1106 raise util.Abort(_('patch "%s" already exists') % name)
1107 raise util.Abort(_('patch "%s" already exists') % name)
1107
1108
1108 def checkkeepchanges(self, keepchanges, force):
1109 def checkkeepchanges(self, keepchanges, force):
1109 if force and keepchanges:
1110 if force and keepchanges:
1110 raise util.Abort(_('cannot use both --force and --keep-changes'))
1111 raise util.Abort(_('cannot use both --force and --keep-changes'))
1111
1112
1112 def new(self, repo, patchfn, *pats, **opts):
1113 def new(self, repo, patchfn, *pats, **opts):
1113 """options:
1114 """options:
1114 msg: a string or a no-argument function returning a string
1115 msg: a string or a no-argument function returning a string
1115 """
1116 """
1116 msg = opts.get('msg')
1117 msg = opts.get('msg')
1117 edit = opts.get('edit')
1118 edit = opts.get('edit')
1118 editform = opts.get('editform', 'mq.qnew')
1119 editform = opts.get('editform', 'mq.qnew')
1119 user = opts.get('user')
1120 user = opts.get('user')
1120 date = opts.get('date')
1121 date = opts.get('date')
1121 if date:
1122 if date:
1122 date = util.parsedate(date)
1123 date = util.parsedate(date)
1123 diffopts = self.diffopts({'git': opts.get('git')})
1124 diffopts = self.diffopts({'git': opts.get('git')})
1124 if opts.get('checkname', True):
1125 if opts.get('checkname', True):
1125 self.checkpatchname(patchfn)
1126 self.checkpatchname(patchfn)
1126 inclsubs = checksubstate(repo)
1127 inclsubs = checksubstate(repo)
1127 if inclsubs:
1128 if inclsubs:
1128 substatestate = repo.dirstate['.hgsubstate']
1129 substatestate = repo.dirstate['.hgsubstate']
1129 if opts.get('include') or opts.get('exclude') or pats:
1130 if opts.get('include') or opts.get('exclude') or pats:
1130 match = scmutil.match(repo[None], pats, opts)
1131 match = scmutil.match(repo[None], pats, opts)
1131 # detect missing files in pats
1132 # detect missing files in pats
1132 def badfn(f, msg):
1133 def badfn(f, msg):
1133 if f != '.hgsubstate': # .hgsubstate is auto-created
1134 if f != '.hgsubstate': # .hgsubstate is auto-created
1134 raise util.Abort('%s: %s' % (f, msg))
1135 raise util.Abort('%s: %s' % (f, msg))
1135 match.bad = badfn
1136 match.bad = badfn
1136 changes = repo.status(match=match)
1137 changes = repo.status(match=match)
1137 else:
1138 else:
1138 changes = self.checklocalchanges(repo, force=True)
1139 changes = self.checklocalchanges(repo, force=True)
1139 commitfiles = list(inclsubs)
1140 commitfiles = list(inclsubs)
1140 for files in changes[:3]:
1141 for files in changes[:3]:
1141 commitfiles.extend(files)
1142 commitfiles.extend(files)
1142 match = scmutil.matchfiles(repo, commitfiles)
1143 match = scmutil.matchfiles(repo, commitfiles)
1143 if len(repo[None].parents()) > 1:
1144 if len(repo[None].parents()) > 1:
1144 raise util.Abort(_('cannot manage merge changesets'))
1145 raise util.Abort(_('cannot manage merge changesets'))
1145 self.checktoppatch(repo)
1146 self.checktoppatch(repo)
1146 insert = self.fullseriesend()
1147 insert = self.fullseriesend()
1147 wlock = repo.wlock()
1148 wlock = repo.wlock()
1148 try:
1149 try:
1149 try:
1150 try:
1150 # if patch file write fails, abort early
1151 # if patch file write fails, abort early
1151 p = self.opener(patchfn, "w")
1152 p = self.opener(patchfn, "w")
1152 except IOError, e:
1153 except IOError, e:
1153 raise util.Abort(_('cannot write patch "%s": %s')
1154 raise util.Abort(_('cannot write patch "%s": %s')
1154 % (patchfn, e.strerror))
1155 % (patchfn, e.strerror))
1155 try:
1156 try:
1156 defaultmsg = "[mq]: %s" % patchfn
1157 defaultmsg = "[mq]: %s" % patchfn
1157 editor = cmdutil.getcommiteditor(editform=editform)
1158 editor = cmdutil.getcommiteditor(editform=editform)
1158 if edit:
1159 if edit:
1159 def finishdesc(desc):
1160 def finishdesc(desc):
1160 if desc.rstrip():
1161 if desc.rstrip():
1161 return desc
1162 return desc
1162 else:
1163 else:
1163 return defaultmsg
1164 return defaultmsg
1164 # i18n: this message is shown in editor with "HG: " prefix
1165 # i18n: this message is shown in editor with "HG: " prefix
1165 extramsg = _('Leave message empty to use default message.')
1166 extramsg = _('Leave message empty to use default message.')
1166 editor = cmdutil.getcommiteditor(finishdesc=finishdesc,
1167 editor = cmdutil.getcommiteditor(finishdesc=finishdesc,
1167 extramsg=extramsg,
1168 extramsg=extramsg,
1168 editform=editform)
1169 editform=editform)
1169 commitmsg = msg
1170 commitmsg = msg
1170 else:
1171 else:
1171 commitmsg = msg or defaultmsg
1172 commitmsg = msg or defaultmsg
1172
1173
1173 n = newcommit(repo, None, commitmsg, user, date, match=match,
1174 n = newcommit(repo, None, commitmsg, user, date, match=match,
1174 force=True, editor=editor)
1175 force=True, editor=editor)
1175 if n is None:
1176 if n is None:
1176 raise util.Abort(_("repo commit failed"))
1177 raise util.Abort(_("repo commit failed"))
1177 try:
1178 try:
1178 self.fullseries[insert:insert] = [patchfn]
1179 self.fullseries[insert:insert] = [patchfn]
1179 self.applied.append(statusentry(n, patchfn))
1180 self.applied.append(statusentry(n, patchfn))
1180 self.parseseries()
1181 self.parseseries()
1181 self.seriesdirty = True
1182 self.seriesdirty = True
1182 self.applieddirty = True
1183 self.applieddirty = True
1183 nctx = repo[n]
1184 nctx = repo[n]
1184 ph = patchheader(self.join(patchfn), self.plainmode)
1185 ph = patchheader(self.join(patchfn), self.plainmode)
1185 if user:
1186 if user:
1186 ph.setuser(user)
1187 ph.setuser(user)
1187 if date:
1188 if date:
1188 ph.setdate('%s %s' % date)
1189 ph.setdate('%s %s' % date)
1189 ph.setparent(hex(nctx.p1().node()))
1190 ph.setparent(hex(nctx.p1().node()))
1190 msg = nctx.description().strip()
1191 msg = nctx.description().strip()
1191 if msg == defaultmsg.strip():
1192 if msg == defaultmsg.strip():
1192 msg = ''
1193 msg = ''
1193 ph.setmessage(msg)
1194 ph.setmessage(msg)
1194 p.write(str(ph))
1195 p.write(str(ph))
1195 if commitfiles:
1196 if commitfiles:
1196 parent = self.qparents(repo, n)
1197 parent = self.qparents(repo, n)
1197 if inclsubs:
1198 if inclsubs:
1198 self.putsubstate2changes(substatestate, changes)
1199 self.putsubstate2changes(substatestate, changes)
1199 chunks = patchmod.diff(repo, node1=parent, node2=n,
1200 chunks = patchmod.diff(repo, node1=parent, node2=n,
1200 changes=changes, opts=diffopts)
1201 changes=changes, opts=diffopts)
1201 for chunk in chunks:
1202 for chunk in chunks:
1202 p.write(chunk)
1203 p.write(chunk)
1203 p.close()
1204 p.close()
1204 r = self.qrepo()
1205 r = self.qrepo()
1205 if r:
1206 if r:
1206 r[None].add([patchfn])
1207 r[None].add([patchfn])
1207 except: # re-raises
1208 except: # re-raises
1208 repo.rollback()
1209 repo.rollback()
1209 raise
1210 raise
1210 except Exception:
1211 except Exception:
1211 patchpath = self.join(patchfn)
1212 patchpath = self.join(patchfn)
1212 try:
1213 try:
1213 os.unlink(patchpath)
1214 os.unlink(patchpath)
1214 except OSError:
1215 except OSError:
1215 self.ui.warn(_('error unlinking %s\n') % patchpath)
1216 self.ui.warn(_('error unlinking %s\n') % patchpath)
1216 raise
1217 raise
1217 self.removeundo(repo)
1218 self.removeundo(repo)
1218 finally:
1219 finally:
1219 release(wlock)
1220 release(wlock)
1220
1221
1221 def isapplied(self, patch):
1222 def isapplied(self, patch):
1222 """returns (index, rev, patch)"""
1223 """returns (index, rev, patch)"""
1223 for i, a in enumerate(self.applied):
1224 for i, a in enumerate(self.applied):
1224 if a.name == patch:
1225 if a.name == patch:
1225 return (i, a.node, a.name)
1226 return (i, a.node, a.name)
1226 return None
1227 return None
1227
1228
1228 # if the exact patch name does not exist, we try a few
1229 # if the exact patch name does not exist, we try a few
1229 # variations. If strict is passed, we try only #1
1230 # variations. If strict is passed, we try only #1
1230 #
1231 #
1231 # 1) a number (as string) to indicate an offset in the series file
1232 # 1) a number (as string) to indicate an offset in the series file
1232 # 2) a unique substring of the patch name was given
1233 # 2) a unique substring of the patch name was given
1233 # 3) patchname[-+]num to indicate an offset in the series file
1234 # 3) patchname[-+]num to indicate an offset in the series file
1234 def lookup(self, patch, strict=False):
1235 def lookup(self, patch, strict=False):
1235 def partialname(s):
1236 def partialname(s):
1236 if s in self.series:
1237 if s in self.series:
1237 return s
1238 return s
1238 matches = [x for x in self.series if s in x]
1239 matches = [x for x in self.series if s in x]
1239 if len(matches) > 1:
1240 if len(matches) > 1:
1240 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
1241 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
1241 for m in matches:
1242 for m in matches:
1242 self.ui.warn(' %s\n' % m)
1243 self.ui.warn(' %s\n' % m)
1243 return None
1244 return None
1244 if matches:
1245 if matches:
1245 return matches[0]
1246 return matches[0]
1246 if self.series and self.applied:
1247 if self.series and self.applied:
1247 if s == 'qtip':
1248 if s == 'qtip':
1248 return self.series[self.seriesend(True) - 1]
1249 return self.series[self.seriesend(True) - 1]
1249 if s == 'qbase':
1250 if s == 'qbase':
1250 return self.series[0]
1251 return self.series[0]
1251 return None
1252 return None
1252
1253
1253 if patch in self.series:
1254 if patch in self.series:
1254 return patch
1255 return patch
1255
1256
1256 if not os.path.isfile(self.join(patch)):
1257 if not os.path.isfile(self.join(patch)):
1257 try:
1258 try:
1258 sno = int(patch)
1259 sno = int(patch)
1259 except (ValueError, OverflowError):
1260 except (ValueError, OverflowError):
1260 pass
1261 pass
1261 else:
1262 else:
1262 if -len(self.series) <= sno < len(self.series):
1263 if -len(self.series) <= sno < len(self.series):
1263 return self.series[sno]
1264 return self.series[sno]
1264
1265
1265 if not strict:
1266 if not strict:
1266 res = partialname(patch)
1267 res = partialname(patch)
1267 if res:
1268 if res:
1268 return res
1269 return res
1269 minus = patch.rfind('-')
1270 minus = patch.rfind('-')
1270 if minus >= 0:
1271 if minus >= 0:
1271 res = partialname(patch[:minus])
1272 res = partialname(patch[:minus])
1272 if res:
1273 if res:
1273 i = self.series.index(res)
1274 i = self.series.index(res)
1274 try:
1275 try:
1275 off = int(patch[minus + 1:] or 1)
1276 off = int(patch[minus + 1:] or 1)
1276 except (ValueError, OverflowError):
1277 except (ValueError, OverflowError):
1277 pass
1278 pass
1278 else:
1279 else:
1279 if i - off >= 0:
1280 if i - off >= 0:
1280 return self.series[i - off]
1281 return self.series[i - off]
1281 plus = patch.rfind('+')
1282 plus = patch.rfind('+')
1282 if plus >= 0:
1283 if plus >= 0:
1283 res = partialname(patch[:plus])
1284 res = partialname(patch[:plus])
1284 if res:
1285 if res:
1285 i = self.series.index(res)
1286 i = self.series.index(res)
1286 try:
1287 try:
1287 off = int(patch[plus + 1:] or 1)
1288 off = int(patch[plus + 1:] or 1)
1288 except (ValueError, OverflowError):
1289 except (ValueError, OverflowError):
1289 pass
1290 pass
1290 else:
1291 else:
1291 if i + off < len(self.series):
1292 if i + off < len(self.series):
1292 return self.series[i + off]
1293 return self.series[i + off]
1293 raise util.Abort(_("patch %s not in series") % patch)
1294 raise util.Abort(_("patch %s not in series") % patch)
1294
1295
1295 def push(self, repo, patch=None, force=False, list=False, mergeq=None,
1296 def push(self, repo, patch=None, force=False, list=False, mergeq=None,
1296 all=False, move=False, exact=False, nobackup=False,
1297 all=False, move=False, exact=False, nobackup=False,
1297 keepchanges=False):
1298 keepchanges=False):
1298 self.checkkeepchanges(keepchanges, force)
1299 self.checkkeepchanges(keepchanges, force)
1299 diffopts = self.diffopts()
1300 diffopts = self.diffopts()
1300 wlock = repo.wlock()
1301 wlock = repo.wlock()
1301 try:
1302 try:
1302 heads = []
1303 heads = []
1303 for hs in repo.branchmap().itervalues():
1304 for hs in repo.branchmap().itervalues():
1304 heads.extend(hs)
1305 heads.extend(hs)
1305 if not heads:
1306 if not heads:
1306 heads = [nullid]
1307 heads = [nullid]
1307 if repo.dirstate.p1() not in heads and not exact:
1308 if repo.dirstate.p1() not in heads and not exact:
1308 self.ui.status(_("(working directory not at a head)\n"))
1309 self.ui.status(_("(working directory not at a head)\n"))
1309
1310
1310 if not self.series:
1311 if not self.series:
1311 self.ui.warn(_('no patches in series\n'))
1312 self.ui.warn(_('no patches in series\n'))
1312 return 0
1313 return 0
1313
1314
1314 # Suppose our series file is: A B C and the current 'top'
1315 # Suppose our series file is: A B C and the current 'top'
1315 # patch is B. qpush C should be performed (moving forward)
1316 # patch is B. qpush C should be performed (moving forward)
1316 # qpush B is a NOP (no change) qpush A is an error (can't
1317 # qpush B is a NOP (no change) qpush A is an error (can't
1317 # go backwards with qpush)
1318 # go backwards with qpush)
1318 if patch:
1319 if patch:
1319 patch = self.lookup(patch)
1320 patch = self.lookup(patch)
1320 info = self.isapplied(patch)
1321 info = self.isapplied(patch)
1321 if info and info[0] >= len(self.applied) - 1:
1322 if info and info[0] >= len(self.applied) - 1:
1322 self.ui.warn(
1323 self.ui.warn(
1323 _('qpush: %s is already at the top\n') % patch)
1324 _('qpush: %s is already at the top\n') % patch)
1324 return 0
1325 return 0
1325
1326
1326 pushable, reason = self.pushable(patch)
1327 pushable, reason = self.pushable(patch)
1327 if pushable:
1328 if pushable:
1328 if self.series.index(patch) < self.seriesend():
1329 if self.series.index(patch) < self.seriesend():
1329 raise util.Abort(
1330 raise util.Abort(
1330 _("cannot push to a previous patch: %s") % patch)
1331 _("cannot push to a previous patch: %s") % patch)
1331 else:
1332 else:
1332 if reason:
1333 if reason:
1333 reason = _('guarded by %s') % reason
1334 reason = _('guarded by %s') % reason
1334 else:
1335 else:
1335 reason = _('no matching guards')
1336 reason = _('no matching guards')
1336 self.ui.warn(_("cannot push '%s' - %s\n") % (patch, reason))
1337 self.ui.warn(_("cannot push '%s' - %s\n") % (patch, reason))
1337 return 1
1338 return 1
1338 elif all:
1339 elif all:
1339 patch = self.series[-1]
1340 patch = self.series[-1]
1340 if self.isapplied(patch):
1341 if self.isapplied(patch):
1341 self.ui.warn(_('all patches are currently applied\n'))
1342 self.ui.warn(_('all patches are currently applied\n'))
1342 return 0
1343 return 0
1343
1344
1344 # Following the above example, starting at 'top' of B:
1345 # Following the above example, starting at 'top' of B:
1345 # qpush should be performed (pushes C), but a subsequent
1346 # qpush should be performed (pushes C), but a subsequent
1346 # qpush without an argument is an error (nothing to
1347 # qpush without an argument is an error (nothing to
1347 # apply). This allows a loop of "...while hg qpush..." to
1348 # apply). This allows a loop of "...while hg qpush..." to
1348 # work as it detects an error when done
1349 # work as it detects an error when done
1349 start = self.seriesend()
1350 start = self.seriesend()
1350 if start == len(self.series):
1351 if start == len(self.series):
1351 self.ui.warn(_('patch series already fully applied\n'))
1352 self.ui.warn(_('patch series already fully applied\n'))
1352 return 1
1353 return 1
1353 if not force and not keepchanges:
1354 if not force and not keepchanges:
1354 self.checklocalchanges(repo, refresh=self.applied)
1355 self.checklocalchanges(repo, refresh=self.applied)
1355
1356
1356 if exact:
1357 if exact:
1357 if keepchanges:
1358 if keepchanges:
1358 raise util.Abort(
1359 raise util.Abort(
1359 _("cannot use --exact and --keep-changes together"))
1360 _("cannot use --exact and --keep-changes together"))
1360 if move:
1361 if move:
1361 raise util.Abort(_('cannot use --exact and --move '
1362 raise util.Abort(_('cannot use --exact and --move '
1362 'together'))
1363 'together'))
1363 if self.applied:
1364 if self.applied:
1364 raise util.Abort(_('cannot push --exact with applied '
1365 raise util.Abort(_('cannot push --exact with applied '
1365 'patches'))
1366 'patches'))
1366 root = self.series[start]
1367 root = self.series[start]
1367 target = patchheader(self.join(root), self.plainmode).parent
1368 target = patchheader(self.join(root), self.plainmode).parent
1368 if not target:
1369 if not target:
1369 raise util.Abort(
1370 raise util.Abort(
1370 _("%s does not have a parent recorded") % root)
1371 _("%s does not have a parent recorded") % root)
1371 if not repo[target] == repo['.']:
1372 if not repo[target] == repo['.']:
1372 hg.update(repo, target)
1373 hg.update(repo, target)
1373
1374
1374 if move:
1375 if move:
1375 if not patch:
1376 if not patch:
1376 raise util.Abort(_("please specify the patch to move"))
1377 raise util.Abort(_("please specify the patch to move"))
1377 for fullstart, rpn in enumerate(self.fullseries):
1378 for fullstart, rpn in enumerate(self.fullseries):
1378 # strip markers for patch guards
1379 # strip markers for patch guards
1379 if self.guard_re.split(rpn, 1)[0] == self.series[start]:
1380 if self.guard_re.split(rpn, 1)[0] == self.series[start]:
1380 break
1381 break
1381 for i, rpn in enumerate(self.fullseries[fullstart:]):
1382 for i, rpn in enumerate(self.fullseries[fullstart:]):
1382 # strip markers for patch guards
1383 # strip markers for patch guards
1383 if self.guard_re.split(rpn, 1)[0] == patch:
1384 if self.guard_re.split(rpn, 1)[0] == patch:
1384 break
1385 break
1385 index = fullstart + i
1386 index = fullstart + i
1386 assert index < len(self.fullseries)
1387 assert index < len(self.fullseries)
1387 fullpatch = self.fullseries[index]
1388 fullpatch = self.fullseries[index]
1388 del self.fullseries[index]
1389 del self.fullseries[index]
1389 self.fullseries.insert(fullstart, fullpatch)
1390 self.fullseries.insert(fullstart, fullpatch)
1390 self.parseseries()
1391 self.parseseries()
1391 self.seriesdirty = True
1392 self.seriesdirty = True
1392
1393
1393 self.applieddirty = True
1394 self.applieddirty = True
1394 if start > 0:
1395 if start > 0:
1395 self.checktoppatch(repo)
1396 self.checktoppatch(repo)
1396 if not patch:
1397 if not patch:
1397 patch = self.series[start]
1398 patch = self.series[start]
1398 end = start + 1
1399 end = start + 1
1399 else:
1400 else:
1400 end = self.series.index(patch, start) + 1
1401 end = self.series.index(patch, start) + 1
1401
1402
1402 tobackup = set()
1403 tobackup = set()
1403 if (not nobackup and force) or keepchanges:
1404 if (not nobackup and force) or keepchanges:
1404 status = self.checklocalchanges(repo, force=True)
1405 status = self.checklocalchanges(repo, force=True)
1405 if keepchanges:
1406 if keepchanges:
1406 tobackup.update(status.modified + status.added +
1407 tobackup.update(status.modified + status.added +
1407 status.removed + status.deleted)
1408 status.removed + status.deleted)
1408 else:
1409 else:
1409 tobackup.update(status.modified + status.added)
1410 tobackup.update(status.modified + status.added)
1410
1411
1411 s = self.series[start:end]
1412 s = self.series[start:end]
1412 all_files = set()
1413 all_files = set()
1413 try:
1414 try:
1414 if mergeq:
1415 if mergeq:
1415 ret = self.mergepatch(repo, mergeq, s, diffopts)
1416 ret = self.mergepatch(repo, mergeq, s, diffopts)
1416 else:
1417 else:
1417 ret = self.apply(repo, s, list, all_files=all_files,
1418 ret = self.apply(repo, s, list, all_files=all_files,
1418 tobackup=tobackup, keepchanges=keepchanges)
1419 tobackup=tobackup, keepchanges=keepchanges)
1419 except: # re-raises
1420 except: # re-raises
1420 self.ui.warn(_('cleaning up working directory...'))
1421 self.ui.warn(_('cleaning up working directory...'))
1421 node = repo.dirstate.p1()
1422 node = repo.dirstate.p1()
1422 hg.revert(repo, node, None)
1423 hg.revert(repo, node, None)
1423 # only remove unknown files that we know we touched or
1424 # only remove unknown files that we know we touched or
1424 # created while patching
1425 # created while patching
1425 for f in all_files:
1426 for f in all_files:
1426 if f not in repo.dirstate:
1427 if f not in repo.dirstate:
1427 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
1428 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
1428 self.ui.warn(_('done\n'))
1429 self.ui.warn(_('done\n'))
1429 raise
1430 raise
1430
1431
1431 if not self.applied:
1432 if not self.applied:
1432 return ret[0]
1433 return ret[0]
1433 top = self.applied[-1].name
1434 top = self.applied[-1].name
1434 if ret[0] and ret[0] > 1:
1435 if ret[0] and ret[0] > 1:
1435 msg = _("errors during apply, please fix and refresh %s\n")
1436 msg = _("errors during apply, please fix and refresh %s\n")
1436 self.ui.write(msg % top)
1437 self.ui.write(msg % top)
1437 else:
1438 else:
1438 self.ui.write(_("now at: %s\n") % top)
1439 self.ui.write(_("now at: %s\n") % top)
1439 return ret[0]
1440 return ret[0]
1440
1441
1441 finally:
1442 finally:
1442 wlock.release()
1443 wlock.release()
1443
1444
1444 def pop(self, repo, patch=None, force=False, update=True, all=False,
1445 def pop(self, repo, patch=None, force=False, update=True, all=False,
1445 nobackup=False, keepchanges=False):
1446 nobackup=False, keepchanges=False):
1446 self.checkkeepchanges(keepchanges, force)
1447 self.checkkeepchanges(keepchanges, force)
1447 wlock = repo.wlock()
1448 wlock = repo.wlock()
1448 try:
1449 try:
1449 if patch:
1450 if patch:
1450 # index, rev, patch
1451 # index, rev, patch
1451 info = self.isapplied(patch)
1452 info = self.isapplied(patch)
1452 if not info:
1453 if not info:
1453 patch = self.lookup(patch)
1454 patch = self.lookup(patch)
1454 info = self.isapplied(patch)
1455 info = self.isapplied(patch)
1455 if not info:
1456 if not info:
1456 raise util.Abort(_("patch %s is not applied") % patch)
1457 raise util.Abort(_("patch %s is not applied") % patch)
1457
1458
1458 if not self.applied:
1459 if not self.applied:
1459 # Allow qpop -a to work repeatedly,
1460 # Allow qpop -a to work repeatedly,
1460 # but not qpop without an argument
1461 # but not qpop without an argument
1461 self.ui.warn(_("no patches applied\n"))
1462 self.ui.warn(_("no patches applied\n"))
1462 return not all
1463 return not all
1463
1464
1464 if all:
1465 if all:
1465 start = 0
1466 start = 0
1466 elif patch:
1467 elif patch:
1467 start = info[0] + 1
1468 start = info[0] + 1
1468 else:
1469 else:
1469 start = len(self.applied) - 1
1470 start = len(self.applied) - 1
1470
1471
1471 if start >= len(self.applied):
1472 if start >= len(self.applied):
1472 self.ui.warn(_("qpop: %s is already at the top\n") % patch)
1473 self.ui.warn(_("qpop: %s is already at the top\n") % patch)
1473 return
1474 return
1474
1475
1475 if not update:
1476 if not update:
1476 parents = repo.dirstate.parents()
1477 parents = repo.dirstate.parents()
1477 rr = [x.node for x in self.applied]
1478 rr = [x.node for x in self.applied]
1478 for p in parents:
1479 for p in parents:
1479 if p in rr:
1480 if p in rr:
1480 self.ui.warn(_("qpop: forcing dirstate update\n"))
1481 self.ui.warn(_("qpop: forcing dirstate update\n"))
1481 update = True
1482 update = True
1482 else:
1483 else:
1483 parents = [p.node() for p in repo[None].parents()]
1484 parents = [p.node() for p in repo[None].parents()]
1484 needupdate = False
1485 needupdate = False
1485 for entry in self.applied[start:]:
1486 for entry in self.applied[start:]:
1486 if entry.node in parents:
1487 if entry.node in parents:
1487 needupdate = True
1488 needupdate = True
1488 break
1489 break
1489 update = needupdate
1490 update = needupdate
1490
1491
1491 tobackup = set()
1492 tobackup = set()
1492 if update:
1493 if update:
1493 s = self.checklocalchanges(repo, force=force or keepchanges)
1494 s = self.checklocalchanges(repo, force=force or keepchanges)
1494 if force:
1495 if force:
1495 if not nobackup:
1496 if not nobackup:
1496 tobackup.update(s.modified + s.added)
1497 tobackup.update(s.modified + s.added)
1497 elif keepchanges:
1498 elif keepchanges:
1498 tobackup.update(s.modified + s.added +
1499 tobackup.update(s.modified + s.added +
1499 s.removed + s.deleted)
1500 s.removed + s.deleted)
1500
1501
1501 self.applieddirty = True
1502 self.applieddirty = True
1502 end = len(self.applied)
1503 end = len(self.applied)
1503 rev = self.applied[start].node
1504 rev = self.applied[start].node
1504
1505
1505 try:
1506 try:
1506 heads = repo.changelog.heads(rev)
1507 heads = repo.changelog.heads(rev)
1507 except error.LookupError:
1508 except error.LookupError:
1508 node = short(rev)
1509 node = short(rev)
1509 raise util.Abort(_('trying to pop unknown node %s') % node)
1510 raise util.Abort(_('trying to pop unknown node %s') % node)
1510
1511
1511 if heads != [self.applied[-1].node]:
1512 if heads != [self.applied[-1].node]:
1512 raise util.Abort(_("popping would remove a revision not "
1513 raise util.Abort(_("popping would remove a revision not "
1513 "managed by this patch queue"))
1514 "managed by this patch queue"))
1514 if not repo[self.applied[-1].node].mutable():
1515 if not repo[self.applied[-1].node].mutable():
1515 raise util.Abort(
1516 raise util.Abort(
1516 _("popping would remove an immutable revision"),
1517 _("popping would remove an immutable revision"),
1517 hint=_('see "hg help phases" for details'))
1518 hint=_('see "hg help phases" for details'))
1518
1519
1519 # we know there are no local changes, so we can make a simplified
1520 # we know there are no local changes, so we can make a simplified
1520 # form of hg.update.
1521 # form of hg.update.
1521 if update:
1522 if update:
1522 qp = self.qparents(repo, rev)
1523 qp = self.qparents(repo, rev)
1523 ctx = repo[qp]
1524 ctx = repo[qp]
1524 m, a, r, d = repo.status(qp, '.')[:4]
1525 m, a, r, d = repo.status(qp, '.')[:4]
1525 if d:
1526 if d:
1526 raise util.Abort(_("deletions found between repo revs"))
1527 raise util.Abort(_("deletions found between repo revs"))
1527
1528
1528 tobackup = set(a + m + r) & tobackup
1529 tobackup = set(a + m + r) & tobackup
1529 if keepchanges and tobackup:
1530 if keepchanges and tobackup:
1530 raise util.Abort(_("local changes found, refresh first"))
1531 raise util.Abort(_("local changes found, refresh first"))
1531 self.backup(repo, tobackup)
1532 self.backup(repo, tobackup)
1532 repo.dirstate.beginparentchange()
1533 repo.dirstate.beginparentchange()
1533 for f in a:
1534 for f in a:
1534 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
1535 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
1535 repo.dirstate.drop(f)
1536 repo.dirstate.drop(f)
1536 for f in m + r:
1537 for f in m + r:
1537 fctx = ctx[f]
1538 fctx = ctx[f]
1538 repo.wwrite(f, fctx.data(), fctx.flags())
1539 repo.wwrite(f, fctx.data(), fctx.flags())
1539 repo.dirstate.normal(f)
1540 repo.dirstate.normal(f)
1540 repo.setparents(qp, nullid)
1541 repo.setparents(qp, nullid)
1541 repo.dirstate.endparentchange()
1542 repo.dirstate.endparentchange()
1542 for patch in reversed(self.applied[start:end]):
1543 for patch in reversed(self.applied[start:end]):
1543 self.ui.status(_("popping %s\n") % patch.name)
1544 self.ui.status(_("popping %s\n") % patch.name)
1544 del self.applied[start:end]
1545 del self.applied[start:end]
1545 strip(self.ui, repo, [rev], update=False, backup=False)
1546 strip(self.ui, repo, [rev], update=False, backup=False)
1546 for s, state in repo['.'].substate.items():
1547 for s, state in repo['.'].substate.items():
1547 repo['.'].sub(s).get(state)
1548 repo['.'].sub(s).get(state)
1548 if self.applied:
1549 if self.applied:
1549 self.ui.write(_("now at: %s\n") % self.applied[-1].name)
1550 self.ui.write(_("now at: %s\n") % self.applied[-1].name)
1550 else:
1551 else:
1551 self.ui.write(_("patch queue now empty\n"))
1552 self.ui.write(_("patch queue now empty\n"))
1552 finally:
1553 finally:
1553 wlock.release()
1554 wlock.release()
1554
1555
1555 def diff(self, repo, pats, opts):
1556 def diff(self, repo, pats, opts):
1556 top, patch = self.checktoppatch(repo)
1557 top, patch = self.checktoppatch(repo)
1557 if not top:
1558 if not top:
1558 self.ui.write(_("no patches applied\n"))
1559 self.ui.write(_("no patches applied\n"))
1559 return
1560 return
1560 qp = self.qparents(repo, top)
1561 qp = self.qparents(repo, top)
1561 if opts.get('reverse'):
1562 if opts.get('reverse'):
1562 node1, node2 = None, qp
1563 node1, node2 = None, qp
1563 else:
1564 else:
1564 node1, node2 = qp, None
1565 node1, node2 = qp, None
1565 diffopts = self.diffopts(opts, patch)
1566 diffopts = self.diffopts(opts, patch)
1566 self.printdiff(repo, diffopts, node1, node2, files=pats, opts=opts)
1567 self.printdiff(repo, diffopts, node1, node2, files=pats, opts=opts)
1567
1568
1568 def refresh(self, repo, pats=None, **opts):
1569 def refresh(self, repo, pats=None, **opts):
1569 if not self.applied:
1570 if not self.applied:
1570 self.ui.write(_("no patches applied\n"))
1571 self.ui.write(_("no patches applied\n"))
1571 return 1
1572 return 1
1572 msg = opts.get('msg', '').rstrip()
1573 msg = opts.get('msg', '').rstrip()
1573 edit = opts.get('edit')
1574 edit = opts.get('edit')
1574 editform = opts.get('editform', 'mq.qrefresh')
1575 editform = opts.get('editform', 'mq.qrefresh')
1575 newuser = opts.get('user')
1576 newuser = opts.get('user')
1576 newdate = opts.get('date')
1577 newdate = opts.get('date')
1577 if newdate:
1578 if newdate:
1578 newdate = '%d %d' % util.parsedate(newdate)
1579 newdate = '%d %d' % util.parsedate(newdate)
1579 wlock = repo.wlock()
1580 wlock = repo.wlock()
1580
1581
1581 try:
1582 try:
1582 self.checktoppatch(repo)
1583 self.checktoppatch(repo)
1583 (top, patchfn) = (self.applied[-1].node, self.applied[-1].name)
1584 (top, patchfn) = (self.applied[-1].node, self.applied[-1].name)
1584 if repo.changelog.heads(top) != [top]:
1585 if repo.changelog.heads(top) != [top]:
1585 raise util.Abort(_("cannot refresh a revision with children"))
1586 raise util.Abort(_("cannot refresh a revision with children"))
1586 if not repo[top].mutable():
1587 if not repo[top].mutable():
1587 raise util.Abort(_("cannot refresh immutable revision"),
1588 raise util.Abort(_("cannot refresh immutable revision"),
1588 hint=_('see "hg help phases" for details'))
1589 hint=_('see "hg help phases" for details'))
1589
1590
1590 cparents = repo.changelog.parents(top)
1591 cparents = repo.changelog.parents(top)
1591 patchparent = self.qparents(repo, top)
1592 patchparent = self.qparents(repo, top)
1592
1593
1593 inclsubs = checksubstate(repo, hex(patchparent))
1594 inclsubs = checksubstate(repo, hex(patchparent))
1594 if inclsubs:
1595 if inclsubs:
1595 substatestate = repo.dirstate['.hgsubstate']
1596 substatestate = repo.dirstate['.hgsubstate']
1596
1597
1597 ph = patchheader(self.join(patchfn), self.plainmode)
1598 ph = patchheader(self.join(patchfn), self.plainmode)
1598 diffopts = self.diffopts({'git': opts.get('git')}, patchfn)
1599 diffopts = self.diffopts({'git': opts.get('git')}, patchfn)
1599 if newuser:
1600 if newuser:
1600 ph.setuser(newuser)
1601 ph.setuser(newuser)
1601 if newdate:
1602 if newdate:
1602 ph.setdate(newdate)
1603 ph.setdate(newdate)
1603 ph.setparent(hex(patchparent))
1604 ph.setparent(hex(patchparent))
1604
1605
1605 # only commit new patch when write is complete
1606 # only commit new patch when write is complete
1606 patchf = self.opener(patchfn, 'w', atomictemp=True)
1607 patchf = self.opener(patchfn, 'w', atomictemp=True)
1607
1608
1608 # update the dirstate in place, strip off the qtip commit
1609 # update the dirstate in place, strip off the qtip commit
1609 # and then commit.
1610 # and then commit.
1610 #
1611 #
1611 # this should really read:
1612 # this should really read:
1612 # mm, dd, aa = repo.status(top, patchparent)[:3]
1613 # mm, dd, aa = repo.status(top, patchparent)[:3]
1613 # but we do it backwards to take advantage of manifest/changelog
1614 # but we do it backwards to take advantage of manifest/changelog
1614 # caching against the next repo.status call
1615 # caching against the next repo.status call
1615 mm, aa, dd = repo.status(patchparent, top)[:3]
1616 mm, aa, dd = repo.status(patchparent, top)[:3]
1616 changes = repo.changelog.read(top)
1617 changes = repo.changelog.read(top)
1617 man = repo.manifest.read(changes[0])
1618 man = repo.manifest.read(changes[0])
1618 aaa = aa[:]
1619 aaa = aa[:]
1619 matchfn = scmutil.match(repo[None], pats, opts)
1620 matchfn = scmutil.match(repo[None], pats, opts)
1620 # in short mode, we only diff the files included in the
1621 # in short mode, we only diff the files included in the
1621 # patch already plus specified files
1622 # patch already plus specified files
1622 if opts.get('short'):
1623 if opts.get('short'):
1623 # if amending a patch, we start with existing
1624 # if amending a patch, we start with existing
1624 # files plus specified files - unfiltered
1625 # files plus specified files - unfiltered
1625 match = scmutil.matchfiles(repo, mm + aa + dd + matchfn.files())
1626 match = scmutil.matchfiles(repo, mm + aa + dd + matchfn.files())
1626 # filter with include/exclude options
1627 # filter with include/exclude options
1627 matchfn = scmutil.match(repo[None], opts=opts)
1628 matchfn = scmutil.match(repo[None], opts=opts)
1628 else:
1629 else:
1629 match = scmutil.matchall(repo)
1630 match = scmutil.matchall(repo)
1630 m, a, r, d = repo.status(match=match)[:4]
1631 m, a, r, d = repo.status(match=match)[:4]
1631 mm = set(mm)
1632 mm = set(mm)
1632 aa = set(aa)
1633 aa = set(aa)
1633 dd = set(dd)
1634 dd = set(dd)
1634
1635
1635 # we might end up with files that were added between
1636 # we might end up with files that were added between
1636 # qtip and the dirstate parent, but then changed in the
1637 # qtip and the dirstate parent, but then changed in the
1637 # local dirstate. in this case, we want them to only
1638 # local dirstate. in this case, we want them to only
1638 # show up in the added section
1639 # show up in the added section
1639 for x in m:
1640 for x in m:
1640 if x not in aa:
1641 if x not in aa:
1641 mm.add(x)
1642 mm.add(x)
1642 # we might end up with files added by the local dirstate that
1643 # we might end up with files added by the local dirstate that
1643 # were deleted by the patch. In this case, they should only
1644 # were deleted by the patch. In this case, they should only
1644 # show up in the changed section.
1645 # show up in the changed section.
1645 for x in a:
1646 for x in a:
1646 if x in dd:
1647 if x in dd:
1647 dd.remove(x)
1648 dd.remove(x)
1648 mm.add(x)
1649 mm.add(x)
1649 else:
1650 else:
1650 aa.add(x)
1651 aa.add(x)
1651 # make sure any files deleted in the local dirstate
1652 # make sure any files deleted in the local dirstate
1652 # are not in the add or change column of the patch
1653 # are not in the add or change column of the patch
1653 forget = []
1654 forget = []
1654 for x in d + r:
1655 for x in d + r:
1655 if x in aa:
1656 if x in aa:
1656 aa.remove(x)
1657 aa.remove(x)
1657 forget.append(x)
1658 forget.append(x)
1658 continue
1659 continue
1659 else:
1660 else:
1660 mm.discard(x)
1661 mm.discard(x)
1661 dd.add(x)
1662 dd.add(x)
1662
1663
1663 m = list(mm)
1664 m = list(mm)
1664 r = list(dd)
1665 r = list(dd)
1665 a = list(aa)
1666 a = list(aa)
1666
1667
1667 # create 'match' that includes the files to be recommitted.
1668 # create 'match' that includes the files to be recommitted.
1668 # apply matchfn via repo.status to ensure correct case handling.
1669 # apply matchfn via repo.status to ensure correct case handling.
1669 cm, ca, cr, cd = repo.status(patchparent, match=matchfn)[:4]
1670 cm, ca, cr, cd = repo.status(patchparent, match=matchfn)[:4]
1670 allmatches = set(cm + ca + cr + cd)
1671 allmatches = set(cm + ca + cr + cd)
1671 refreshchanges = [x.intersection(allmatches) for x in (mm, aa, dd)]
1672 refreshchanges = [x.intersection(allmatches) for x in (mm, aa, dd)]
1672
1673
1673 files = set(inclsubs)
1674 files = set(inclsubs)
1674 for x in refreshchanges:
1675 for x in refreshchanges:
1675 files.update(x)
1676 files.update(x)
1676 match = scmutil.matchfiles(repo, files)
1677 match = scmutil.matchfiles(repo, files)
1677
1678
1678 bmlist = repo[top].bookmarks()
1679 bmlist = repo[top].bookmarks()
1679
1680
1680 try:
1681 try:
1681 repo.dirstate.beginparentchange()
1682 repo.dirstate.beginparentchange()
1682 if diffopts.git or diffopts.upgrade:
1683 if diffopts.git or diffopts.upgrade:
1683 copies = {}
1684 copies = {}
1684 for dst in a:
1685 for dst in a:
1685 src = repo.dirstate.copied(dst)
1686 src = repo.dirstate.copied(dst)
1686 # during qfold, the source file for copies may
1687 # during qfold, the source file for copies may
1687 # be removed. Treat this as a simple add.
1688 # be removed. Treat this as a simple add.
1688 if src is not None and src in repo.dirstate:
1689 if src is not None and src in repo.dirstate:
1689 copies.setdefault(src, []).append(dst)
1690 copies.setdefault(src, []).append(dst)
1690 repo.dirstate.add(dst)
1691 repo.dirstate.add(dst)
1691 # remember the copies between patchparent and qtip
1692 # remember the copies between patchparent and qtip
1692 for dst in aaa:
1693 for dst in aaa:
1693 f = repo.file(dst)
1694 f = repo.file(dst)
1694 src = f.renamed(man[dst])
1695 src = f.renamed(man[dst])
1695 if src:
1696 if src:
1696 copies.setdefault(src[0], []).extend(
1697 copies.setdefault(src[0], []).extend(
1697 copies.get(dst, []))
1698 copies.get(dst, []))
1698 if dst in a:
1699 if dst in a:
1699 copies[src[0]].append(dst)
1700 copies[src[0]].append(dst)
1700 # we can't copy a file created by the patch itself
1701 # we can't copy a file created by the patch itself
1701 if dst in copies:
1702 if dst in copies:
1702 del copies[dst]
1703 del copies[dst]
1703 for src, dsts in copies.iteritems():
1704 for src, dsts in copies.iteritems():
1704 for dst in dsts:
1705 for dst in dsts:
1705 repo.dirstate.copy(src, dst)
1706 repo.dirstate.copy(src, dst)
1706 else:
1707 else:
1707 for dst in a:
1708 for dst in a:
1708 repo.dirstate.add(dst)
1709 repo.dirstate.add(dst)
1709 # Drop useless copy information
1710 # Drop useless copy information
1710 for f in list(repo.dirstate.copies()):
1711 for f in list(repo.dirstate.copies()):
1711 repo.dirstate.copy(None, f)
1712 repo.dirstate.copy(None, f)
1712 for f in r:
1713 for f in r:
1713 repo.dirstate.remove(f)
1714 repo.dirstate.remove(f)
1714 # if the patch excludes a modified file, mark that
1715 # if the patch excludes a modified file, mark that
1715 # file with mtime=0 so status can see it.
1716 # file with mtime=0 so status can see it.
1716 mm = []
1717 mm = []
1717 for i in xrange(len(m) - 1, -1, -1):
1718 for i in xrange(len(m) - 1, -1, -1):
1718 if not matchfn(m[i]):
1719 if not matchfn(m[i]):
1719 mm.append(m[i])
1720 mm.append(m[i])
1720 del m[i]
1721 del m[i]
1721 for f in m:
1722 for f in m:
1722 repo.dirstate.normal(f)
1723 repo.dirstate.normal(f)
1723 for f in mm:
1724 for f in mm:
1724 repo.dirstate.normallookup(f)
1725 repo.dirstate.normallookup(f)
1725 for f in forget:
1726 for f in forget:
1726 repo.dirstate.drop(f)
1727 repo.dirstate.drop(f)
1727
1728
1728 user = ph.user or changes[1]
1729 user = ph.user or changes[1]
1729
1730
1730 oldphase = repo[top].phase()
1731 oldphase = repo[top].phase()
1731
1732
1732 # assumes strip can roll itself back if interrupted
1733 # assumes strip can roll itself back if interrupted
1733 repo.setparents(*cparents)
1734 repo.setparents(*cparents)
1734 repo.dirstate.endparentchange()
1735 repo.dirstate.endparentchange()
1735 self.applied.pop()
1736 self.applied.pop()
1736 self.applieddirty = True
1737 self.applieddirty = True
1737 strip(self.ui, repo, [top], update=False, backup=False)
1738 strip(self.ui, repo, [top], update=False, backup=False)
1738 except: # re-raises
1739 except: # re-raises
1739 repo.dirstate.invalidate()
1740 repo.dirstate.invalidate()
1740 raise
1741 raise
1741
1742
1742 try:
1743 try:
1743 # might be nice to attempt to roll back strip after this
1744 # might be nice to attempt to roll back strip after this
1744
1745
1745 defaultmsg = "[mq]: %s" % patchfn
1746 defaultmsg = "[mq]: %s" % patchfn
1746 editor = cmdutil.getcommiteditor(editform=editform)
1747 editor = cmdutil.getcommiteditor(editform=editform)
1747 if edit:
1748 if edit:
1748 def finishdesc(desc):
1749 def finishdesc(desc):
1749 if desc.rstrip():
1750 if desc.rstrip():
1750 ph.setmessage(desc)
1751 ph.setmessage(desc)
1751 return desc
1752 return desc
1752 return defaultmsg
1753 return defaultmsg
1753 # i18n: this message is shown in editor with "HG: " prefix
1754 # i18n: this message is shown in editor with "HG: " prefix
1754 extramsg = _('Leave message empty to use default message.')
1755 extramsg = _('Leave message empty to use default message.')
1755 editor = cmdutil.getcommiteditor(finishdesc=finishdesc,
1756 editor = cmdutil.getcommiteditor(finishdesc=finishdesc,
1756 extramsg=extramsg,
1757 extramsg=extramsg,
1757 editform=editform)
1758 editform=editform)
1758 message = msg or "\n".join(ph.message)
1759 message = msg or "\n".join(ph.message)
1759 elif not msg:
1760 elif not msg:
1760 if not ph.message:
1761 if not ph.message:
1761 message = defaultmsg
1762 message = defaultmsg
1762 else:
1763 else:
1763 message = "\n".join(ph.message)
1764 message = "\n".join(ph.message)
1764 else:
1765 else:
1765 message = msg
1766 message = msg
1766 ph.setmessage(msg)
1767 ph.setmessage(msg)
1767
1768
1768 # Ensure we create a new changeset in the same phase than
1769 # Ensure we create a new changeset in the same phase than
1769 # the old one.
1770 # the old one.
1770 n = newcommit(repo, oldphase, message, user, ph.date,
1771 n = newcommit(repo, oldphase, message, user, ph.date,
1771 match=match, force=True, editor=editor)
1772 match=match, force=True, editor=editor)
1772 # only write patch after a successful commit
1773 # only write patch after a successful commit
1773 c = [list(x) for x in refreshchanges]
1774 c = [list(x) for x in refreshchanges]
1774 if inclsubs:
1775 if inclsubs:
1775 self.putsubstate2changes(substatestate, c)
1776 self.putsubstate2changes(substatestate, c)
1776 chunks = patchmod.diff(repo, patchparent,
1777 chunks = patchmod.diff(repo, patchparent,
1777 changes=c, opts=diffopts)
1778 changes=c, opts=diffopts)
1778 comments = str(ph)
1779 comments = str(ph)
1779 if comments:
1780 if comments:
1780 patchf.write(comments)
1781 patchf.write(comments)
1781 for chunk in chunks:
1782 for chunk in chunks:
1782 patchf.write(chunk)
1783 patchf.write(chunk)
1783 patchf.close()
1784 patchf.close()
1784
1785
1785 marks = repo._bookmarks
1786 marks = repo._bookmarks
1786 for bm in bmlist:
1787 for bm in bmlist:
1787 marks[bm] = n
1788 marks[bm] = n
1788 marks.write()
1789 marks.write()
1789
1790
1790 self.applied.append(statusentry(n, patchfn))
1791 self.applied.append(statusentry(n, patchfn))
1791 except: # re-raises
1792 except: # re-raises
1792 ctx = repo[cparents[0]]
1793 ctx = repo[cparents[0]]
1793 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1794 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1794 self.savedirty()
1795 self.savedirty()
1795 self.ui.warn(_('refresh interrupted while patch was popped! '
1796 self.ui.warn(_('refresh interrupted while patch was popped! '
1796 '(revert --all, qpush to recover)\n'))
1797 '(revert --all, qpush to recover)\n'))
1797 raise
1798 raise
1798 finally:
1799 finally:
1799 wlock.release()
1800 wlock.release()
1800 self.removeundo(repo)
1801 self.removeundo(repo)
1801
1802
1802 def init(self, repo, create=False):
1803 def init(self, repo, create=False):
1803 if not create and os.path.isdir(self.path):
1804 if not create and os.path.isdir(self.path):
1804 raise util.Abort(_("patch queue directory already exists"))
1805 raise util.Abort(_("patch queue directory already exists"))
1805 try:
1806 try:
1806 os.mkdir(self.path)
1807 os.mkdir(self.path)
1807 except OSError, inst:
1808 except OSError, inst:
1808 if inst.errno != errno.EEXIST or not create:
1809 if inst.errno != errno.EEXIST or not create:
1809 raise
1810 raise
1810 if create:
1811 if create:
1811 return self.qrepo(create=True)
1812 return self.qrepo(create=True)
1812
1813
1813 def unapplied(self, repo, patch=None):
1814 def unapplied(self, repo, patch=None):
1814 if patch and patch not in self.series:
1815 if patch and patch not in self.series:
1815 raise util.Abort(_("patch %s is not in series file") % patch)
1816 raise util.Abort(_("patch %s is not in series file") % patch)
1816 if not patch:
1817 if not patch:
1817 start = self.seriesend()
1818 start = self.seriesend()
1818 else:
1819 else:
1819 start = self.series.index(patch) + 1
1820 start = self.series.index(patch) + 1
1820 unapplied = []
1821 unapplied = []
1821 for i in xrange(start, len(self.series)):
1822 for i in xrange(start, len(self.series)):
1822 pushable, reason = self.pushable(i)
1823 pushable, reason = self.pushable(i)
1823 if pushable:
1824 if pushable:
1824 unapplied.append((i, self.series[i]))
1825 unapplied.append((i, self.series[i]))
1825 self.explainpushable(i)
1826 self.explainpushable(i)
1826 return unapplied
1827 return unapplied
1827
1828
1828 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1829 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1829 summary=False):
1830 summary=False):
1830 def displayname(pfx, patchname, state):
1831 def displayname(pfx, patchname, state):
1831 if pfx:
1832 if pfx:
1832 self.ui.write(pfx)
1833 self.ui.write(pfx)
1833 if summary:
1834 if summary:
1834 ph = patchheader(self.join(patchname), self.plainmode)
1835 ph = patchheader(self.join(patchname), self.plainmode)
1835 if ph.message:
1836 if ph.message:
1836 msg = ph.message[0]
1837 msg = ph.message[0]
1837 else:
1838 else:
1838 msg = ''
1839 msg = ''
1839
1840
1840 if self.ui.formatted():
1841 if self.ui.formatted():
1841 width = self.ui.termwidth() - len(pfx) - len(patchname) - 2
1842 width = self.ui.termwidth() - len(pfx) - len(patchname) - 2
1842 if width > 0:
1843 if width > 0:
1843 msg = util.ellipsis(msg, width)
1844 msg = util.ellipsis(msg, width)
1844 else:
1845 else:
1845 msg = ''
1846 msg = ''
1846 self.ui.write(patchname, label='qseries.' + state)
1847 self.ui.write(patchname, label='qseries.' + state)
1847 self.ui.write(': ')
1848 self.ui.write(': ')
1848 self.ui.write(msg, label='qseries.message.' + state)
1849 self.ui.write(msg, label='qseries.message.' + state)
1849 else:
1850 else:
1850 self.ui.write(patchname, label='qseries.' + state)
1851 self.ui.write(patchname, label='qseries.' + state)
1851 self.ui.write('\n')
1852 self.ui.write('\n')
1852
1853
1853 applied = set([p.name for p in self.applied])
1854 applied = set([p.name for p in self.applied])
1854 if length is None:
1855 if length is None:
1855 length = len(self.series) - start
1856 length = len(self.series) - start
1856 if not missing:
1857 if not missing:
1857 if self.ui.verbose:
1858 if self.ui.verbose:
1858 idxwidth = len(str(start + length - 1))
1859 idxwidth = len(str(start + length - 1))
1859 for i in xrange(start, start + length):
1860 for i in xrange(start, start + length):
1860 patch = self.series[i]
1861 patch = self.series[i]
1861 if patch in applied:
1862 if patch in applied:
1862 char, state = 'A', 'applied'
1863 char, state = 'A', 'applied'
1863 elif self.pushable(i)[0]:
1864 elif self.pushable(i)[0]:
1864 char, state = 'U', 'unapplied'
1865 char, state = 'U', 'unapplied'
1865 else:
1866 else:
1866 char, state = 'G', 'guarded'
1867 char, state = 'G', 'guarded'
1867 pfx = ''
1868 pfx = ''
1868 if self.ui.verbose:
1869 if self.ui.verbose:
1869 pfx = '%*d %s ' % (idxwidth, i, char)
1870 pfx = '%*d %s ' % (idxwidth, i, char)
1870 elif status and status != char:
1871 elif status and status != char:
1871 continue
1872 continue
1872 displayname(pfx, patch, state)
1873 displayname(pfx, patch, state)
1873 else:
1874 else:
1874 msng_list = []
1875 msng_list = []
1875 for root, dirs, files in os.walk(self.path):
1876 for root, dirs, files in os.walk(self.path):
1876 d = root[len(self.path) + 1:]
1877 d = root[len(self.path) + 1:]
1877 for f in files:
1878 for f in files:
1878 fl = os.path.join(d, f)
1879 fl = os.path.join(d, f)
1879 if (fl not in self.series and
1880 if (fl not in self.series and
1880 fl not in (self.statuspath, self.seriespath,
1881 fl not in (self.statuspath, self.seriespath,
1881 self.guardspath)
1882 self.guardspath)
1882 and not fl.startswith('.')):
1883 and not fl.startswith('.')):
1883 msng_list.append(fl)
1884 msng_list.append(fl)
1884 for x in sorted(msng_list):
1885 for x in sorted(msng_list):
1885 pfx = self.ui.verbose and ('D ') or ''
1886 pfx = self.ui.verbose and ('D ') or ''
1886 displayname(pfx, x, 'missing')
1887 displayname(pfx, x, 'missing')
1887
1888
1888 def issaveline(self, l):
1889 def issaveline(self, l):
1889 if l.name == '.hg.patches.save.line':
1890 if l.name == '.hg.patches.save.line':
1890 return True
1891 return True
1891
1892
1892 def qrepo(self, create=False):
1893 def qrepo(self, create=False):
1893 ui = self.baseui.copy()
1894 ui = self.baseui.copy()
1894 if create or os.path.isdir(self.join(".hg")):
1895 if create or os.path.isdir(self.join(".hg")):
1895 return hg.repository(ui, path=self.path, create=create)
1896 return hg.repository(ui, path=self.path, create=create)
1896
1897
1897 def restore(self, repo, rev, delete=None, qupdate=None):
1898 def restore(self, repo, rev, delete=None, qupdate=None):
1898 desc = repo[rev].description().strip()
1899 desc = repo[rev].description().strip()
1899 lines = desc.splitlines()
1900 lines = desc.splitlines()
1900 i = 0
1901 i = 0
1901 datastart = None
1902 datastart = None
1902 series = []
1903 series = []
1903 applied = []
1904 applied = []
1904 qpp = None
1905 qpp = None
1905 for i, line in enumerate(lines):
1906 for i, line in enumerate(lines):
1906 if line == 'Patch Data:':
1907 if line == 'Patch Data:':
1907 datastart = i + 1
1908 datastart = i + 1
1908 elif line.startswith('Dirstate:'):
1909 elif line.startswith('Dirstate:'):
1909 l = line.rstrip()
1910 l = line.rstrip()
1910 l = l[10:].split(' ')
1911 l = l[10:].split(' ')
1911 qpp = [bin(x) for x in l]
1912 qpp = [bin(x) for x in l]
1912 elif datastart is not None:
1913 elif datastart is not None:
1913 l = line.rstrip()
1914 l = line.rstrip()
1914 n, name = l.split(':', 1)
1915 n, name = l.split(':', 1)
1915 if n:
1916 if n:
1916 applied.append(statusentry(bin(n), name))
1917 applied.append(statusentry(bin(n), name))
1917 else:
1918 else:
1918 series.append(l)
1919 series.append(l)
1919 if datastart is None:
1920 if datastart is None:
1920 self.ui.warn(_("no saved patch data found\n"))
1921 self.ui.warn(_("no saved patch data found\n"))
1921 return 1
1922 return 1
1922 self.ui.warn(_("restoring status: %s\n") % lines[0])
1923 self.ui.warn(_("restoring status: %s\n") % lines[0])
1923 self.fullseries = series
1924 self.fullseries = series
1924 self.applied = applied
1925 self.applied = applied
1925 self.parseseries()
1926 self.parseseries()
1926 self.seriesdirty = True
1927 self.seriesdirty = True
1927 self.applieddirty = True
1928 self.applieddirty = True
1928 heads = repo.changelog.heads()
1929 heads = repo.changelog.heads()
1929 if delete:
1930 if delete:
1930 if rev not in heads:
1931 if rev not in heads:
1931 self.ui.warn(_("save entry has children, leaving it alone\n"))
1932 self.ui.warn(_("save entry has children, leaving it alone\n"))
1932 else:
1933 else:
1933 self.ui.warn(_("removing save entry %s\n") % short(rev))
1934 self.ui.warn(_("removing save entry %s\n") % short(rev))
1934 pp = repo.dirstate.parents()
1935 pp = repo.dirstate.parents()
1935 if rev in pp:
1936 if rev in pp:
1936 update = True
1937 update = True
1937 else:
1938 else:
1938 update = False
1939 update = False
1939 strip(self.ui, repo, [rev], update=update, backup=False)
1940 strip(self.ui, repo, [rev], update=update, backup=False)
1940 if qpp:
1941 if qpp:
1941 self.ui.warn(_("saved queue repository parents: %s %s\n") %
1942 self.ui.warn(_("saved queue repository parents: %s %s\n") %
1942 (short(qpp[0]), short(qpp[1])))
1943 (short(qpp[0]), short(qpp[1])))
1943 if qupdate:
1944 if qupdate:
1944 self.ui.status(_("updating queue directory\n"))
1945 self.ui.status(_("updating queue directory\n"))
1945 r = self.qrepo()
1946 r = self.qrepo()
1946 if not r:
1947 if not r:
1947 self.ui.warn(_("unable to load queue repository\n"))
1948 self.ui.warn(_("unable to load queue repository\n"))
1948 return 1
1949 return 1
1949 hg.clean(r, qpp[0])
1950 hg.clean(r, qpp[0])
1950
1951
1951 def save(self, repo, msg=None):
1952 def save(self, repo, msg=None):
1952 if not self.applied:
1953 if not self.applied:
1953 self.ui.warn(_("save: no patches applied, exiting\n"))
1954 self.ui.warn(_("save: no patches applied, exiting\n"))
1954 return 1
1955 return 1
1955 if self.issaveline(self.applied[-1]):
1956 if self.issaveline(self.applied[-1]):
1956 self.ui.warn(_("status is already saved\n"))
1957 self.ui.warn(_("status is already saved\n"))
1957 return 1
1958 return 1
1958
1959
1959 if not msg:
1960 if not msg:
1960 msg = _("hg patches saved state")
1961 msg = _("hg patches saved state")
1961 else:
1962 else:
1962 msg = "hg patches: " + msg.rstrip('\r\n')
1963 msg = "hg patches: " + msg.rstrip('\r\n')
1963 r = self.qrepo()
1964 r = self.qrepo()
1964 if r:
1965 if r:
1965 pp = r.dirstate.parents()
1966 pp = r.dirstate.parents()
1966 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1967 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1967 msg += "\n\nPatch Data:\n"
1968 msg += "\n\nPatch Data:\n"
1968 msg += ''.join('%s\n' % x for x in self.applied)
1969 msg += ''.join('%s\n' % x for x in self.applied)
1969 msg += ''.join(':%s\n' % x for x in self.fullseries)
1970 msg += ''.join(':%s\n' % x for x in self.fullseries)
1970 n = repo.commit(msg, force=True)
1971 n = repo.commit(msg, force=True)
1971 if not n:
1972 if not n:
1972 self.ui.warn(_("repo commit failed\n"))
1973 self.ui.warn(_("repo commit failed\n"))
1973 return 1
1974 return 1
1974 self.applied.append(statusentry(n, '.hg.patches.save.line'))
1975 self.applied.append(statusentry(n, '.hg.patches.save.line'))
1975 self.applieddirty = True
1976 self.applieddirty = True
1976 self.removeundo(repo)
1977 self.removeundo(repo)
1977
1978
1978 def fullseriesend(self):
1979 def fullseriesend(self):
1979 if self.applied:
1980 if self.applied:
1980 p = self.applied[-1].name
1981 p = self.applied[-1].name
1981 end = self.findseries(p)
1982 end = self.findseries(p)
1982 if end is None:
1983 if end is None:
1983 return len(self.fullseries)
1984 return len(self.fullseries)
1984 return end + 1
1985 return end + 1
1985 return 0
1986 return 0
1986
1987
1987 def seriesend(self, all_patches=False):
1988 def seriesend(self, all_patches=False):
1988 """If all_patches is False, return the index of the next pushable patch
1989 """If all_patches is False, return the index of the next pushable patch
1989 in the series, or the series length. If all_patches is True, return the
1990 in the series, or the series length. If all_patches is True, return the
1990 index of the first patch past the last applied one.
1991 index of the first patch past the last applied one.
1991 """
1992 """
1992 end = 0
1993 end = 0
1993 def nextpatch(start):
1994 def nextpatch(start):
1994 if all_patches or start >= len(self.series):
1995 if all_patches or start >= len(self.series):
1995 return start
1996 return start
1996 for i in xrange(start, len(self.series)):
1997 for i in xrange(start, len(self.series)):
1997 p, reason = self.pushable(i)
1998 p, reason = self.pushable(i)
1998 if p:
1999 if p:
1999 return i
2000 return i
2000 self.explainpushable(i)
2001 self.explainpushable(i)
2001 return len(self.series)
2002 return len(self.series)
2002 if self.applied:
2003 if self.applied:
2003 p = self.applied[-1].name
2004 p = self.applied[-1].name
2004 try:
2005 try:
2005 end = self.series.index(p)
2006 end = self.series.index(p)
2006 except ValueError:
2007 except ValueError:
2007 return 0
2008 return 0
2008 return nextpatch(end + 1)
2009 return nextpatch(end + 1)
2009 return nextpatch(end)
2010 return nextpatch(end)
2010
2011
2011 def appliedname(self, index):
2012 def appliedname(self, index):
2012 pname = self.applied[index].name
2013 pname = self.applied[index].name
2013 if not self.ui.verbose:
2014 if not self.ui.verbose:
2014 p = pname
2015 p = pname
2015 else:
2016 else:
2016 p = str(self.series.index(pname)) + " " + pname
2017 p = str(self.series.index(pname)) + " " + pname
2017 return p
2018 return p
2018
2019
2019 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
2020 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
2020 force=None, git=False):
2021 force=None, git=False):
2021 def checkseries(patchname):
2022 def checkseries(patchname):
2022 if patchname in self.series:
2023 if patchname in self.series:
2023 raise util.Abort(_('patch %s is already in the series file')
2024 raise util.Abort(_('patch %s is already in the series file')
2024 % patchname)
2025 % patchname)
2025
2026
2026 if rev:
2027 if rev:
2027 if files:
2028 if files:
2028 raise util.Abort(_('option "-r" not valid when importing '
2029 raise util.Abort(_('option "-r" not valid when importing '
2029 'files'))
2030 'files'))
2030 rev = scmutil.revrange(repo, rev)
2031 rev = scmutil.revrange(repo, rev)
2031 rev.sort(reverse=True)
2032 rev.sort(reverse=True)
2032 elif not files:
2033 elif not files:
2033 raise util.Abort(_('no files or revisions specified'))
2034 raise util.Abort(_('no files or revisions specified'))
2034 if (len(files) > 1 or len(rev) > 1) and patchname:
2035 if (len(files) > 1 or len(rev) > 1) and patchname:
2035 raise util.Abort(_('option "-n" not valid when importing multiple '
2036 raise util.Abort(_('option "-n" not valid when importing multiple '
2036 'patches'))
2037 'patches'))
2037 imported = []
2038 imported = []
2038 if rev:
2039 if rev:
2039 # If mq patches are applied, we can only import revisions
2040 # If mq patches are applied, we can only import revisions
2040 # that form a linear path to qbase.
2041 # that form a linear path to qbase.
2041 # Otherwise, they should form a linear path to a head.
2042 # Otherwise, they should form a linear path to a head.
2042 heads = repo.changelog.heads(repo.changelog.node(rev.first()))
2043 heads = repo.changelog.heads(repo.changelog.node(rev.first()))
2043 if len(heads) > 1:
2044 if len(heads) > 1:
2044 raise util.Abort(_('revision %d is the root of more than one '
2045 raise util.Abort(_('revision %d is the root of more than one '
2045 'branch') % rev.last())
2046 'branch') % rev.last())
2046 if self.applied:
2047 if self.applied:
2047 base = repo.changelog.node(rev.first())
2048 base = repo.changelog.node(rev.first())
2048 if base in [n.node for n in self.applied]:
2049 if base in [n.node for n in self.applied]:
2049 raise util.Abort(_('revision %d is already managed')
2050 raise util.Abort(_('revision %d is already managed')
2050 % rev.first())
2051 % rev.first())
2051 if heads != [self.applied[-1].node]:
2052 if heads != [self.applied[-1].node]:
2052 raise util.Abort(_('revision %d is not the parent of '
2053 raise util.Abort(_('revision %d is not the parent of '
2053 'the queue') % rev.first())
2054 'the queue') % rev.first())
2054 base = repo.changelog.rev(self.applied[0].node)
2055 base = repo.changelog.rev(self.applied[0].node)
2055 lastparent = repo.changelog.parentrevs(base)[0]
2056 lastparent = repo.changelog.parentrevs(base)[0]
2056 else:
2057 else:
2057 if heads != [repo.changelog.node(rev.first())]:
2058 if heads != [repo.changelog.node(rev.first())]:
2058 raise util.Abort(_('revision %d has unmanaged children')
2059 raise util.Abort(_('revision %d has unmanaged children')
2059 % rev.first())
2060 % rev.first())
2060 lastparent = None
2061 lastparent = None
2061
2062
2062 diffopts = self.diffopts({'git': git})
2063 diffopts = self.diffopts({'git': git})
2063 tr = repo.transaction('qimport')
2064 tr = repo.transaction('qimport')
2064 try:
2065 try:
2065 for r in rev:
2066 for r in rev:
2066 if not repo[r].mutable():
2067 if not repo[r].mutable():
2067 raise util.Abort(_('revision %d is not mutable') % r,
2068 raise util.Abort(_('revision %d is not mutable') % r,
2068 hint=_('see "hg help phases" '
2069 hint=_('see "hg help phases" '
2069 'for details'))
2070 'for details'))
2070 p1, p2 = repo.changelog.parentrevs(r)
2071 p1, p2 = repo.changelog.parentrevs(r)
2071 n = repo.changelog.node(r)
2072 n = repo.changelog.node(r)
2072 if p2 != nullrev:
2073 if p2 != nullrev:
2073 raise util.Abort(_('cannot import merge revision %d')
2074 raise util.Abort(_('cannot import merge revision %d')
2074 % r)
2075 % r)
2075 if lastparent and lastparent != r:
2076 if lastparent and lastparent != r:
2076 raise util.Abort(_('revision %d is not the parent of '
2077 raise util.Abort(_('revision %d is not the parent of '
2077 '%d')
2078 '%d')
2078 % (r, lastparent))
2079 % (r, lastparent))
2079 lastparent = p1
2080 lastparent = p1
2080
2081
2081 if not patchname:
2082 if not patchname:
2082 patchname = normname('%d.diff' % r)
2083 patchname = normname('%d.diff' % r)
2083 checkseries(patchname)
2084 checkseries(patchname)
2084 self.checkpatchname(patchname, force)
2085 self.checkpatchname(patchname, force)
2085 self.fullseries.insert(0, patchname)
2086 self.fullseries.insert(0, patchname)
2086
2087
2087 patchf = self.opener(patchname, "w")
2088 patchf = self.opener(patchname, "w")
2088 cmdutil.export(repo, [n], fp=patchf, opts=diffopts)
2089 cmdutil.export(repo, [n], fp=patchf, opts=diffopts)
2089 patchf.close()
2090 patchf.close()
2090
2091
2091 se = statusentry(n, patchname)
2092 se = statusentry(n, patchname)
2092 self.applied.insert(0, se)
2093 self.applied.insert(0, se)
2093
2094
2094 self.added.append(patchname)
2095 self.added.append(patchname)
2095 imported.append(patchname)
2096 imported.append(patchname)
2096 patchname = None
2097 patchname = None
2097 if rev and repo.ui.configbool('mq', 'secret', False):
2098 if rev and repo.ui.configbool('mq', 'secret', False):
2098 # if we added anything with --rev, move the secret root
2099 # if we added anything with --rev, move the secret root
2099 phases.retractboundary(repo, tr, phases.secret, [n])
2100 phases.retractboundary(repo, tr, phases.secret, [n])
2100 self.parseseries()
2101 self.parseseries()
2101 self.applieddirty = True
2102 self.applieddirty = True
2102 self.seriesdirty = True
2103 self.seriesdirty = True
2103 tr.close()
2104 tr.close()
2104 finally:
2105 finally:
2105 tr.release()
2106 tr.release()
2106
2107
2107 for i, filename in enumerate(files):
2108 for i, filename in enumerate(files):
2108 if existing:
2109 if existing:
2109 if filename == '-':
2110 if filename == '-':
2110 raise util.Abort(_('-e is incompatible with import from -'))
2111 raise util.Abort(_('-e is incompatible with import from -'))
2111 filename = normname(filename)
2112 filename = normname(filename)
2112 self.checkreservedname(filename)
2113 self.checkreservedname(filename)
2113 if util.url(filename).islocal():
2114 if util.url(filename).islocal():
2114 originpath = self.join(filename)
2115 originpath = self.join(filename)
2115 if not os.path.isfile(originpath):
2116 if not os.path.isfile(originpath):
2116 raise util.Abort(
2117 raise util.Abort(
2117 _("patch %s does not exist") % filename)
2118 _("patch %s does not exist") % filename)
2118
2119
2119 if patchname:
2120 if patchname:
2120 self.checkpatchname(patchname, force)
2121 self.checkpatchname(patchname, force)
2121
2122
2122 self.ui.write(_('renaming %s to %s\n')
2123 self.ui.write(_('renaming %s to %s\n')
2123 % (filename, patchname))
2124 % (filename, patchname))
2124 util.rename(originpath, self.join(patchname))
2125 util.rename(originpath, self.join(patchname))
2125 else:
2126 else:
2126 patchname = filename
2127 patchname = filename
2127
2128
2128 else:
2129 else:
2129 if filename == '-' and not patchname:
2130 if filename == '-' and not patchname:
2130 raise util.Abort(_('need --name to import a patch from -'))
2131 raise util.Abort(_('need --name to import a patch from -'))
2131 elif not patchname:
2132 elif not patchname:
2132 patchname = normname(os.path.basename(filename.rstrip('/')))
2133 patchname = normname(os.path.basename(filename.rstrip('/')))
2133 self.checkpatchname(patchname, force)
2134 self.checkpatchname(patchname, force)
2134 try:
2135 try:
2135 if filename == '-':
2136 if filename == '-':
2136 text = self.ui.fin.read()
2137 text = self.ui.fin.read()
2137 else:
2138 else:
2138 fp = hg.openpath(self.ui, filename)
2139 fp = hg.openpath(self.ui, filename)
2139 text = fp.read()
2140 text = fp.read()
2140 fp.close()
2141 fp.close()
2141 except (OSError, IOError):
2142 except (OSError, IOError):
2142 raise util.Abort(_("unable to read file %s") % filename)
2143 raise util.Abort(_("unable to read file %s") % filename)
2143 patchf = self.opener(patchname, "w")
2144 patchf = self.opener(patchname, "w")
2144 patchf.write(text)
2145 patchf.write(text)
2145 patchf.close()
2146 patchf.close()
2146 if not force:
2147 if not force:
2147 checkseries(patchname)
2148 checkseries(patchname)
2148 if patchname not in self.series:
2149 if patchname not in self.series:
2149 index = self.fullseriesend() + i
2150 index = self.fullseriesend() + i
2150 self.fullseries[index:index] = [patchname]
2151 self.fullseries[index:index] = [patchname]
2151 self.parseseries()
2152 self.parseseries()
2152 self.seriesdirty = True
2153 self.seriesdirty = True
2153 self.ui.warn(_("adding %s to series file\n") % patchname)
2154 self.ui.warn(_("adding %s to series file\n") % patchname)
2154 self.added.append(patchname)
2155 self.added.append(patchname)
2155 imported.append(patchname)
2156 imported.append(patchname)
2156 patchname = None
2157 patchname = None
2157
2158
2158 self.removeundo(repo)
2159 self.removeundo(repo)
2159 return imported
2160 return imported
2160
2161
2161 def fixkeepchangesopts(ui, opts):
2162 def fixkeepchangesopts(ui, opts):
2162 if (not ui.configbool('mq', 'keepchanges') or opts.get('force')
2163 if (not ui.configbool('mq', 'keepchanges') or opts.get('force')
2163 or opts.get('exact')):
2164 or opts.get('exact')):
2164 return opts
2165 return opts
2165 opts = dict(opts)
2166 opts = dict(opts)
2166 opts['keep_changes'] = True
2167 opts['keep_changes'] = True
2167 return opts
2168 return opts
2168
2169
2169 @command("qdelete|qremove|qrm",
2170 @command("qdelete|qremove|qrm",
2170 [('k', 'keep', None, _('keep patch file')),
2171 [('k', 'keep', None, _('keep patch file')),
2171 ('r', 'rev', [],
2172 ('r', 'rev', [],
2172 _('stop managing a revision (DEPRECATED)'), _('REV'))],
2173 _('stop managing a revision (DEPRECATED)'), _('REV'))],
2173 _('hg qdelete [-k] [PATCH]...'))
2174 _('hg qdelete [-k] [PATCH]...'))
2174 def delete(ui, repo, *patches, **opts):
2175 def delete(ui, repo, *patches, **opts):
2175 """remove patches from queue
2176 """remove patches from queue
2176
2177
2177 The patches must not be applied, and at least one patch is required. Exact
2178 The patches must not be applied, and at least one patch is required. Exact
2178 patch identifiers must be given. With -k/--keep, the patch files are
2179 patch identifiers must be given. With -k/--keep, the patch files are
2179 preserved in the patch directory.
2180 preserved in the patch directory.
2180
2181
2181 To stop managing a patch and move it into permanent history,
2182 To stop managing a patch and move it into permanent history,
2182 use the :hg:`qfinish` command."""
2183 use the :hg:`qfinish` command."""
2183 q = repo.mq
2184 q = repo.mq
2184 q.delete(repo, patches, opts)
2185 q.delete(repo, patches, opts)
2185 q.savedirty()
2186 q.savedirty()
2186 return 0
2187 return 0
2187
2188
2188 @command("qapplied",
2189 @command("qapplied",
2189 [('1', 'last', None, _('show only the preceding applied patch'))
2190 [('1', 'last', None, _('show only the preceding applied patch'))
2190 ] + seriesopts,
2191 ] + seriesopts,
2191 _('hg qapplied [-1] [-s] [PATCH]'))
2192 _('hg qapplied [-1] [-s] [PATCH]'))
2192 def applied(ui, repo, patch=None, **opts):
2193 def applied(ui, repo, patch=None, **opts):
2193 """print the patches already applied
2194 """print the patches already applied
2194
2195
2195 Returns 0 on success."""
2196 Returns 0 on success."""
2196
2197
2197 q = repo.mq
2198 q = repo.mq
2198
2199
2199 if patch:
2200 if patch:
2200 if patch not in q.series:
2201 if patch not in q.series:
2201 raise util.Abort(_("patch %s is not in series file") % patch)
2202 raise util.Abort(_("patch %s is not in series file") % patch)
2202 end = q.series.index(patch) + 1
2203 end = q.series.index(patch) + 1
2203 else:
2204 else:
2204 end = q.seriesend(True)
2205 end = q.seriesend(True)
2205
2206
2206 if opts.get('last') and not end:
2207 if opts.get('last') and not end:
2207 ui.write(_("no patches applied\n"))
2208 ui.write(_("no patches applied\n"))
2208 return 1
2209 return 1
2209 elif opts.get('last') and end == 1:
2210 elif opts.get('last') and end == 1:
2210 ui.write(_("only one patch applied\n"))
2211 ui.write(_("only one patch applied\n"))
2211 return 1
2212 return 1
2212 elif opts.get('last'):
2213 elif opts.get('last'):
2213 start = end - 2
2214 start = end - 2
2214 end = 1
2215 end = 1
2215 else:
2216 else:
2216 start = 0
2217 start = 0
2217
2218
2218 q.qseries(repo, length=end, start=start, status='A',
2219 q.qseries(repo, length=end, start=start, status='A',
2219 summary=opts.get('summary'))
2220 summary=opts.get('summary'))
2220
2221
2221
2222
2222 @command("qunapplied",
2223 @command("qunapplied",
2223 [('1', 'first', None, _('show only the first patch'))] + seriesopts,
2224 [('1', 'first', None, _('show only the first patch'))] + seriesopts,
2224 _('hg qunapplied [-1] [-s] [PATCH]'))
2225 _('hg qunapplied [-1] [-s] [PATCH]'))
2225 def unapplied(ui, repo, patch=None, **opts):
2226 def unapplied(ui, repo, patch=None, **opts):
2226 """print the patches not yet applied
2227 """print the patches not yet applied
2227
2228
2228 Returns 0 on success."""
2229 Returns 0 on success."""
2229
2230
2230 q = repo.mq
2231 q = repo.mq
2231 if patch:
2232 if patch:
2232 if patch not in q.series:
2233 if patch not in q.series:
2233 raise util.Abort(_("patch %s is not in series file") % patch)
2234 raise util.Abort(_("patch %s is not in series file") % patch)
2234 start = q.series.index(patch) + 1
2235 start = q.series.index(patch) + 1
2235 else:
2236 else:
2236 start = q.seriesend(True)
2237 start = q.seriesend(True)
2237
2238
2238 if start == len(q.series) and opts.get('first'):
2239 if start == len(q.series) and opts.get('first'):
2239 ui.write(_("all patches applied\n"))
2240 ui.write(_("all patches applied\n"))
2240 return 1
2241 return 1
2241
2242
2242 if opts.get('first'):
2243 if opts.get('first'):
2243 length = 1
2244 length = 1
2244 else:
2245 else:
2245 length = None
2246 length = None
2246 q.qseries(repo, start=start, length=length, status='U',
2247 q.qseries(repo, start=start, length=length, status='U',
2247 summary=opts.get('summary'))
2248 summary=opts.get('summary'))
2248
2249
2249 @command("qimport",
2250 @command("qimport",
2250 [('e', 'existing', None, _('import file in patch directory')),
2251 [('e', 'existing', None, _('import file in patch directory')),
2251 ('n', 'name', '',
2252 ('n', 'name', '',
2252 _('name of patch file'), _('NAME')),
2253 _('name of patch file'), _('NAME')),
2253 ('f', 'force', None, _('overwrite existing files')),
2254 ('f', 'force', None, _('overwrite existing files')),
2254 ('r', 'rev', [],
2255 ('r', 'rev', [],
2255 _('place existing revisions under mq control'), _('REV')),
2256 _('place existing revisions under mq control'), _('REV')),
2256 ('g', 'git', None, _('use git extended diff format')),
2257 ('g', 'git', None, _('use git extended diff format')),
2257 ('P', 'push', None, _('qpush after importing'))],
2258 ('P', 'push', None, _('qpush after importing'))],
2258 _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... [FILE]...'))
2259 _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... [FILE]...'))
2259 def qimport(ui, repo, *filename, **opts):
2260 def qimport(ui, repo, *filename, **opts):
2260 """import a patch or existing changeset
2261 """import a patch or existing changeset
2261
2262
2262 The patch is inserted into the series after the last applied
2263 The patch is inserted into the series after the last applied
2263 patch. If no patches have been applied, qimport prepends the patch
2264 patch. If no patches have been applied, qimport prepends the patch
2264 to the series.
2265 to the series.
2265
2266
2266 The patch will have the same name as its source file unless you
2267 The patch will have the same name as its source file unless you
2267 give it a new one with -n/--name.
2268 give it a new one with -n/--name.
2268
2269
2269 You can register an existing patch inside the patch directory with
2270 You can register an existing patch inside the patch directory with
2270 the -e/--existing flag.
2271 the -e/--existing flag.
2271
2272
2272 With -f/--force, an existing patch of the same name will be
2273 With -f/--force, an existing patch of the same name will be
2273 overwritten.
2274 overwritten.
2274
2275
2275 An existing changeset may be placed under mq control with -r/--rev
2276 An existing changeset may be placed under mq control with -r/--rev
2276 (e.g. qimport --rev . -n patch will place the current revision
2277 (e.g. qimport --rev . -n patch will place the current revision
2277 under mq control). With -g/--git, patches imported with --rev will
2278 under mq control). With -g/--git, patches imported with --rev will
2278 use the git diff format. See the diffs help topic for information
2279 use the git diff format. See the diffs help topic for information
2279 on why this is important for preserving rename/copy information
2280 on why this is important for preserving rename/copy information
2280 and permission changes. Use :hg:`qfinish` to remove changesets
2281 and permission changes. Use :hg:`qfinish` to remove changesets
2281 from mq control.
2282 from mq control.
2282
2283
2283 To import a patch from standard input, pass - as the patch file.
2284 To import a patch from standard input, pass - as the patch file.
2284 When importing from standard input, a patch name must be specified
2285 When importing from standard input, a patch name must be specified
2285 using the --name flag.
2286 using the --name flag.
2286
2287
2287 To import an existing patch while renaming it::
2288 To import an existing patch while renaming it::
2288
2289
2289 hg qimport -e existing-patch -n new-name
2290 hg qimport -e existing-patch -n new-name
2290
2291
2291 Returns 0 if import succeeded.
2292 Returns 0 if import succeeded.
2292 """
2293 """
2293 lock = repo.lock() # cause this may move phase
2294 lock = repo.lock() # cause this may move phase
2294 try:
2295 try:
2295 q = repo.mq
2296 q = repo.mq
2296 try:
2297 try:
2297 imported = q.qimport(
2298 imported = q.qimport(
2298 repo, filename, patchname=opts.get('name'),
2299 repo, filename, patchname=opts.get('name'),
2299 existing=opts.get('existing'), force=opts.get('force'),
2300 existing=opts.get('existing'), force=opts.get('force'),
2300 rev=opts.get('rev'), git=opts.get('git'))
2301 rev=opts.get('rev'), git=opts.get('git'))
2301 finally:
2302 finally:
2302 q.savedirty()
2303 q.savedirty()
2303 finally:
2304 finally:
2304 lock.release()
2305 lock.release()
2305
2306
2306 if imported and opts.get('push') and not opts.get('rev'):
2307 if imported and opts.get('push') and not opts.get('rev'):
2307 return q.push(repo, imported[-1])
2308 return q.push(repo, imported[-1])
2308 return 0
2309 return 0
2309
2310
2310 def qinit(ui, repo, create):
2311 def qinit(ui, repo, create):
2311 """initialize a new queue repository
2312 """initialize a new queue repository
2312
2313
2313 This command also creates a series file for ordering patches, and
2314 This command also creates a series file for ordering patches, and
2314 an mq-specific .hgignore file in the queue repository, to exclude
2315 an mq-specific .hgignore file in the queue repository, to exclude
2315 the status and guards files (these contain mostly transient state).
2316 the status and guards files (these contain mostly transient state).
2316
2317
2317 Returns 0 if initialization succeeded."""
2318 Returns 0 if initialization succeeded."""
2318 q = repo.mq
2319 q = repo.mq
2319 r = q.init(repo, create)
2320 r = q.init(repo, create)
2320 q.savedirty()
2321 q.savedirty()
2321 if r:
2322 if r:
2322 if not os.path.exists(r.wjoin('.hgignore')):
2323 if not os.path.exists(r.wjoin('.hgignore')):
2323 fp = r.wvfs('.hgignore', 'w')
2324 fp = r.wvfs('.hgignore', 'w')
2324 fp.write('^\\.hg\n')
2325 fp.write('^\\.hg\n')
2325 fp.write('^\\.mq\n')
2326 fp.write('^\\.mq\n')
2326 fp.write('syntax: glob\n')
2327 fp.write('syntax: glob\n')
2327 fp.write('status\n')
2328 fp.write('status\n')
2328 fp.write('guards\n')
2329 fp.write('guards\n')
2329 fp.close()
2330 fp.close()
2330 if not os.path.exists(r.wjoin('series')):
2331 if not os.path.exists(r.wjoin('series')):
2331 r.wvfs('series', 'w').close()
2332 r.wvfs('series', 'w').close()
2332 r[None].add(['.hgignore', 'series'])
2333 r[None].add(['.hgignore', 'series'])
2333 commands.add(ui, r)
2334 commands.add(ui, r)
2334 return 0
2335 return 0
2335
2336
2336 @command("^qinit",
2337 @command("^qinit",
2337 [('c', 'create-repo', None, _('create queue repository'))],
2338 [('c', 'create-repo', None, _('create queue repository'))],
2338 _('hg qinit [-c]'))
2339 _('hg qinit [-c]'))
2339 def init(ui, repo, **opts):
2340 def init(ui, repo, **opts):
2340 """init a new queue repository (DEPRECATED)
2341 """init a new queue repository (DEPRECATED)
2341
2342
2342 The queue repository is unversioned by default. If
2343 The queue repository is unversioned by default. If
2343 -c/--create-repo is specified, qinit will create a separate nested
2344 -c/--create-repo is specified, qinit will create a separate nested
2344 repository for patches (qinit -c may also be run later to convert
2345 repository for patches (qinit -c may also be run later to convert
2345 an unversioned patch repository into a versioned one). You can use
2346 an unversioned patch repository into a versioned one). You can use
2346 qcommit to commit changes to this queue repository.
2347 qcommit to commit changes to this queue repository.
2347
2348
2348 This command is deprecated. Without -c, it's implied by other relevant
2349 This command is deprecated. Without -c, it's implied by other relevant
2349 commands. With -c, use :hg:`init --mq` instead."""
2350 commands. With -c, use :hg:`init --mq` instead."""
2350 return qinit(ui, repo, create=opts.get('create_repo'))
2351 return qinit(ui, repo, create=opts.get('create_repo'))
2351
2352
2352 @command("qclone",
2353 @command("qclone",
2353 [('', 'pull', None, _('use pull protocol to copy metadata')),
2354 [('', 'pull', None, _('use pull protocol to copy metadata')),
2354 ('U', 'noupdate', None,
2355 ('U', 'noupdate', None,
2355 _('do not update the new working directories')),
2356 _('do not update the new working directories')),
2356 ('', 'uncompressed', None,
2357 ('', 'uncompressed', None,
2357 _('use uncompressed transfer (fast over LAN)')),
2358 _('use uncompressed transfer (fast over LAN)')),
2358 ('p', 'patches', '',
2359 ('p', 'patches', '',
2359 _('location of source patch repository'), _('REPO')),
2360 _('location of source patch repository'), _('REPO')),
2360 ] + commands.remoteopts,
2361 ] + commands.remoteopts,
2361 _('hg qclone [OPTION]... SOURCE [DEST]'),
2362 _('hg qclone [OPTION]... SOURCE [DEST]'),
2362 norepo=True)
2363 norepo=True)
2363 def clone(ui, source, dest=None, **opts):
2364 def clone(ui, source, dest=None, **opts):
2364 '''clone main and patch repository at same time
2365 '''clone main and patch repository at same time
2365
2366
2366 If source is local, destination will have no patches applied. If
2367 If source is local, destination will have no patches applied. If
2367 source is remote, this command can not check if patches are
2368 source is remote, this command can not check if patches are
2368 applied in source, so cannot guarantee that patches are not
2369 applied in source, so cannot guarantee that patches are not
2369 applied in destination. If you clone remote repository, be sure
2370 applied in destination. If you clone remote repository, be sure
2370 before that it has no patches applied.
2371 before that it has no patches applied.
2371
2372
2372 Source patch repository is looked for in <src>/.hg/patches by
2373 Source patch repository is looked for in <src>/.hg/patches by
2373 default. Use -p <url> to change.
2374 default. Use -p <url> to change.
2374
2375
2375 The patch directory must be a nested Mercurial repository, as
2376 The patch directory must be a nested Mercurial repository, as
2376 would be created by :hg:`init --mq`.
2377 would be created by :hg:`init --mq`.
2377
2378
2378 Return 0 on success.
2379 Return 0 on success.
2379 '''
2380 '''
2380 def patchdir(repo):
2381 def patchdir(repo):
2381 """compute a patch repo url from a repo object"""
2382 """compute a patch repo url from a repo object"""
2382 url = repo.url()
2383 url = repo.url()
2383 if url.endswith('/'):
2384 if url.endswith('/'):
2384 url = url[:-1]
2385 url = url[:-1]
2385 return url + '/.hg/patches'
2386 return url + '/.hg/patches'
2386
2387
2387 # main repo (destination and sources)
2388 # main repo (destination and sources)
2388 if dest is None:
2389 if dest is None:
2389 dest = hg.defaultdest(source)
2390 dest = hg.defaultdest(source)
2390 sr = hg.peer(ui, opts, ui.expandpath(source))
2391 sr = hg.peer(ui, opts, ui.expandpath(source))
2391
2392
2392 # patches repo (source only)
2393 # patches repo (source only)
2393 if opts.get('patches'):
2394 if opts.get('patches'):
2394 patchespath = ui.expandpath(opts.get('patches'))
2395 patchespath = ui.expandpath(opts.get('patches'))
2395 else:
2396 else:
2396 patchespath = patchdir(sr)
2397 patchespath = patchdir(sr)
2397 try:
2398 try:
2398 hg.peer(ui, opts, patchespath)
2399 hg.peer(ui, opts, patchespath)
2399 except error.RepoError:
2400 except error.RepoError:
2400 raise util.Abort(_('versioned patch repository not found'
2401 raise util.Abort(_('versioned patch repository not found'
2401 ' (see init --mq)'))
2402 ' (see init --mq)'))
2402 qbase, destrev = None, None
2403 qbase, destrev = None, None
2403 if sr.local():
2404 if sr.local():
2404 repo = sr.local()
2405 repo = sr.local()
2405 if repo.mq.applied and repo[qbase].phase() != phases.secret:
2406 if repo.mq.applied and repo[qbase].phase() != phases.secret:
2406 qbase = repo.mq.applied[0].node
2407 qbase = repo.mq.applied[0].node
2407 if not hg.islocal(dest):
2408 if not hg.islocal(dest):
2408 heads = set(repo.heads())
2409 heads = set(repo.heads())
2409 destrev = list(heads.difference(repo.heads(qbase)))
2410 destrev = list(heads.difference(repo.heads(qbase)))
2410 destrev.append(repo.changelog.parents(qbase)[0])
2411 destrev.append(repo.changelog.parents(qbase)[0])
2411 elif sr.capable('lookup'):
2412 elif sr.capable('lookup'):
2412 try:
2413 try:
2413 qbase = sr.lookup('qbase')
2414 qbase = sr.lookup('qbase')
2414 except error.RepoError:
2415 except error.RepoError:
2415 pass
2416 pass
2416
2417
2417 ui.note(_('cloning main repository\n'))
2418 ui.note(_('cloning main repository\n'))
2418 sr, dr = hg.clone(ui, opts, sr.url(), dest,
2419 sr, dr = hg.clone(ui, opts, sr.url(), dest,
2419 pull=opts.get('pull'),
2420 pull=opts.get('pull'),
2420 rev=destrev,
2421 rev=destrev,
2421 update=False,
2422 update=False,
2422 stream=opts.get('uncompressed'))
2423 stream=opts.get('uncompressed'))
2423
2424
2424 ui.note(_('cloning patch repository\n'))
2425 ui.note(_('cloning patch repository\n'))
2425 hg.clone(ui, opts, opts.get('patches') or patchdir(sr), patchdir(dr),
2426 hg.clone(ui, opts, opts.get('patches') or patchdir(sr), patchdir(dr),
2426 pull=opts.get('pull'), update=not opts.get('noupdate'),
2427 pull=opts.get('pull'), update=not opts.get('noupdate'),
2427 stream=opts.get('uncompressed'))
2428 stream=opts.get('uncompressed'))
2428
2429
2429 if dr.local():
2430 if dr.local():
2430 repo = dr.local()
2431 repo = dr.local()
2431 if qbase:
2432 if qbase:
2432 ui.note(_('stripping applied patches from destination '
2433 ui.note(_('stripping applied patches from destination '
2433 'repository\n'))
2434 'repository\n'))
2434 strip(ui, repo, [qbase], update=False, backup=None)
2435 strip(ui, repo, [qbase], update=False, backup=None)
2435 if not opts.get('noupdate'):
2436 if not opts.get('noupdate'):
2436 ui.note(_('updating destination repository\n'))
2437 ui.note(_('updating destination repository\n'))
2437 hg.update(repo, repo.changelog.tip())
2438 hg.update(repo, repo.changelog.tip())
2438
2439
2439 @command("qcommit|qci",
2440 @command("qcommit|qci",
2440 commands.table["^commit|ci"][1],
2441 commands.table["^commit|ci"][1],
2441 _('hg qcommit [OPTION]... [FILE]...'),
2442 _('hg qcommit [OPTION]... [FILE]...'),
2442 inferrepo=True)
2443 inferrepo=True)
2443 def commit(ui, repo, *pats, **opts):
2444 def commit(ui, repo, *pats, **opts):
2444 """commit changes in the queue repository (DEPRECATED)
2445 """commit changes in the queue repository (DEPRECATED)
2445
2446
2446 This command is deprecated; use :hg:`commit --mq` instead."""
2447 This command is deprecated; use :hg:`commit --mq` instead."""
2447 q = repo.mq
2448 q = repo.mq
2448 r = q.qrepo()
2449 r = q.qrepo()
2449 if not r:
2450 if not r:
2450 raise util.Abort('no queue repository')
2451 raise util.Abort('no queue repository')
2451 commands.commit(r.ui, r, *pats, **opts)
2452 commands.commit(r.ui, r, *pats, **opts)
2452
2453
2453 @command("qseries",
2454 @command("qseries",
2454 [('m', 'missing', None, _('print patches not in series')),
2455 [('m', 'missing', None, _('print patches not in series')),
2455 ] + seriesopts,
2456 ] + seriesopts,
2456 _('hg qseries [-ms]'))
2457 _('hg qseries [-ms]'))
2457 def series(ui, repo, **opts):
2458 def series(ui, repo, **opts):
2458 """print the entire series file
2459 """print the entire series file
2459
2460
2460 Returns 0 on success."""
2461 Returns 0 on success."""
2461 repo.mq.qseries(repo, missing=opts.get('missing'),
2462 repo.mq.qseries(repo, missing=opts.get('missing'),
2462 summary=opts.get('summary'))
2463 summary=opts.get('summary'))
2463 return 0
2464 return 0
2464
2465
2465 @command("qtop", seriesopts, _('hg qtop [-s]'))
2466 @command("qtop", seriesopts, _('hg qtop [-s]'))
2466 def top(ui, repo, **opts):
2467 def top(ui, repo, **opts):
2467 """print the name of the current patch
2468 """print the name of the current patch
2468
2469
2469 Returns 0 on success."""
2470 Returns 0 on success."""
2470 q = repo.mq
2471 q = repo.mq
2471 if q.applied:
2472 if q.applied:
2472 t = q.seriesend(True)
2473 t = q.seriesend(True)
2473 else:
2474 else:
2474 t = 0
2475 t = 0
2475
2476
2476 if t:
2477 if t:
2477 q.qseries(repo, start=t - 1, length=1, status='A',
2478 q.qseries(repo, start=t - 1, length=1, status='A',
2478 summary=opts.get('summary'))
2479 summary=opts.get('summary'))
2479 else:
2480 else:
2480 ui.write(_("no patches applied\n"))
2481 ui.write(_("no patches applied\n"))
2481 return 1
2482 return 1
2482
2483
2483 @command("qnext", seriesopts, _('hg qnext [-s]'))
2484 @command("qnext", seriesopts, _('hg qnext [-s]'))
2484 def next(ui, repo, **opts):
2485 def next(ui, repo, **opts):
2485 """print the name of the next pushable patch
2486 """print the name of the next pushable patch
2486
2487
2487 Returns 0 on success."""
2488 Returns 0 on success."""
2488 q = repo.mq
2489 q = repo.mq
2489 end = q.seriesend()
2490 end = q.seriesend()
2490 if end == len(q.series):
2491 if end == len(q.series):
2491 ui.write(_("all patches applied\n"))
2492 ui.write(_("all patches applied\n"))
2492 return 1
2493 return 1
2493 q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
2494 q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
2494
2495
2495 @command("qprev", seriesopts, _('hg qprev [-s]'))
2496 @command("qprev", seriesopts, _('hg qprev [-s]'))
2496 def prev(ui, repo, **opts):
2497 def prev(ui, repo, **opts):
2497 """print the name of the preceding applied patch
2498 """print the name of the preceding applied patch
2498
2499
2499 Returns 0 on success."""
2500 Returns 0 on success."""
2500 q = repo.mq
2501 q = repo.mq
2501 l = len(q.applied)
2502 l = len(q.applied)
2502 if l == 1:
2503 if l == 1:
2503 ui.write(_("only one patch applied\n"))
2504 ui.write(_("only one patch applied\n"))
2504 return 1
2505 return 1
2505 if not l:
2506 if not l:
2506 ui.write(_("no patches applied\n"))
2507 ui.write(_("no patches applied\n"))
2507 return 1
2508 return 1
2508 idx = q.series.index(q.applied[-2].name)
2509 idx = q.series.index(q.applied[-2].name)
2509 q.qseries(repo, start=idx, length=1, status='A',
2510 q.qseries(repo, start=idx, length=1, status='A',
2510 summary=opts.get('summary'))
2511 summary=opts.get('summary'))
2511
2512
2512 def setupheaderopts(ui, opts):
2513 def setupheaderopts(ui, opts):
2513 if not opts.get('user') and opts.get('currentuser'):
2514 if not opts.get('user') and opts.get('currentuser'):
2514 opts['user'] = ui.username()
2515 opts['user'] = ui.username()
2515 if not opts.get('date') and opts.get('currentdate'):
2516 if not opts.get('date') and opts.get('currentdate'):
2516 opts['date'] = "%d %d" % util.makedate()
2517 opts['date'] = "%d %d" % util.makedate()
2517
2518
2518 @command("^qnew",
2519 @command("^qnew",
2519 [('e', 'edit', None, _('invoke editor on commit messages')),
2520 [('e', 'edit', None, _('invoke editor on commit messages')),
2520 ('f', 'force', None, _('import uncommitted changes (DEPRECATED)')),
2521 ('f', 'force', None, _('import uncommitted changes (DEPRECATED)')),
2521 ('g', 'git', None, _('use git extended diff format')),
2522 ('g', 'git', None, _('use git extended diff format')),
2522 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2523 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2523 ('u', 'user', '',
2524 ('u', 'user', '',
2524 _('add "From: <USER>" to patch'), _('USER')),
2525 _('add "From: <USER>" to patch'), _('USER')),
2525 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2526 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2526 ('d', 'date', '',
2527 ('d', 'date', '',
2527 _('add "Date: <DATE>" to patch'), _('DATE'))
2528 _('add "Date: <DATE>" to patch'), _('DATE'))
2528 ] + commands.walkopts + commands.commitopts,
2529 ] + commands.walkopts + commands.commitopts,
2529 _('hg qnew [-e] [-m TEXT] [-l FILE] PATCH [FILE]...'),
2530 _('hg qnew [-e] [-m TEXT] [-l FILE] PATCH [FILE]...'),
2530 inferrepo=True)
2531 inferrepo=True)
2531 def new(ui, repo, patch, *args, **opts):
2532 def new(ui, repo, patch, *args, **opts):
2532 """create a new patch
2533 """create a new patch
2533
2534
2534 qnew creates a new patch on top of the currently-applied patch (if
2535 qnew creates a new patch on top of the currently-applied patch (if
2535 any). The patch will be initialized with any outstanding changes
2536 any). The patch will be initialized with any outstanding changes
2536 in the working directory. You may also use -I/--include,
2537 in the working directory. You may also use -I/--include,
2537 -X/--exclude, and/or a list of files after the patch name to add
2538 -X/--exclude, and/or a list of files after the patch name to add
2538 only changes to matching files to the new patch, leaving the rest
2539 only changes to matching files to the new patch, leaving the rest
2539 as uncommitted modifications.
2540 as uncommitted modifications.
2540
2541
2541 -u/--user and -d/--date can be used to set the (given) user and
2542 -u/--user and -d/--date can be used to set the (given) user and
2542 date, respectively. -U/--currentuser and -D/--currentdate set user
2543 date, respectively. -U/--currentuser and -D/--currentdate set user
2543 to current user and date to current date.
2544 to current user and date to current date.
2544
2545
2545 -e/--edit, -m/--message or -l/--logfile set the patch header as
2546 -e/--edit, -m/--message or -l/--logfile set the patch header as
2546 well as the commit message. If none is specified, the header is
2547 well as the commit message. If none is specified, the header is
2547 empty and the commit message is '[mq]: PATCH'.
2548 empty and the commit message is '[mq]: PATCH'.
2548
2549
2549 Use the -g/--git option to keep the patch in the git extended diff
2550 Use the -g/--git option to keep the patch in the git extended diff
2550 format. Read the diffs help topic for more information on why this
2551 format. Read the diffs help topic for more information on why this
2551 is important for preserving permission changes and copy/rename
2552 is important for preserving permission changes and copy/rename
2552 information.
2553 information.
2553
2554
2554 Returns 0 on successful creation of a new patch.
2555 Returns 0 on successful creation of a new patch.
2555 """
2556 """
2556 msg = cmdutil.logmessage(ui, opts)
2557 msg = cmdutil.logmessage(ui, opts)
2557 q = repo.mq
2558 q = repo.mq
2558 opts['msg'] = msg
2559 opts['msg'] = msg
2559 setupheaderopts(ui, opts)
2560 setupheaderopts(ui, opts)
2560 q.new(repo, patch, *args, **opts)
2561 q.new(repo, patch, *args, **opts)
2561 q.savedirty()
2562 q.savedirty()
2562 return 0
2563 return 0
2563
2564
2564 @command("^qrefresh",
2565 @command("^qrefresh",
2565 [('e', 'edit', None, _('invoke editor on commit messages')),
2566 [('e', 'edit', None, _('invoke editor on commit messages')),
2566 ('g', 'git', None, _('use git extended diff format')),
2567 ('g', 'git', None, _('use git extended diff format')),
2567 ('s', 'short', None,
2568 ('s', 'short', None,
2568 _('refresh only files already in the patch and specified files')),
2569 _('refresh only files already in the patch and specified files')),
2569 ('U', 'currentuser', None,
2570 ('U', 'currentuser', None,
2570 _('add/update author field in patch with current user')),
2571 _('add/update author field in patch with current user')),
2571 ('u', 'user', '',
2572 ('u', 'user', '',
2572 _('add/update author field in patch with given user'), _('USER')),
2573 _('add/update author field in patch with given user'), _('USER')),
2573 ('D', 'currentdate', None,
2574 ('D', 'currentdate', None,
2574 _('add/update date field in patch with current date')),
2575 _('add/update date field in patch with current date')),
2575 ('d', 'date', '',
2576 ('d', 'date', '',
2576 _('add/update date field in patch with given date'), _('DATE'))
2577 _('add/update date field in patch with given date'), _('DATE'))
2577 ] + commands.walkopts + commands.commitopts,
2578 ] + commands.walkopts + commands.commitopts,
2578 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...'),
2579 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...'),
2579 inferrepo=True)
2580 inferrepo=True)
2580 def refresh(ui, repo, *pats, **opts):
2581 def refresh(ui, repo, *pats, **opts):
2581 """update the current patch
2582 """update the current patch
2582
2583
2583 If any file patterns are provided, the refreshed patch will
2584 If any file patterns are provided, the refreshed patch will
2584 contain only the modifications that match those patterns; the
2585 contain only the modifications that match those patterns; the
2585 remaining modifications will remain in the working directory.
2586 remaining modifications will remain in the working directory.
2586
2587
2587 If -s/--short is specified, files currently included in the patch
2588 If -s/--short is specified, files currently included in the patch
2588 will be refreshed just like matched files and remain in the patch.
2589 will be refreshed just like matched files and remain in the patch.
2589
2590
2590 If -e/--edit is specified, Mercurial will start your configured editor for
2591 If -e/--edit is specified, Mercurial will start your configured editor for
2591 you to enter a message. In case qrefresh fails, you will find a backup of
2592 you to enter a message. In case qrefresh fails, you will find a backup of
2592 your message in ``.hg/last-message.txt``.
2593 your message in ``.hg/last-message.txt``.
2593
2594
2594 hg add/remove/copy/rename work as usual, though you might want to
2595 hg add/remove/copy/rename work as usual, though you might want to
2595 use git-style patches (-g/--git or [diff] git=1) to track copies
2596 use git-style patches (-g/--git or [diff] git=1) to track copies
2596 and renames. See the diffs help topic for more information on the
2597 and renames. See the diffs help topic for more information on the
2597 git diff format.
2598 git diff format.
2598
2599
2599 Returns 0 on success.
2600 Returns 0 on success.
2600 """
2601 """
2601 q = repo.mq
2602 q = repo.mq
2602 message = cmdutil.logmessage(ui, opts)
2603 message = cmdutil.logmessage(ui, opts)
2603 setupheaderopts(ui, opts)
2604 setupheaderopts(ui, opts)
2604 wlock = repo.wlock()
2605 wlock = repo.wlock()
2605 try:
2606 try:
2606 ret = q.refresh(repo, pats, msg=message, **opts)
2607 ret = q.refresh(repo, pats, msg=message, **opts)
2607 q.savedirty()
2608 q.savedirty()
2608 return ret
2609 return ret
2609 finally:
2610 finally:
2610 wlock.release()
2611 wlock.release()
2611
2612
2612 @command("^qdiff",
2613 @command("^qdiff",
2613 commands.diffopts + commands.diffopts2 + commands.walkopts,
2614 commands.diffopts + commands.diffopts2 + commands.walkopts,
2614 _('hg qdiff [OPTION]... [FILE]...'),
2615 _('hg qdiff [OPTION]... [FILE]...'),
2615 inferrepo=True)
2616 inferrepo=True)
2616 def diff(ui, repo, *pats, **opts):
2617 def diff(ui, repo, *pats, **opts):
2617 """diff of the current patch and subsequent modifications
2618 """diff of the current patch and subsequent modifications
2618
2619
2619 Shows a diff which includes the current patch as well as any
2620 Shows a diff which includes the current patch as well as any
2620 changes which have been made in the working directory since the
2621 changes which have been made in the working directory since the
2621 last refresh (thus showing what the current patch would become
2622 last refresh (thus showing what the current patch would become
2622 after a qrefresh).
2623 after a qrefresh).
2623
2624
2624 Use :hg:`diff` if you only want to see the changes made since the
2625 Use :hg:`diff` if you only want to see the changes made since the
2625 last qrefresh, or :hg:`export qtip` if you want to see changes
2626 last qrefresh, or :hg:`export qtip` if you want to see changes
2626 made by the current patch without including changes made since the
2627 made by the current patch without including changes made since the
2627 qrefresh.
2628 qrefresh.
2628
2629
2629 Returns 0 on success.
2630 Returns 0 on success.
2630 """
2631 """
2631 repo.mq.diff(repo, pats, opts)
2632 repo.mq.diff(repo, pats, opts)
2632 return 0
2633 return 0
2633
2634
2634 @command('qfold',
2635 @command('qfold',
2635 [('e', 'edit', None, _('invoke editor on commit messages')),
2636 [('e', 'edit', None, _('invoke editor on commit messages')),
2636 ('k', 'keep', None, _('keep folded patch files')),
2637 ('k', 'keep', None, _('keep folded patch files')),
2637 ] + commands.commitopts,
2638 ] + commands.commitopts,
2638 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...'))
2639 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...'))
2639 def fold(ui, repo, *files, **opts):
2640 def fold(ui, repo, *files, **opts):
2640 """fold the named patches into the current patch
2641 """fold the named patches into the current patch
2641
2642
2642 Patches must not yet be applied. Each patch will be successively
2643 Patches must not yet be applied. Each patch will be successively
2643 applied to the current patch in the order given. If all the
2644 applied to the current patch in the order given. If all the
2644 patches apply successfully, the current patch will be refreshed
2645 patches apply successfully, the current patch will be refreshed
2645 with the new cumulative patch, and the folded patches will be
2646 with the new cumulative patch, and the folded patches will be
2646 deleted. With -k/--keep, the folded patch files will not be
2647 deleted. With -k/--keep, the folded patch files will not be
2647 removed afterwards.
2648 removed afterwards.
2648
2649
2649 The header for each folded patch will be concatenated with the
2650 The header for each folded patch will be concatenated with the
2650 current patch header, separated by a line of ``* * *``.
2651 current patch header, separated by a line of ``* * *``.
2651
2652
2652 Returns 0 on success."""
2653 Returns 0 on success."""
2653 q = repo.mq
2654 q = repo.mq
2654 if not files:
2655 if not files:
2655 raise util.Abort(_('qfold requires at least one patch name'))
2656 raise util.Abort(_('qfold requires at least one patch name'))
2656 if not q.checktoppatch(repo)[0]:
2657 if not q.checktoppatch(repo)[0]:
2657 raise util.Abort(_('no patches applied'))
2658 raise util.Abort(_('no patches applied'))
2658 q.checklocalchanges(repo)
2659 q.checklocalchanges(repo)
2659
2660
2660 message = cmdutil.logmessage(ui, opts)
2661 message = cmdutil.logmessage(ui, opts)
2661
2662
2662 parent = q.lookup('qtip')
2663 parent = q.lookup('qtip')
2663 patches = []
2664 patches = []
2664 messages = []
2665 messages = []
2665 for f in files:
2666 for f in files:
2666 p = q.lookup(f)
2667 p = q.lookup(f)
2667 if p in patches or p == parent:
2668 if p in patches or p == parent:
2668 ui.warn(_('skipping already folded patch %s\n') % p)
2669 ui.warn(_('skipping already folded patch %s\n') % p)
2669 if q.isapplied(p):
2670 if q.isapplied(p):
2670 raise util.Abort(_('qfold cannot fold already applied patch %s')
2671 raise util.Abort(_('qfold cannot fold already applied patch %s')
2671 % p)
2672 % p)
2672 patches.append(p)
2673 patches.append(p)
2673
2674
2674 for p in patches:
2675 for p in patches:
2675 if not message:
2676 if not message:
2676 ph = patchheader(q.join(p), q.plainmode)
2677 ph = patchheader(q.join(p), q.plainmode)
2677 if ph.message:
2678 if ph.message:
2678 messages.append(ph.message)
2679 messages.append(ph.message)
2679 pf = q.join(p)
2680 pf = q.join(p)
2680 (patchsuccess, files, fuzz) = q.patch(repo, pf)
2681 (patchsuccess, files, fuzz) = q.patch(repo, pf)
2681 if not patchsuccess:
2682 if not patchsuccess:
2682 raise util.Abort(_('error folding patch %s') % p)
2683 raise util.Abort(_('error folding patch %s') % p)
2683
2684
2684 if not message:
2685 if not message:
2685 ph = patchheader(q.join(parent), q.plainmode)
2686 ph = patchheader(q.join(parent), q.plainmode)
2686 message = ph.message
2687 message = ph.message
2687 for msg in messages:
2688 for msg in messages:
2688 if msg:
2689 if msg:
2689 if message:
2690 if message:
2690 message.append('* * *')
2691 message.append('* * *')
2691 message.extend(msg)
2692 message.extend(msg)
2692 message = '\n'.join(message)
2693 message = '\n'.join(message)
2693
2694
2694 diffopts = q.patchopts(q.diffopts(), *patches)
2695 diffopts = q.patchopts(q.diffopts(), *patches)
2695 wlock = repo.wlock()
2696 wlock = repo.wlock()
2696 try:
2697 try:
2697 q.refresh(repo, msg=message, git=diffopts.git, edit=opts.get('edit'),
2698 q.refresh(repo, msg=message, git=diffopts.git, edit=opts.get('edit'),
2698 editform='mq.qfold')
2699 editform='mq.qfold')
2699 q.delete(repo, patches, opts)
2700 q.delete(repo, patches, opts)
2700 q.savedirty()
2701 q.savedirty()
2701 finally:
2702 finally:
2702 wlock.release()
2703 wlock.release()
2703
2704
2704 @command("qgoto",
2705 @command("qgoto",
2705 [('', 'keep-changes', None,
2706 [('', 'keep-changes', None,
2706 _('tolerate non-conflicting local changes')),
2707 _('tolerate non-conflicting local changes')),
2707 ('f', 'force', None, _('overwrite any local changes')),
2708 ('f', 'force', None, _('overwrite any local changes')),
2708 ('', 'no-backup', None, _('do not save backup copies of files'))],
2709 ('', 'no-backup', None, _('do not save backup copies of files'))],
2709 _('hg qgoto [OPTION]... PATCH'))
2710 _('hg qgoto [OPTION]... PATCH'))
2710 def goto(ui, repo, patch, **opts):
2711 def goto(ui, repo, patch, **opts):
2711 '''push or pop patches until named patch is at top of stack
2712 '''push or pop patches until named patch is at top of stack
2712
2713
2713 Returns 0 on success.'''
2714 Returns 0 on success.'''
2714 opts = fixkeepchangesopts(ui, opts)
2715 opts = fixkeepchangesopts(ui, opts)
2715 q = repo.mq
2716 q = repo.mq
2716 patch = q.lookup(patch)
2717 patch = q.lookup(patch)
2717 nobackup = opts.get('no_backup')
2718 nobackup = opts.get('no_backup')
2718 keepchanges = opts.get('keep_changes')
2719 keepchanges = opts.get('keep_changes')
2719 if q.isapplied(patch):
2720 if q.isapplied(patch):
2720 ret = q.pop(repo, patch, force=opts.get('force'), nobackup=nobackup,
2721 ret = q.pop(repo, patch, force=opts.get('force'), nobackup=nobackup,
2721 keepchanges=keepchanges)
2722 keepchanges=keepchanges)
2722 else:
2723 else:
2723 ret = q.push(repo, patch, force=opts.get('force'), nobackup=nobackup,
2724 ret = q.push(repo, patch, force=opts.get('force'), nobackup=nobackup,
2724 keepchanges=keepchanges)
2725 keepchanges=keepchanges)
2725 q.savedirty()
2726 q.savedirty()
2726 return ret
2727 return ret
2727
2728
2728 @command("qguard",
2729 @command("qguard",
2729 [('l', 'list', None, _('list all patches and guards')),
2730 [('l', 'list', None, _('list all patches and guards')),
2730 ('n', 'none', None, _('drop all guards'))],
2731 ('n', 'none', None, _('drop all guards'))],
2731 _('hg qguard [-l] [-n] [PATCH] [-- [+GUARD]... [-GUARD]...]'))
2732 _('hg qguard [-l] [-n] [PATCH] [-- [+GUARD]... [-GUARD]...]'))
2732 def guard(ui, repo, *args, **opts):
2733 def guard(ui, repo, *args, **opts):
2733 '''set or print guards for a patch
2734 '''set or print guards for a patch
2734
2735
2735 Guards control whether a patch can be pushed. A patch with no
2736 Guards control whether a patch can be pushed. A patch with no
2736 guards is always pushed. A patch with a positive guard ("+foo") is
2737 guards is always pushed. A patch with a positive guard ("+foo") is
2737 pushed only if the :hg:`qselect` command has activated it. A patch with
2738 pushed only if the :hg:`qselect` command has activated it. A patch with
2738 a negative guard ("-foo") is never pushed if the :hg:`qselect` command
2739 a negative guard ("-foo") is never pushed if the :hg:`qselect` command
2739 has activated it.
2740 has activated it.
2740
2741
2741 With no arguments, print the currently active guards.
2742 With no arguments, print the currently active guards.
2742 With arguments, set guards for the named patch.
2743 With arguments, set guards for the named patch.
2743
2744
2744 .. note::
2745 .. note::
2745
2746
2746 Specifying negative guards now requires '--'.
2747 Specifying negative guards now requires '--'.
2747
2748
2748 To set guards on another patch::
2749 To set guards on another patch::
2749
2750
2750 hg qguard other.patch -- +2.6.17 -stable
2751 hg qguard other.patch -- +2.6.17 -stable
2751
2752
2752 Returns 0 on success.
2753 Returns 0 on success.
2753 '''
2754 '''
2754 def status(idx):
2755 def status(idx):
2755 guards = q.seriesguards[idx] or ['unguarded']
2756 guards = q.seriesguards[idx] or ['unguarded']
2756 if q.series[idx] in applied:
2757 if q.series[idx] in applied:
2757 state = 'applied'
2758 state = 'applied'
2758 elif q.pushable(idx)[0]:
2759 elif q.pushable(idx)[0]:
2759 state = 'unapplied'
2760 state = 'unapplied'
2760 else:
2761 else:
2761 state = 'guarded'
2762 state = 'guarded'
2762 label = 'qguard.patch qguard.%s qseries.%s' % (state, state)
2763 label = 'qguard.patch qguard.%s qseries.%s' % (state, state)
2763 ui.write('%s: ' % ui.label(q.series[idx], label))
2764 ui.write('%s: ' % ui.label(q.series[idx], label))
2764
2765
2765 for i, guard in enumerate(guards):
2766 for i, guard in enumerate(guards):
2766 if guard.startswith('+'):
2767 if guard.startswith('+'):
2767 ui.write(guard, label='qguard.positive')
2768 ui.write(guard, label='qguard.positive')
2768 elif guard.startswith('-'):
2769 elif guard.startswith('-'):
2769 ui.write(guard, label='qguard.negative')
2770 ui.write(guard, label='qguard.negative')
2770 else:
2771 else:
2771 ui.write(guard, label='qguard.unguarded')
2772 ui.write(guard, label='qguard.unguarded')
2772 if i != len(guards) - 1:
2773 if i != len(guards) - 1:
2773 ui.write(' ')
2774 ui.write(' ')
2774 ui.write('\n')
2775 ui.write('\n')
2775 q = repo.mq
2776 q = repo.mq
2776 applied = set(p.name for p in q.applied)
2777 applied = set(p.name for p in q.applied)
2777 patch = None
2778 patch = None
2778 args = list(args)
2779 args = list(args)
2779 if opts.get('list'):
2780 if opts.get('list'):
2780 if args or opts.get('none'):
2781 if args or opts.get('none'):
2781 raise util.Abort(_('cannot mix -l/--list with options or '
2782 raise util.Abort(_('cannot mix -l/--list with options or '
2782 'arguments'))
2783 'arguments'))
2783 for i in xrange(len(q.series)):
2784 for i in xrange(len(q.series)):
2784 status(i)
2785 status(i)
2785 return
2786 return
2786 if not args or args[0][0:1] in '-+':
2787 if not args or args[0][0:1] in '-+':
2787 if not q.applied:
2788 if not q.applied:
2788 raise util.Abort(_('no patches applied'))
2789 raise util.Abort(_('no patches applied'))
2789 patch = q.applied[-1].name
2790 patch = q.applied[-1].name
2790 if patch is None and args[0][0:1] not in '-+':
2791 if patch is None and args[0][0:1] not in '-+':
2791 patch = args.pop(0)
2792 patch = args.pop(0)
2792 if patch is None:
2793 if patch is None:
2793 raise util.Abort(_('no patch to work with'))
2794 raise util.Abort(_('no patch to work with'))
2794 if args or opts.get('none'):
2795 if args or opts.get('none'):
2795 idx = q.findseries(patch)
2796 idx = q.findseries(patch)
2796 if idx is None:
2797 if idx is None:
2797 raise util.Abort(_('no patch named %s') % patch)
2798 raise util.Abort(_('no patch named %s') % patch)
2798 q.setguards(idx, args)
2799 q.setguards(idx, args)
2799 q.savedirty()
2800 q.savedirty()
2800 else:
2801 else:
2801 status(q.series.index(q.lookup(patch)))
2802 status(q.series.index(q.lookup(patch)))
2802
2803
2803 @command("qheader", [], _('hg qheader [PATCH]'))
2804 @command("qheader", [], _('hg qheader [PATCH]'))
2804 def header(ui, repo, patch=None):
2805 def header(ui, repo, patch=None):
2805 """print the header of the topmost or specified patch
2806 """print the header of the topmost or specified patch
2806
2807
2807 Returns 0 on success."""
2808 Returns 0 on success."""
2808 q = repo.mq
2809 q = repo.mq
2809
2810
2810 if patch:
2811 if patch:
2811 patch = q.lookup(patch)
2812 patch = q.lookup(patch)
2812 else:
2813 else:
2813 if not q.applied:
2814 if not q.applied:
2814 ui.write(_('no patches applied\n'))
2815 ui.write(_('no patches applied\n'))
2815 return 1
2816 return 1
2816 patch = q.lookup('qtip')
2817 patch = q.lookup('qtip')
2817 ph = patchheader(q.join(patch), q.plainmode)
2818 ph = patchheader(q.join(patch), q.plainmode)
2818
2819
2819 ui.write('\n'.join(ph.message) + '\n')
2820 ui.write('\n'.join(ph.message) + '\n')
2820
2821
2821 def lastsavename(path):
2822 def lastsavename(path):
2822 (directory, base) = os.path.split(path)
2823 (directory, base) = os.path.split(path)
2823 names = os.listdir(directory)
2824 names = os.listdir(directory)
2824 namere = re.compile("%s.([0-9]+)" % base)
2825 namere = re.compile("%s.([0-9]+)" % base)
2825 maxindex = None
2826 maxindex = None
2826 maxname = None
2827 maxname = None
2827 for f in names:
2828 for f in names:
2828 m = namere.match(f)
2829 m = namere.match(f)
2829 if m:
2830 if m:
2830 index = int(m.group(1))
2831 index = int(m.group(1))
2831 if maxindex is None or index > maxindex:
2832 if maxindex is None or index > maxindex:
2832 maxindex = index
2833 maxindex = index
2833 maxname = f
2834 maxname = f
2834 if maxname:
2835 if maxname:
2835 return (os.path.join(directory, maxname), maxindex)
2836 return (os.path.join(directory, maxname), maxindex)
2836 return (None, None)
2837 return (None, None)
2837
2838
2838 def savename(path):
2839 def savename(path):
2839 (last, index) = lastsavename(path)
2840 (last, index) = lastsavename(path)
2840 if last is None:
2841 if last is None:
2841 index = 0
2842 index = 0
2842 newpath = path + ".%d" % (index + 1)
2843 newpath = path + ".%d" % (index + 1)
2843 return newpath
2844 return newpath
2844
2845
2845 @command("^qpush",
2846 @command("^qpush",
2846 [('', 'keep-changes', None,
2847 [('', 'keep-changes', None,
2847 _('tolerate non-conflicting local changes')),
2848 _('tolerate non-conflicting local changes')),
2848 ('f', 'force', None, _('apply on top of local changes')),
2849 ('f', 'force', None, _('apply on top of local changes')),
2849 ('e', 'exact', None,
2850 ('e', 'exact', None,
2850 _('apply the target patch to its recorded parent')),
2851 _('apply the target patch to its recorded parent')),
2851 ('l', 'list', None, _('list patch name in commit text')),
2852 ('l', 'list', None, _('list patch name in commit text')),
2852 ('a', 'all', None, _('apply all patches')),
2853 ('a', 'all', None, _('apply all patches')),
2853 ('m', 'merge', None, _('merge from another queue (DEPRECATED)')),
2854 ('m', 'merge', None, _('merge from another queue (DEPRECATED)')),
2854 ('n', 'name', '',
2855 ('n', 'name', '',
2855 _('merge queue name (DEPRECATED)'), _('NAME')),
2856 _('merge queue name (DEPRECATED)'), _('NAME')),
2856 ('', 'move', None,
2857 ('', 'move', None,
2857 _('reorder patch series and apply only the patch')),
2858 _('reorder patch series and apply only the patch')),
2858 ('', 'no-backup', None, _('do not save backup copies of files'))],
2859 ('', 'no-backup', None, _('do not save backup copies of files'))],
2859 _('hg qpush [-f] [-l] [-a] [--move] [PATCH | INDEX]'))
2860 _('hg qpush [-f] [-l] [-a] [--move] [PATCH | INDEX]'))
2860 def push(ui, repo, patch=None, **opts):
2861 def push(ui, repo, patch=None, **opts):
2861 """push the next patch onto the stack
2862 """push the next patch onto the stack
2862
2863
2863 By default, abort if the working directory contains uncommitted
2864 By default, abort if the working directory contains uncommitted
2864 changes. With --keep-changes, abort only if the uncommitted files
2865 changes. With --keep-changes, abort only if the uncommitted files
2865 overlap with patched files. With -f/--force, backup and patch over
2866 overlap with patched files. With -f/--force, backup and patch over
2866 uncommitted changes.
2867 uncommitted changes.
2867
2868
2868 Return 0 on success.
2869 Return 0 on success.
2869 """
2870 """
2870 q = repo.mq
2871 q = repo.mq
2871 mergeq = None
2872 mergeq = None
2872
2873
2873 opts = fixkeepchangesopts(ui, opts)
2874 opts = fixkeepchangesopts(ui, opts)
2874 if opts.get('merge'):
2875 if opts.get('merge'):
2875 if opts.get('name'):
2876 if opts.get('name'):
2876 newpath = repo.join(opts.get('name'))
2877 newpath = repo.join(opts.get('name'))
2877 else:
2878 else:
2878 newpath, i = lastsavename(q.path)
2879 newpath, i = lastsavename(q.path)
2879 if not newpath:
2880 if not newpath:
2880 ui.warn(_("no saved queues found, please use -n\n"))
2881 ui.warn(_("no saved queues found, please use -n\n"))
2881 return 1
2882 return 1
2882 mergeq = queue(ui, repo.baseui, repo.path, newpath)
2883 mergeq = queue(ui, repo.baseui, repo.path, newpath)
2883 ui.warn(_("merging with queue at: %s\n") % mergeq.path)
2884 ui.warn(_("merging with queue at: %s\n") % mergeq.path)
2884 ret = q.push(repo, patch, force=opts.get('force'), list=opts.get('list'),
2885 ret = q.push(repo, patch, force=opts.get('force'), list=opts.get('list'),
2885 mergeq=mergeq, all=opts.get('all'), move=opts.get('move'),
2886 mergeq=mergeq, all=opts.get('all'), move=opts.get('move'),
2886 exact=opts.get('exact'), nobackup=opts.get('no_backup'),
2887 exact=opts.get('exact'), nobackup=opts.get('no_backup'),
2887 keepchanges=opts.get('keep_changes'))
2888 keepchanges=opts.get('keep_changes'))
2888 return ret
2889 return ret
2889
2890
2890 @command("^qpop",
2891 @command("^qpop",
2891 [('a', 'all', None, _('pop all patches')),
2892 [('a', 'all', None, _('pop all patches')),
2892 ('n', 'name', '',
2893 ('n', 'name', '',
2893 _('queue name to pop (DEPRECATED)'), _('NAME')),
2894 _('queue name to pop (DEPRECATED)'), _('NAME')),
2894 ('', 'keep-changes', None,
2895 ('', 'keep-changes', None,
2895 _('tolerate non-conflicting local changes')),
2896 _('tolerate non-conflicting local changes')),
2896 ('f', 'force', None, _('forget any local changes to patched files')),
2897 ('f', 'force', None, _('forget any local changes to patched files')),
2897 ('', 'no-backup', None, _('do not save backup copies of files'))],
2898 ('', 'no-backup', None, _('do not save backup copies of files'))],
2898 _('hg qpop [-a] [-f] [PATCH | INDEX]'))
2899 _('hg qpop [-a] [-f] [PATCH | INDEX]'))
2899 def pop(ui, repo, patch=None, **opts):
2900 def pop(ui, repo, patch=None, **opts):
2900 """pop the current patch off the stack
2901 """pop the current patch off the stack
2901
2902
2902 Without argument, pops off the top of the patch stack. If given a
2903 Without argument, pops off the top of the patch stack. If given a
2903 patch name, keeps popping off patches until the named patch is at
2904 patch name, keeps popping off patches until the named patch is at
2904 the top of the stack.
2905 the top of the stack.
2905
2906
2906 By default, abort if the working directory contains uncommitted
2907 By default, abort if the working directory contains uncommitted
2907 changes. With --keep-changes, abort only if the uncommitted files
2908 changes. With --keep-changes, abort only if the uncommitted files
2908 overlap with patched files. With -f/--force, backup and discard
2909 overlap with patched files. With -f/--force, backup and discard
2909 changes made to such files.
2910 changes made to such files.
2910
2911
2911 Return 0 on success.
2912 Return 0 on success.
2912 """
2913 """
2913 opts = fixkeepchangesopts(ui, opts)
2914 opts = fixkeepchangesopts(ui, opts)
2914 localupdate = True
2915 localupdate = True
2915 if opts.get('name'):
2916 if opts.get('name'):
2916 q = queue(ui, repo.baseui, repo.path, repo.join(opts.get('name')))
2917 q = queue(ui, repo.baseui, repo.path, repo.join(opts.get('name')))
2917 ui.warn(_('using patch queue: %s\n') % q.path)
2918 ui.warn(_('using patch queue: %s\n') % q.path)
2918 localupdate = False
2919 localupdate = False
2919 else:
2920 else:
2920 q = repo.mq
2921 q = repo.mq
2921 ret = q.pop(repo, patch, force=opts.get('force'), update=localupdate,
2922 ret = q.pop(repo, patch, force=opts.get('force'), update=localupdate,
2922 all=opts.get('all'), nobackup=opts.get('no_backup'),
2923 all=opts.get('all'), nobackup=opts.get('no_backup'),
2923 keepchanges=opts.get('keep_changes'))
2924 keepchanges=opts.get('keep_changes'))
2924 q.savedirty()
2925 q.savedirty()
2925 return ret
2926 return ret
2926
2927
2927 @command("qrename|qmv", [], _('hg qrename PATCH1 [PATCH2]'))
2928 @command("qrename|qmv", [], _('hg qrename PATCH1 [PATCH2]'))
2928 def rename(ui, repo, patch, name=None, **opts):
2929 def rename(ui, repo, patch, name=None, **opts):
2929 """rename a patch
2930 """rename a patch
2930
2931
2931 With one argument, renames the current patch to PATCH1.
2932 With one argument, renames the current patch to PATCH1.
2932 With two arguments, renames PATCH1 to PATCH2.
2933 With two arguments, renames PATCH1 to PATCH2.
2933
2934
2934 Returns 0 on success."""
2935 Returns 0 on success."""
2935 q = repo.mq
2936 q = repo.mq
2936 if not name:
2937 if not name:
2937 name = patch
2938 name = patch
2938 patch = None
2939 patch = None
2939
2940
2940 if patch:
2941 if patch:
2941 patch = q.lookup(patch)
2942 patch = q.lookup(patch)
2942 else:
2943 else:
2943 if not q.applied:
2944 if not q.applied:
2944 ui.write(_('no patches applied\n'))
2945 ui.write(_('no patches applied\n'))
2945 return
2946 return
2946 patch = q.lookup('qtip')
2947 patch = q.lookup('qtip')
2947 absdest = q.join(name)
2948 absdest = q.join(name)
2948 if os.path.isdir(absdest):
2949 if os.path.isdir(absdest):
2949 name = normname(os.path.join(name, os.path.basename(patch)))
2950 name = normname(os.path.join(name, os.path.basename(patch)))
2950 absdest = q.join(name)
2951 absdest = q.join(name)
2951 q.checkpatchname(name)
2952 q.checkpatchname(name)
2952
2953
2953 ui.note(_('renaming %s to %s\n') % (patch, name))
2954 ui.note(_('renaming %s to %s\n') % (patch, name))
2954 i = q.findseries(patch)
2955 i = q.findseries(patch)
2955 guards = q.guard_re.findall(q.fullseries[i])
2956 guards = q.guard_re.findall(q.fullseries[i])
2956 q.fullseries[i] = name + ''.join([' #' + g for g in guards])
2957 q.fullseries[i] = name + ''.join([' #' + g for g in guards])
2957 q.parseseries()
2958 q.parseseries()
2958 q.seriesdirty = True
2959 q.seriesdirty = True
2959
2960
2960 info = q.isapplied(patch)
2961 info = q.isapplied(patch)
2961 if info:
2962 if info:
2962 q.applied[info[0]] = statusentry(info[1], name)
2963 q.applied[info[0]] = statusentry(info[1], name)
2963 q.applieddirty = True
2964 q.applieddirty = True
2964
2965
2965 destdir = os.path.dirname(absdest)
2966 destdir = os.path.dirname(absdest)
2966 if not os.path.isdir(destdir):
2967 if not os.path.isdir(destdir):
2967 os.makedirs(destdir)
2968 os.makedirs(destdir)
2968 util.rename(q.join(patch), absdest)
2969 util.rename(q.join(patch), absdest)
2969 r = q.qrepo()
2970 r = q.qrepo()
2970 if r and patch in r.dirstate:
2971 if r and patch in r.dirstate:
2971 wctx = r[None]
2972 wctx = r[None]
2972 wlock = r.wlock()
2973 wlock = r.wlock()
2973 try:
2974 try:
2974 if r.dirstate[patch] == 'a':
2975 if r.dirstate[patch] == 'a':
2975 r.dirstate.drop(patch)
2976 r.dirstate.drop(patch)
2976 r.dirstate.add(name)
2977 r.dirstate.add(name)
2977 else:
2978 else:
2978 wctx.copy(patch, name)
2979 wctx.copy(patch, name)
2979 wctx.forget([patch])
2980 wctx.forget([patch])
2980 finally:
2981 finally:
2981 wlock.release()
2982 wlock.release()
2982
2983
2983 q.savedirty()
2984 q.savedirty()
2984
2985
2985 @command("qrestore",
2986 @command("qrestore",
2986 [('d', 'delete', None, _('delete save entry')),
2987 [('d', 'delete', None, _('delete save entry')),
2987 ('u', 'update', None, _('update queue working directory'))],
2988 ('u', 'update', None, _('update queue working directory'))],
2988 _('hg qrestore [-d] [-u] REV'))
2989 _('hg qrestore [-d] [-u] REV'))
2989 def restore(ui, repo, rev, **opts):
2990 def restore(ui, repo, rev, **opts):
2990 """restore the queue state saved by a revision (DEPRECATED)
2991 """restore the queue state saved by a revision (DEPRECATED)
2991
2992
2992 This command is deprecated, use :hg:`rebase` instead."""
2993 This command is deprecated, use :hg:`rebase` instead."""
2993 rev = repo.lookup(rev)
2994 rev = repo.lookup(rev)
2994 q = repo.mq
2995 q = repo.mq
2995 q.restore(repo, rev, delete=opts.get('delete'),
2996 q.restore(repo, rev, delete=opts.get('delete'),
2996 qupdate=opts.get('update'))
2997 qupdate=opts.get('update'))
2997 q.savedirty()
2998 q.savedirty()
2998 return 0
2999 return 0
2999
3000
3000 @command("qsave",
3001 @command("qsave",
3001 [('c', 'copy', None, _('copy patch directory')),
3002 [('c', 'copy', None, _('copy patch directory')),
3002 ('n', 'name', '',
3003 ('n', 'name', '',
3003 _('copy directory name'), _('NAME')),
3004 _('copy directory name'), _('NAME')),
3004 ('e', 'empty', None, _('clear queue status file')),
3005 ('e', 'empty', None, _('clear queue status file')),
3005 ('f', 'force', None, _('force copy'))] + commands.commitopts,
3006 ('f', 'force', None, _('force copy'))] + commands.commitopts,
3006 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'))
3007 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'))
3007 def save(ui, repo, **opts):
3008 def save(ui, repo, **opts):
3008 """save current queue state (DEPRECATED)
3009 """save current queue state (DEPRECATED)
3009
3010
3010 This command is deprecated, use :hg:`rebase` instead."""
3011 This command is deprecated, use :hg:`rebase` instead."""
3011 q = repo.mq
3012 q = repo.mq
3012 message = cmdutil.logmessage(ui, opts)
3013 message = cmdutil.logmessage(ui, opts)
3013 ret = q.save(repo, msg=message)
3014 ret = q.save(repo, msg=message)
3014 if ret:
3015 if ret:
3015 return ret
3016 return ret
3016 q.savedirty() # save to .hg/patches before copying
3017 q.savedirty() # save to .hg/patches before copying
3017 if opts.get('copy'):
3018 if opts.get('copy'):
3018 path = q.path
3019 path = q.path
3019 if opts.get('name'):
3020 if opts.get('name'):
3020 newpath = os.path.join(q.basepath, opts.get('name'))
3021 newpath = os.path.join(q.basepath, opts.get('name'))
3021 if os.path.exists(newpath):
3022 if os.path.exists(newpath):
3022 if not os.path.isdir(newpath):
3023 if not os.path.isdir(newpath):
3023 raise util.Abort(_('destination %s exists and is not '
3024 raise util.Abort(_('destination %s exists and is not '
3024 'a directory') % newpath)
3025 'a directory') % newpath)
3025 if not opts.get('force'):
3026 if not opts.get('force'):
3026 raise util.Abort(_('destination %s exists, '
3027 raise util.Abort(_('destination %s exists, '
3027 'use -f to force') % newpath)
3028 'use -f to force') % newpath)
3028 else:
3029 else:
3029 newpath = savename(path)
3030 newpath = savename(path)
3030 ui.warn(_("copy %s to %s\n") % (path, newpath))
3031 ui.warn(_("copy %s to %s\n") % (path, newpath))
3031 util.copyfiles(path, newpath)
3032 util.copyfiles(path, newpath)
3032 if opts.get('empty'):
3033 if opts.get('empty'):
3033 del q.applied[:]
3034 del q.applied[:]
3034 q.applieddirty = True
3035 q.applieddirty = True
3035 q.savedirty()
3036 q.savedirty()
3036 return 0
3037 return 0
3037
3038
3038
3039
3039 @command("qselect",
3040 @command("qselect",
3040 [('n', 'none', None, _('disable all guards')),
3041 [('n', 'none', None, _('disable all guards')),
3041 ('s', 'series', None, _('list all guards in series file')),
3042 ('s', 'series', None, _('list all guards in series file')),
3042 ('', 'pop', None, _('pop to before first guarded applied patch')),
3043 ('', 'pop', None, _('pop to before first guarded applied patch')),
3043 ('', 'reapply', None, _('pop, then reapply patches'))],
3044 ('', 'reapply', None, _('pop, then reapply patches'))],
3044 _('hg qselect [OPTION]... [GUARD]...'))
3045 _('hg qselect [OPTION]... [GUARD]...'))
3045 def select(ui, repo, *args, **opts):
3046 def select(ui, repo, *args, **opts):
3046 '''set or print guarded patches to push
3047 '''set or print guarded patches to push
3047
3048
3048 Use the :hg:`qguard` command to set or print guards on patch, then use
3049 Use the :hg:`qguard` command to set or print guards on patch, then use
3049 qselect to tell mq which guards to use. A patch will be pushed if
3050 qselect to tell mq which guards to use. A patch will be pushed if
3050 it has no guards or any positive guards match the currently
3051 it has no guards or any positive guards match the currently
3051 selected guard, but will not be pushed if any negative guards
3052 selected guard, but will not be pushed if any negative guards
3052 match the current guard. For example::
3053 match the current guard. For example::
3053
3054
3054 qguard foo.patch -- -stable (negative guard)
3055 qguard foo.patch -- -stable (negative guard)
3055 qguard bar.patch +stable (positive guard)
3056 qguard bar.patch +stable (positive guard)
3056 qselect stable
3057 qselect stable
3057
3058
3058 This activates the "stable" guard. mq will skip foo.patch (because
3059 This activates the "stable" guard. mq will skip foo.patch (because
3059 it has a negative match) but push bar.patch (because it has a
3060 it has a negative match) but push bar.patch (because it has a
3060 positive match).
3061 positive match).
3061
3062
3062 With no arguments, prints the currently active guards.
3063 With no arguments, prints the currently active guards.
3063 With one argument, sets the active guard.
3064 With one argument, sets the active guard.
3064
3065
3065 Use -n/--none to deactivate guards (no other arguments needed).
3066 Use -n/--none to deactivate guards (no other arguments needed).
3066 When no guards are active, patches with positive guards are
3067 When no guards are active, patches with positive guards are
3067 skipped and patches with negative guards are pushed.
3068 skipped and patches with negative guards are pushed.
3068
3069
3069 qselect can change the guards on applied patches. It does not pop
3070 qselect can change the guards on applied patches. It does not pop
3070 guarded patches by default. Use --pop to pop back to the last
3071 guarded patches by default. Use --pop to pop back to the last
3071 applied patch that is not guarded. Use --reapply (which implies
3072 applied patch that is not guarded. Use --reapply (which implies
3072 --pop) to push back to the current patch afterwards, but skip
3073 --pop) to push back to the current patch afterwards, but skip
3073 guarded patches.
3074 guarded patches.
3074
3075
3075 Use -s/--series to print a list of all guards in the series file
3076 Use -s/--series to print a list of all guards in the series file
3076 (no other arguments needed). Use -v for more information.
3077 (no other arguments needed). Use -v for more information.
3077
3078
3078 Returns 0 on success.'''
3079 Returns 0 on success.'''
3079
3080
3080 q = repo.mq
3081 q = repo.mq
3081 guards = q.active()
3082 guards = q.active()
3082 pushable = lambda i: q.pushable(q.applied[i].name)[0]
3083 pushable = lambda i: q.pushable(q.applied[i].name)[0]
3083 if args or opts.get('none'):
3084 if args or opts.get('none'):
3084 old_unapplied = q.unapplied(repo)
3085 old_unapplied = q.unapplied(repo)
3085 old_guarded = [i for i in xrange(len(q.applied)) if not pushable(i)]
3086 old_guarded = [i for i in xrange(len(q.applied)) if not pushable(i)]
3086 q.setactive(args)
3087 q.setactive(args)
3087 q.savedirty()
3088 q.savedirty()
3088 if not args:
3089 if not args:
3089 ui.status(_('guards deactivated\n'))
3090 ui.status(_('guards deactivated\n'))
3090 if not opts.get('pop') and not opts.get('reapply'):
3091 if not opts.get('pop') and not opts.get('reapply'):
3091 unapplied = q.unapplied(repo)
3092 unapplied = q.unapplied(repo)
3092 guarded = [i for i in xrange(len(q.applied)) if not pushable(i)]
3093 guarded = [i for i in xrange(len(q.applied)) if not pushable(i)]
3093 if len(unapplied) != len(old_unapplied):
3094 if len(unapplied) != len(old_unapplied):
3094 ui.status(_('number of unguarded, unapplied patches has '
3095 ui.status(_('number of unguarded, unapplied patches has '
3095 'changed from %d to %d\n') %
3096 'changed from %d to %d\n') %
3096 (len(old_unapplied), len(unapplied)))
3097 (len(old_unapplied), len(unapplied)))
3097 if len(guarded) != len(old_guarded):
3098 if len(guarded) != len(old_guarded):
3098 ui.status(_('number of guarded, applied patches has changed '
3099 ui.status(_('number of guarded, applied patches has changed '
3099 'from %d to %d\n') %
3100 'from %d to %d\n') %
3100 (len(old_guarded), len(guarded)))
3101 (len(old_guarded), len(guarded)))
3101 elif opts.get('series'):
3102 elif opts.get('series'):
3102 guards = {}
3103 guards = {}
3103 noguards = 0
3104 noguards = 0
3104 for gs in q.seriesguards:
3105 for gs in q.seriesguards:
3105 if not gs:
3106 if not gs:
3106 noguards += 1
3107 noguards += 1
3107 for g in gs:
3108 for g in gs:
3108 guards.setdefault(g, 0)
3109 guards.setdefault(g, 0)
3109 guards[g] += 1
3110 guards[g] += 1
3110 if ui.verbose:
3111 if ui.verbose:
3111 guards['NONE'] = noguards
3112 guards['NONE'] = noguards
3112 guards = guards.items()
3113 guards = guards.items()
3113 guards.sort(key=lambda x: x[0][1:])
3114 guards.sort(key=lambda x: x[0][1:])
3114 if guards:
3115 if guards:
3115 ui.note(_('guards in series file:\n'))
3116 ui.note(_('guards in series file:\n'))
3116 for guard, count in guards:
3117 for guard, count in guards:
3117 ui.note('%2d ' % count)
3118 ui.note('%2d ' % count)
3118 ui.write(guard, '\n')
3119 ui.write(guard, '\n')
3119 else:
3120 else:
3120 ui.note(_('no guards in series file\n'))
3121 ui.note(_('no guards in series file\n'))
3121 else:
3122 else:
3122 if guards:
3123 if guards:
3123 ui.note(_('active guards:\n'))
3124 ui.note(_('active guards:\n'))
3124 for g in guards:
3125 for g in guards:
3125 ui.write(g, '\n')
3126 ui.write(g, '\n')
3126 else:
3127 else:
3127 ui.write(_('no active guards\n'))
3128 ui.write(_('no active guards\n'))
3128 reapply = opts.get('reapply') and q.applied and q.applied[-1].name
3129 reapply = opts.get('reapply') and q.applied and q.applied[-1].name
3129 popped = False
3130 popped = False
3130 if opts.get('pop') or opts.get('reapply'):
3131 if opts.get('pop') or opts.get('reapply'):
3131 for i in xrange(len(q.applied)):
3132 for i in xrange(len(q.applied)):
3132 if not pushable(i):
3133 if not pushable(i):
3133 ui.status(_('popping guarded patches\n'))
3134 ui.status(_('popping guarded patches\n'))
3134 popped = True
3135 popped = True
3135 if i == 0:
3136 if i == 0:
3136 q.pop(repo, all=True)
3137 q.pop(repo, all=True)
3137 else:
3138 else:
3138 q.pop(repo, q.applied[i - 1].name)
3139 q.pop(repo, q.applied[i - 1].name)
3139 break
3140 break
3140 if popped:
3141 if popped:
3141 try:
3142 try:
3142 if reapply:
3143 if reapply:
3143 ui.status(_('reapplying unguarded patches\n'))
3144 ui.status(_('reapplying unguarded patches\n'))
3144 q.push(repo, reapply)
3145 q.push(repo, reapply)
3145 finally:
3146 finally:
3146 q.savedirty()
3147 q.savedirty()
3147
3148
3148 @command("qfinish",
3149 @command("qfinish",
3149 [('a', 'applied', None, _('finish all applied changesets'))],
3150 [('a', 'applied', None, _('finish all applied changesets'))],
3150 _('hg qfinish [-a] [REV]...'))
3151 _('hg qfinish [-a] [REV]...'))
3151 def finish(ui, repo, *revrange, **opts):
3152 def finish(ui, repo, *revrange, **opts):
3152 """move applied patches into repository history
3153 """move applied patches into repository history
3153
3154
3154 Finishes the specified revisions (corresponding to applied
3155 Finishes the specified revisions (corresponding to applied
3155 patches) by moving them out of mq control into regular repository
3156 patches) by moving them out of mq control into regular repository
3156 history.
3157 history.
3157
3158
3158 Accepts a revision range or the -a/--applied option. If --applied
3159 Accepts a revision range or the -a/--applied option. If --applied
3159 is specified, all applied mq revisions are removed from mq
3160 is specified, all applied mq revisions are removed from mq
3160 control. Otherwise, the given revisions must be at the base of the
3161 control. Otherwise, the given revisions must be at the base of the
3161 stack of applied patches.
3162 stack of applied patches.
3162
3163
3163 This can be especially useful if your changes have been applied to
3164 This can be especially useful if your changes have been applied to
3164 an upstream repository, or if you are about to push your changes
3165 an upstream repository, or if you are about to push your changes
3165 to upstream.
3166 to upstream.
3166
3167
3167 Returns 0 on success.
3168 Returns 0 on success.
3168 """
3169 """
3169 if not opts.get('applied') and not revrange:
3170 if not opts.get('applied') and not revrange:
3170 raise util.Abort(_('no revisions specified'))
3171 raise util.Abort(_('no revisions specified'))
3171 elif opts.get('applied'):
3172 elif opts.get('applied'):
3172 revrange = ('qbase::qtip',) + revrange
3173 revrange = ('qbase::qtip',) + revrange
3173
3174
3174 q = repo.mq
3175 q = repo.mq
3175 if not q.applied:
3176 if not q.applied:
3176 ui.status(_('no patches applied\n'))
3177 ui.status(_('no patches applied\n'))
3177 return 0
3178 return 0
3178
3179
3179 revs = scmutil.revrange(repo, revrange)
3180 revs = scmutil.revrange(repo, revrange)
3180 if repo['.'].rev() in revs and repo[None].files():
3181 if repo['.'].rev() in revs and repo[None].files():
3181 ui.warn(_('warning: uncommitted changes in the working directory\n'))
3182 ui.warn(_('warning: uncommitted changes in the working directory\n'))
3182 # queue.finish may changes phases but leave the responsibility to lock the
3183 # queue.finish may changes phases but leave the responsibility to lock the
3183 # repo to the caller to avoid deadlock with wlock. This command code is
3184 # repo to the caller to avoid deadlock with wlock. This command code is
3184 # responsibility for this locking.
3185 # responsibility for this locking.
3185 lock = repo.lock()
3186 lock = repo.lock()
3186 try:
3187 try:
3187 q.finish(repo, revs)
3188 q.finish(repo, revs)
3188 q.savedirty()
3189 q.savedirty()
3189 finally:
3190 finally:
3190 lock.release()
3191 lock.release()
3191 return 0
3192 return 0
3192
3193
3193 @command("qqueue",
3194 @command("qqueue",
3194 [('l', 'list', False, _('list all available queues')),
3195 [('l', 'list', False, _('list all available queues')),
3195 ('', 'active', False, _('print name of active queue')),
3196 ('', 'active', False, _('print name of active queue')),
3196 ('c', 'create', False, _('create new queue')),
3197 ('c', 'create', False, _('create new queue')),
3197 ('', 'rename', False, _('rename active queue')),
3198 ('', 'rename', False, _('rename active queue')),
3198 ('', 'delete', False, _('delete reference to queue')),
3199 ('', 'delete', False, _('delete reference to queue')),
3199 ('', 'purge', False, _('delete queue, and remove patch dir')),
3200 ('', 'purge', False, _('delete queue, and remove patch dir')),
3200 ],
3201 ],
3201 _('[OPTION] [QUEUE]'))
3202 _('[OPTION] [QUEUE]'))
3202 def qqueue(ui, repo, name=None, **opts):
3203 def qqueue(ui, repo, name=None, **opts):
3203 '''manage multiple patch queues
3204 '''manage multiple patch queues
3204
3205
3205 Supports switching between different patch queues, as well as creating
3206 Supports switching between different patch queues, as well as creating
3206 new patch queues and deleting existing ones.
3207 new patch queues and deleting existing ones.
3207
3208
3208 Omitting a queue name or specifying -l/--list will show you the registered
3209 Omitting a queue name or specifying -l/--list will show you the registered
3209 queues - by default the "normal" patches queue is registered. The currently
3210 queues - by default the "normal" patches queue is registered. The currently
3210 active queue will be marked with "(active)". Specifying --active will print
3211 active queue will be marked with "(active)". Specifying --active will print
3211 only the name of the active queue.
3212 only the name of the active queue.
3212
3213
3213 To create a new queue, use -c/--create. The queue is automatically made
3214 To create a new queue, use -c/--create. The queue is automatically made
3214 active, except in the case where there are applied patches from the
3215 active, except in the case where there are applied patches from the
3215 currently active queue in the repository. Then the queue will only be
3216 currently active queue in the repository. Then the queue will only be
3216 created and switching will fail.
3217 created and switching will fail.
3217
3218
3218 To delete an existing queue, use --delete. You cannot delete the currently
3219 To delete an existing queue, use --delete. You cannot delete the currently
3219 active queue.
3220 active queue.
3220
3221
3221 Returns 0 on success.
3222 Returns 0 on success.
3222 '''
3223 '''
3223 q = repo.mq
3224 q = repo.mq
3224 _defaultqueue = 'patches'
3225 _defaultqueue = 'patches'
3225 _allqueues = 'patches.queues'
3226 _allqueues = 'patches.queues'
3226 _activequeue = 'patches.queue'
3227 _activequeue = 'patches.queue'
3227
3228
3228 def _getcurrent():
3229 def _getcurrent():
3229 cur = os.path.basename(q.path)
3230 cur = os.path.basename(q.path)
3230 if cur.startswith('patches-'):
3231 if cur.startswith('patches-'):
3231 cur = cur[8:]
3232 cur = cur[8:]
3232 return cur
3233 return cur
3233
3234
3234 def _noqueues():
3235 def _noqueues():
3235 try:
3236 try:
3236 fh = repo.vfs(_allqueues, 'r')
3237 fh = repo.vfs(_allqueues, 'r')
3237 fh.close()
3238 fh.close()
3238 except IOError:
3239 except IOError:
3239 return True
3240 return True
3240
3241
3241 return False
3242 return False
3242
3243
3243 def _getqueues():
3244 def _getqueues():
3244 current = _getcurrent()
3245 current = _getcurrent()
3245
3246
3246 try:
3247 try:
3247 fh = repo.vfs(_allqueues, 'r')
3248 fh = repo.vfs(_allqueues, 'r')
3248 queues = [queue.strip() for queue in fh if queue.strip()]
3249 queues = [queue.strip() for queue in fh if queue.strip()]
3249 fh.close()
3250 fh.close()
3250 if current not in queues:
3251 if current not in queues:
3251 queues.append(current)
3252 queues.append(current)
3252 except IOError:
3253 except IOError:
3253 queues = [_defaultqueue]
3254 queues = [_defaultqueue]
3254
3255
3255 return sorted(queues)
3256 return sorted(queues)
3256
3257
3257 def _setactive(name):
3258 def _setactive(name):
3258 if q.applied:
3259 if q.applied:
3259 raise util.Abort(_('new queue created, but cannot make active '
3260 raise util.Abort(_('new queue created, but cannot make active '
3260 'as patches are applied'))
3261 'as patches are applied'))
3261 _setactivenocheck(name)
3262 _setactivenocheck(name)
3262
3263
3263 def _setactivenocheck(name):
3264 def _setactivenocheck(name):
3264 fh = repo.vfs(_activequeue, 'w')
3265 fh = repo.vfs(_activequeue, 'w')
3265 if name != 'patches':
3266 if name != 'patches':
3266 fh.write(name)
3267 fh.write(name)
3267 fh.close()
3268 fh.close()
3268
3269
3269 def _addqueue(name):
3270 def _addqueue(name):
3270 fh = repo.vfs(_allqueues, 'a')
3271 fh = repo.vfs(_allqueues, 'a')
3271 fh.write('%s\n' % (name,))
3272 fh.write('%s\n' % (name,))
3272 fh.close()
3273 fh.close()
3273
3274
3274 def _queuedir(name):
3275 def _queuedir(name):
3275 if name == 'patches':
3276 if name == 'patches':
3276 return repo.join('patches')
3277 return repo.join('patches')
3277 else:
3278 else:
3278 return repo.join('patches-' + name)
3279 return repo.join('patches-' + name)
3279
3280
3280 def _validname(name):
3281 def _validname(name):
3281 for n in name:
3282 for n in name:
3282 if n in ':\\/.':
3283 if n in ':\\/.':
3283 return False
3284 return False
3284 return True
3285 return True
3285
3286
3286 def _delete(name):
3287 def _delete(name):
3287 if name not in existing:
3288 if name not in existing:
3288 raise util.Abort(_('cannot delete queue that does not exist'))
3289 raise util.Abort(_('cannot delete queue that does not exist'))
3289
3290
3290 current = _getcurrent()
3291 current = _getcurrent()
3291
3292
3292 if name == current:
3293 if name == current:
3293 raise util.Abort(_('cannot delete currently active queue'))
3294 raise util.Abort(_('cannot delete currently active queue'))
3294
3295
3295 fh = repo.vfs('patches.queues.new', 'w')
3296 fh = repo.vfs('patches.queues.new', 'w')
3296 for queue in existing:
3297 for queue in existing:
3297 if queue == name:
3298 if queue == name:
3298 continue
3299 continue
3299 fh.write('%s\n' % (queue,))
3300 fh.write('%s\n' % (queue,))
3300 fh.close()
3301 fh.close()
3301 util.rename(repo.join('patches.queues.new'), repo.join(_allqueues))
3302 util.rename(repo.join('patches.queues.new'), repo.join(_allqueues))
3302
3303
3303 if not name or opts.get('list') or opts.get('active'):
3304 if not name or opts.get('list') or opts.get('active'):
3304 current = _getcurrent()
3305 current = _getcurrent()
3305 if opts.get('active'):
3306 if opts.get('active'):
3306 ui.write('%s\n' % (current,))
3307 ui.write('%s\n' % (current,))
3307 return
3308 return
3308 for queue in _getqueues():
3309 for queue in _getqueues():
3309 ui.write('%s' % (queue,))
3310 ui.write('%s' % (queue,))
3310 if queue == current and not ui.quiet:
3311 if queue == current and not ui.quiet:
3311 ui.write(_(' (active)\n'))
3312 ui.write(_(' (active)\n'))
3312 else:
3313 else:
3313 ui.write('\n')
3314 ui.write('\n')
3314 return
3315 return
3315
3316
3316 if not _validname(name):
3317 if not _validname(name):
3317 raise util.Abort(
3318 raise util.Abort(
3318 _('invalid queue name, may not contain the characters ":\\/."'))
3319 _('invalid queue name, may not contain the characters ":\\/."'))
3319
3320
3320 existing = _getqueues()
3321 existing = _getqueues()
3321
3322
3322 if opts.get('create'):
3323 if opts.get('create'):
3323 if name in existing:
3324 if name in existing:
3324 raise util.Abort(_('queue "%s" already exists') % name)
3325 raise util.Abort(_('queue "%s" already exists') % name)
3325 if _noqueues():
3326 if _noqueues():
3326 _addqueue(_defaultqueue)
3327 _addqueue(_defaultqueue)
3327 _addqueue(name)
3328 _addqueue(name)
3328 _setactive(name)
3329 _setactive(name)
3329 elif opts.get('rename'):
3330 elif opts.get('rename'):
3330 current = _getcurrent()
3331 current = _getcurrent()
3331 if name == current:
3332 if name == current:
3332 raise util.Abort(_('can\'t rename "%s" to its current name') % name)
3333 raise util.Abort(_('can\'t rename "%s" to its current name') % name)
3333 if name in existing:
3334 if name in existing:
3334 raise util.Abort(_('queue "%s" already exists') % name)
3335 raise util.Abort(_('queue "%s" already exists') % name)
3335
3336
3336 olddir = _queuedir(current)
3337 olddir = _queuedir(current)
3337 newdir = _queuedir(name)
3338 newdir = _queuedir(name)
3338
3339
3339 if os.path.exists(newdir):
3340 if os.path.exists(newdir):
3340 raise util.Abort(_('non-queue directory "%s" already exists') %
3341 raise util.Abort(_('non-queue directory "%s" already exists') %
3341 newdir)
3342 newdir)
3342
3343
3343 fh = repo.vfs('patches.queues.new', 'w')
3344 fh = repo.vfs('patches.queues.new', 'w')
3344 for queue in existing:
3345 for queue in existing:
3345 if queue == current:
3346 if queue == current:
3346 fh.write('%s\n' % (name,))
3347 fh.write('%s\n' % (name,))
3347 if os.path.exists(olddir):
3348 if os.path.exists(olddir):
3348 util.rename(olddir, newdir)
3349 util.rename(olddir, newdir)
3349 else:
3350 else:
3350 fh.write('%s\n' % (queue,))
3351 fh.write('%s\n' % (queue,))
3351 fh.close()
3352 fh.close()
3352 util.rename(repo.join('patches.queues.new'), repo.join(_allqueues))
3353 util.rename(repo.join('patches.queues.new'), repo.join(_allqueues))
3353 _setactivenocheck(name)
3354 _setactivenocheck(name)
3354 elif opts.get('delete'):
3355 elif opts.get('delete'):
3355 _delete(name)
3356 _delete(name)
3356 elif opts.get('purge'):
3357 elif opts.get('purge'):
3357 if name in existing:
3358 if name in existing:
3358 _delete(name)
3359 _delete(name)
3359 qdir = _queuedir(name)
3360 qdir = _queuedir(name)
3360 if os.path.exists(qdir):
3361 if os.path.exists(qdir):
3361 shutil.rmtree(qdir)
3362 shutil.rmtree(qdir)
3362 else:
3363 else:
3363 if name not in existing:
3364 if name not in existing:
3364 raise util.Abort(_('use --create to create a new queue'))
3365 raise util.Abort(_('use --create to create a new queue'))
3365 _setactive(name)
3366 _setactive(name)
3366
3367
3367 def mqphasedefaults(repo, roots):
3368 def mqphasedefaults(repo, roots):
3368 """callback used to set mq changeset as secret when no phase data exists"""
3369 """callback used to set mq changeset as secret when no phase data exists"""
3369 if repo.mq.applied:
3370 if repo.mq.applied:
3370 if repo.ui.configbool('mq', 'secret', False):
3371 if repo.ui.configbool('mq', 'secret', False):
3371 mqphase = phases.secret
3372 mqphase = phases.secret
3372 else:
3373 else:
3373 mqphase = phases.draft
3374 mqphase = phases.draft
3374 qbase = repo[repo.mq.applied[0].node]
3375 qbase = repo[repo.mq.applied[0].node]
3375 roots[mqphase].add(qbase.node())
3376 roots[mqphase].add(qbase.node())
3376 return roots
3377 return roots
3377
3378
3378 def reposetup(ui, repo):
3379 def reposetup(ui, repo):
3379 class mqrepo(repo.__class__):
3380 class mqrepo(repo.__class__):
3380 @localrepo.unfilteredpropertycache
3381 @localrepo.unfilteredpropertycache
3381 def mq(self):
3382 def mq(self):
3382 return queue(self.ui, self.baseui, self.path)
3383 return queue(self.ui, self.baseui, self.path)
3383
3384
3384 def invalidateall(self):
3385 def invalidateall(self):
3385 super(mqrepo, self).invalidateall()
3386 super(mqrepo, self).invalidateall()
3386 if localrepo.hasunfilteredcache(self, 'mq'):
3387 if localrepo.hasunfilteredcache(self, 'mq'):
3387 # recreate mq in case queue path was changed
3388 # recreate mq in case queue path was changed
3388 delattr(self.unfiltered(), 'mq')
3389 delattr(self.unfiltered(), 'mq')
3389
3390
3390 def abortifwdirpatched(self, errmsg, force=False):
3391 def abortifwdirpatched(self, errmsg, force=False):
3391 if self.mq.applied and self.mq.checkapplied and not force:
3392 if self.mq.applied and self.mq.checkapplied and not force:
3392 parents = self.dirstate.parents()
3393 parents = self.dirstate.parents()
3393 patches = [s.node for s in self.mq.applied]
3394 patches = [s.node for s in self.mq.applied]
3394 if parents[0] in patches or parents[1] in patches:
3395 if parents[0] in patches or parents[1] in patches:
3395 raise util.Abort(errmsg)
3396 raise util.Abort(errmsg)
3396
3397
3397 def commit(self, text="", user=None, date=None, match=None,
3398 def commit(self, text="", user=None, date=None, match=None,
3398 force=False, editor=False, extra={}):
3399 force=False, editor=False, extra={}):
3399 self.abortifwdirpatched(
3400 self.abortifwdirpatched(
3400 _('cannot commit over an applied mq patch'),
3401 _('cannot commit over an applied mq patch'),
3401 force)
3402 force)
3402
3403
3403 return super(mqrepo, self).commit(text, user, date, match, force,
3404 return super(mqrepo, self).commit(text, user, date, match, force,
3404 editor, extra)
3405 editor, extra)
3405
3406
3406 def checkpush(self, pushop):
3407 def checkpush(self, pushop):
3407 if self.mq.applied and self.mq.checkapplied and not pushop.force:
3408 if self.mq.applied and self.mq.checkapplied and not pushop.force:
3408 outapplied = [e.node for e in self.mq.applied]
3409 outapplied = [e.node for e in self.mq.applied]
3409 if pushop.revs:
3410 if pushop.revs:
3410 # Assume applied patches have no non-patch descendants and
3411 # Assume applied patches have no non-patch descendants and
3411 # are not on remote already. Filtering any changeset not
3412 # are not on remote already. Filtering any changeset not
3412 # pushed.
3413 # pushed.
3413 heads = set(pushop.revs)
3414 heads = set(pushop.revs)
3414 for node in reversed(outapplied):
3415 for node in reversed(outapplied):
3415 if node in heads:
3416 if node in heads:
3416 break
3417 break
3417 else:
3418 else:
3418 outapplied.pop()
3419 outapplied.pop()
3419 # looking for pushed and shared changeset
3420 # looking for pushed and shared changeset
3420 for node in outapplied:
3421 for node in outapplied:
3421 if self[node].phase() < phases.secret:
3422 if self[node].phase() < phases.secret:
3422 raise util.Abort(_('source has mq patches applied'))
3423 raise util.Abort(_('source has mq patches applied'))
3423 # no non-secret patches pushed
3424 # no non-secret patches pushed
3424 super(mqrepo, self).checkpush(pushop)
3425 super(mqrepo, self).checkpush(pushop)
3425
3426
3426 def _findtags(self):
3427 def _findtags(self):
3427 '''augment tags from base class with patch tags'''
3428 '''augment tags from base class with patch tags'''
3428 result = super(mqrepo, self)._findtags()
3429 result = super(mqrepo, self)._findtags()
3429
3430
3430 q = self.mq
3431 q = self.mq
3431 if not q.applied:
3432 if not q.applied:
3432 return result
3433 return result
3433
3434
3434 mqtags = [(patch.node, patch.name) for patch in q.applied]
3435 mqtags = [(patch.node, patch.name) for patch in q.applied]
3435
3436
3436 try:
3437 try:
3437 # for now ignore filtering business
3438 # for now ignore filtering business
3438 self.unfiltered().changelog.rev(mqtags[-1][0])
3439 self.unfiltered().changelog.rev(mqtags[-1][0])
3439 except error.LookupError:
3440 except error.LookupError:
3440 self.ui.warn(_('mq status file refers to unknown node %s\n')
3441 self.ui.warn(_('mq status file refers to unknown node %s\n')
3441 % short(mqtags[-1][0]))
3442 % short(mqtags[-1][0]))
3442 return result
3443 return result
3443
3444
3444 # do not add fake tags for filtered revisions
3445 # do not add fake tags for filtered revisions
3445 included = self.changelog.hasnode
3446 included = self.changelog.hasnode
3446 mqtags = [mqt for mqt in mqtags if included(mqt[0])]
3447 mqtags = [mqt for mqt in mqtags if included(mqt[0])]
3447 if not mqtags:
3448 if not mqtags:
3448 return result
3449 return result
3449
3450
3450 mqtags.append((mqtags[-1][0], 'qtip'))
3451 mqtags.append((mqtags[-1][0], 'qtip'))
3451 mqtags.append((mqtags[0][0], 'qbase'))
3452 mqtags.append((mqtags[0][0], 'qbase'))
3452 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
3453 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
3453 tags = result[0]
3454 tags = result[0]
3454 for patch in mqtags:
3455 for patch in mqtags:
3455 if patch[1] in tags:
3456 if patch[1] in tags:
3456 self.ui.warn(_('tag %s overrides mq patch of the same '
3457 self.ui.warn(_('tag %s overrides mq patch of the same '
3457 'name\n') % patch[1])
3458 'name\n') % patch[1])
3458 else:
3459 else:
3459 tags[patch[1]] = patch[0]
3460 tags[patch[1]] = patch[0]
3460
3461
3461 return result
3462 return result
3462
3463
3463 if repo.local():
3464 if repo.local():
3464 repo.__class__ = mqrepo
3465 repo.__class__ = mqrepo
3465
3466
3466 repo._phasedefaults.append(mqphasedefaults)
3467 repo._phasedefaults.append(mqphasedefaults)
3467
3468
3468 def mqimport(orig, ui, repo, *args, **kwargs):
3469 def mqimport(orig, ui, repo, *args, **kwargs):
3469 if (util.safehasattr(repo, 'abortifwdirpatched')
3470 if (util.safehasattr(repo, 'abortifwdirpatched')
3470 and not kwargs.get('no_commit', False)):
3471 and not kwargs.get('no_commit', False)):
3471 repo.abortifwdirpatched(_('cannot import over an applied patch'),
3472 repo.abortifwdirpatched(_('cannot import over an applied patch'),
3472 kwargs.get('force'))
3473 kwargs.get('force'))
3473 return orig(ui, repo, *args, **kwargs)
3474 return orig(ui, repo, *args, **kwargs)
3474
3475
3475 def mqinit(orig, ui, *args, **kwargs):
3476 def mqinit(orig, ui, *args, **kwargs):
3476 mq = kwargs.pop('mq', None)
3477 mq = kwargs.pop('mq', None)
3477
3478
3478 if not mq:
3479 if not mq:
3479 return orig(ui, *args, **kwargs)
3480 return orig(ui, *args, **kwargs)
3480
3481
3481 if args:
3482 if args:
3482 repopath = args[0]
3483 repopath = args[0]
3483 if not hg.islocal(repopath):
3484 if not hg.islocal(repopath):
3484 raise util.Abort(_('only a local queue repository '
3485 raise util.Abort(_('only a local queue repository '
3485 'may be initialized'))
3486 'may be initialized'))
3486 else:
3487 else:
3487 repopath = cmdutil.findrepo(os.getcwd())
3488 repopath = cmdutil.findrepo(os.getcwd())
3488 if not repopath:
3489 if not repopath:
3489 raise util.Abort(_('there is no Mercurial repository here '
3490 raise util.Abort(_('there is no Mercurial repository here '
3490 '(.hg not found)'))
3491 '(.hg not found)'))
3491 repo = hg.repository(ui, repopath)
3492 repo = hg.repository(ui, repopath)
3492 return qinit(ui, repo, True)
3493 return qinit(ui, repo, True)
3493
3494
3494 def mqcommand(orig, ui, repo, *args, **kwargs):
3495 def mqcommand(orig, ui, repo, *args, **kwargs):
3495 """Add --mq option to operate on patch repository instead of main"""
3496 """Add --mq option to operate on patch repository instead of main"""
3496
3497
3497 # some commands do not like getting unknown options
3498 # some commands do not like getting unknown options
3498 mq = kwargs.pop('mq', None)
3499 mq = kwargs.pop('mq', None)
3499
3500
3500 if not mq:
3501 if not mq:
3501 return orig(ui, repo, *args, **kwargs)
3502 return orig(ui, repo, *args, **kwargs)
3502
3503
3503 q = repo.mq
3504 q = repo.mq
3504 r = q.qrepo()
3505 r = q.qrepo()
3505 if not r:
3506 if not r:
3506 raise util.Abort(_('no queue repository'))
3507 raise util.Abort(_('no queue repository'))
3507 return orig(r.ui, r, *args, **kwargs)
3508 return orig(r.ui, r, *args, **kwargs)
3508
3509
3509 def summaryhook(ui, repo):
3510 def summaryhook(ui, repo):
3510 q = repo.mq
3511 q = repo.mq
3511 m = []
3512 m = []
3512 a, u = len(q.applied), len(q.unapplied(repo))
3513 a, u = len(q.applied), len(q.unapplied(repo))
3513 if a:
3514 if a:
3514 m.append(ui.label(_("%d applied"), 'qseries.applied') % a)
3515 m.append(ui.label(_("%d applied"), 'qseries.applied') % a)
3515 if u:
3516 if u:
3516 m.append(ui.label(_("%d unapplied"), 'qseries.unapplied') % u)
3517 m.append(ui.label(_("%d unapplied"), 'qseries.unapplied') % u)
3517 if m:
3518 if m:
3518 # i18n: column positioning for "hg summary"
3519 # i18n: column positioning for "hg summary"
3519 ui.write(_("mq: %s\n") % ', '.join(m))
3520 ui.write(_("mq: %s\n") % ', '.join(m))
3520 else:
3521 else:
3521 # i18n: column positioning for "hg summary"
3522 # i18n: column positioning for "hg summary"
3522 ui.note(_("mq: (empty queue)\n"))
3523 ui.note(_("mq: (empty queue)\n"))
3523
3524
3524 def revsetmq(repo, subset, x):
3525 def revsetmq(repo, subset, x):
3525 """``mq()``
3526 """``mq()``
3526 Changesets managed by MQ.
3527 Changesets managed by MQ.
3527 """
3528 """
3528 revset.getargs(x, 0, 0, _("mq takes no arguments"))
3529 revset.getargs(x, 0, 0, _("mq takes no arguments"))
3529 applied = set([repo[r.node].rev() for r in repo.mq.applied])
3530 applied = set([repo[r.node].rev() for r in repo.mq.applied])
3530 return revset.baseset([r for r in subset if r in applied])
3531 return revset.baseset([r for r in subset if r in applied])
3531
3532
3532 # tell hggettext to extract docstrings from these functions:
3533 # tell hggettext to extract docstrings from these functions:
3533 i18nfunctions = [revsetmq]
3534 i18nfunctions = [revsetmq]
3534
3535
3535 def extsetup(ui):
3536 def extsetup(ui):
3536 # Ensure mq wrappers are called first, regardless of extension load order by
3537 # Ensure mq wrappers are called first, regardless of extension load order by
3537 # NOT wrapping in uisetup() and instead deferring to init stage two here.
3538 # NOT wrapping in uisetup() and instead deferring to init stage two here.
3538 mqopt = [('', 'mq', None, _("operate on patch repository"))]
3539 mqopt = [('', 'mq', None, _("operate on patch repository"))]
3539
3540
3540 extensions.wrapcommand(commands.table, 'import', mqimport)
3541 extensions.wrapcommand(commands.table, 'import', mqimport)
3541 cmdutil.summaryhooks.add('mq', summaryhook)
3542 cmdutil.summaryhooks.add('mq', summaryhook)
3542
3543
3543 entry = extensions.wrapcommand(commands.table, 'init', mqinit)
3544 entry = extensions.wrapcommand(commands.table, 'init', mqinit)
3544 entry[1].extend(mqopt)
3545 entry[1].extend(mqopt)
3545
3546
3546 nowrap = set(commands.norepo.split(" "))
3547 nowrap = set(commands.norepo.split(" "))
3547
3548
3548 def dotable(cmdtable):
3549 def dotable(cmdtable):
3549 for cmd in cmdtable.keys():
3550 for cmd in cmdtable.keys():
3550 cmd = cmdutil.parsealiases(cmd)[0]
3551 cmd = cmdutil.parsealiases(cmd)[0]
3551 if cmd in nowrap:
3552 if cmd in nowrap:
3552 continue
3553 continue
3553 entry = extensions.wrapcommand(cmdtable, cmd, mqcommand)
3554 entry = extensions.wrapcommand(cmdtable, cmd, mqcommand)
3554 entry[1].extend(mqopt)
3555 entry[1].extend(mqopt)
3555
3556
3556 dotable(commands.table)
3557 dotable(commands.table)
3557
3558
3558 for extname, extmodule in extensions.extensions():
3559 for extname, extmodule in extensions.extensions():
3559 if extmodule.__file__ != __file__:
3560 if extmodule.__file__ != __file__:
3560 dotable(getattr(extmodule, 'cmdtable', {}))
3561 dotable(getattr(extmodule, 'cmdtable', {}))
3561
3562
3562 revset.symbols['mq'] = revsetmq
3563 revset.symbols['mq'] = revsetmq
3563
3564
3564 colortable = {'qguard.negative': 'red',
3565 colortable = {'qguard.negative': 'red',
3565 'qguard.positive': 'yellow',
3566 'qguard.positive': 'yellow',
3566 'qguard.unguarded': 'green',
3567 'qguard.unguarded': 'green',
3567 'qseries.applied': 'blue bold underline',
3568 'qseries.applied': 'blue bold underline',
3568 'qseries.guarded': 'black bold',
3569 'qseries.guarded': 'black bold',
3569 'qseries.missing': 'red bold',
3570 'qseries.missing': 'red bold',
3570 'qseries.unapplied': 'black bold'}
3571 'qseries.unapplied': 'black bold'}
@@ -1,699 +1,698 b''
1 # Patch transplanting extension for Mercurial
1 # Patch transplanting extension for Mercurial
2 #
2 #
3 # Copyright 2006, 2007 Brendan Cully <brendan@kublai.com>
3 # Copyright 2006, 2007 Brendan Cully <brendan@kublai.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 '''command to transplant changesets from another branch
8 '''command to transplant changesets from another branch
9
9
10 This extension allows you to transplant changes to another parent revision,
10 This extension allows you to transplant changes to another parent revision,
11 possibly in another repository. The transplant is done using 'diff' patches.
11 possibly in another repository. The transplant is done using 'diff' patches.
12
12
13 Transplanted patches are recorded in .hg/transplant/transplants, as a
13 Transplanted patches are recorded in .hg/transplant/transplants, as a
14 map from a changeset hash to its hash in the source repository.
14 map from a changeset hash to its hash in the source repository.
15 '''
15 '''
16
16
17 from mercurial.i18n import _
17 from mercurial.i18n import _
18 import os, tempfile
18 import os, tempfile
19 from mercurial.node import short
19 from mercurial.node import short
20 from mercurial import bundlerepo, hg, merge, match
20 from mercurial import bundlerepo, hg, merge, match
21 from mercurial import patch, revlog, scmutil, util, error, cmdutil
21 from mercurial import patch, revlog, scmutil, util, error, cmdutil
22 from mercurial import revset, templatekw, exchange
22 from mercurial import revset, templatekw, exchange
23
23
24 class TransplantError(error.Abort):
24 class TransplantError(error.Abort):
25 pass
25 pass
26
26
27 cmdtable = {}
27 cmdtable = {}
28 command = cmdutil.command(cmdtable)
28 command = cmdutil.command(cmdtable)
29 testedwith = 'internal'
29 testedwith = 'internal'
30
30
31 class transplantentry(object):
31 class transplantentry(object):
32 def __init__(self, lnode, rnode):
32 def __init__(self, lnode, rnode):
33 self.lnode = lnode
33 self.lnode = lnode
34 self.rnode = rnode
34 self.rnode = rnode
35
35
36 class transplants(object):
36 class transplants(object):
37 def __init__(self, path=None, transplantfile=None, opener=None):
37 def __init__(self, path=None, transplantfile=None, opener=None):
38 self.path = path
38 self.path = path
39 self.transplantfile = transplantfile
39 self.transplantfile = transplantfile
40 self.opener = opener
40 self.opener = opener
41
41
42 if not opener:
42 if not opener:
43 self.opener = scmutil.opener(self.path)
43 self.opener = scmutil.opener(self.path)
44 self.transplants = {}
44 self.transplants = {}
45 self.dirty = False
45 self.dirty = False
46 self.read()
46 self.read()
47
47
48 def read(self):
48 def read(self):
49 abspath = os.path.join(self.path, self.transplantfile)
49 abspath = os.path.join(self.path, self.transplantfile)
50 if self.transplantfile and os.path.exists(abspath):
50 if self.transplantfile and os.path.exists(abspath):
51 for line in self.opener.read(self.transplantfile).splitlines():
51 for line in self.opener.read(self.transplantfile).splitlines():
52 lnode, rnode = map(revlog.bin, line.split(':'))
52 lnode, rnode = map(revlog.bin, line.split(':'))
53 list = self.transplants.setdefault(rnode, [])
53 list = self.transplants.setdefault(rnode, [])
54 list.append(transplantentry(lnode, rnode))
54 list.append(transplantentry(lnode, rnode))
55
55
56 def write(self):
56 def write(self):
57 if self.dirty and self.transplantfile:
57 if self.dirty and self.transplantfile:
58 if not os.path.isdir(self.path):
58 if not os.path.isdir(self.path):
59 os.mkdir(self.path)
59 os.mkdir(self.path)
60 fp = self.opener(self.transplantfile, 'w')
60 fp = self.opener(self.transplantfile, 'w')
61 for list in self.transplants.itervalues():
61 for list in self.transplants.itervalues():
62 for t in list:
62 for t in list:
63 l, r = map(revlog.hex, (t.lnode, t.rnode))
63 l, r = map(revlog.hex, (t.lnode, t.rnode))
64 fp.write(l + ':' + r + '\n')
64 fp.write(l + ':' + r + '\n')
65 fp.close()
65 fp.close()
66 self.dirty = False
66 self.dirty = False
67
67
68 def get(self, rnode):
68 def get(self, rnode):
69 return self.transplants.get(rnode) or []
69 return self.transplants.get(rnode) or []
70
70
71 def set(self, lnode, rnode):
71 def set(self, lnode, rnode):
72 list = self.transplants.setdefault(rnode, [])
72 list = self.transplants.setdefault(rnode, [])
73 list.append(transplantentry(lnode, rnode))
73 list.append(transplantentry(lnode, rnode))
74 self.dirty = True
74 self.dirty = True
75
75
76 def remove(self, transplant):
76 def remove(self, transplant):
77 list = self.transplants.get(transplant.rnode)
77 list = self.transplants.get(transplant.rnode)
78 if list:
78 if list:
79 del list[list.index(transplant)]
79 del list[list.index(transplant)]
80 self.dirty = True
80 self.dirty = True
81
81
82 class transplanter(object):
82 class transplanter(object):
83 def __init__(self, ui, repo, opts):
83 def __init__(self, ui, repo, opts):
84 self.ui = ui
84 self.ui = ui
85 self.path = repo.join('transplant')
85 self.path = repo.join('transplant')
86 self.opener = scmutil.opener(self.path)
86 self.opener = scmutil.opener(self.path)
87 self.transplants = transplants(self.path, 'transplants',
87 self.transplants = transplants(self.path, 'transplants',
88 opener=self.opener)
88 opener=self.opener)
89 def getcommiteditor():
89 def getcommiteditor():
90 editform = cmdutil.mergeeditform(repo[None], 'transplant')
90 editform = cmdutil.mergeeditform(repo[None], 'transplant')
91 return cmdutil.getcommiteditor(editform=editform, **opts)
91 return cmdutil.getcommiteditor(editform=editform, **opts)
92 self.getcommiteditor = getcommiteditor
92 self.getcommiteditor = getcommiteditor
93
93
94 def applied(self, repo, node, parent):
94 def applied(self, repo, node, parent):
95 '''returns True if a node is already an ancestor of parent
95 '''returns True if a node is already an ancestor of parent
96 or is parent or has already been transplanted'''
96 or is parent or has already been transplanted'''
97 if hasnode(repo, parent):
97 if hasnode(repo, parent):
98 parentrev = repo.changelog.rev(parent)
98 parentrev = repo.changelog.rev(parent)
99 if hasnode(repo, node):
99 if hasnode(repo, node):
100 rev = repo.changelog.rev(node)
100 rev = repo.changelog.rev(node)
101 reachable = repo.changelog.ancestors([parentrev], rev,
101 reachable = repo.changelog.ancestors([parentrev], rev,
102 inclusive=True)
102 inclusive=True)
103 if rev in reachable:
103 if rev in reachable:
104 return True
104 return True
105 for t in self.transplants.get(node):
105 for t in self.transplants.get(node):
106 # it might have been stripped
106 # it might have been stripped
107 if not hasnode(repo, t.lnode):
107 if not hasnode(repo, t.lnode):
108 self.transplants.remove(t)
108 self.transplants.remove(t)
109 return False
109 return False
110 lnoderev = repo.changelog.rev(t.lnode)
110 lnoderev = repo.changelog.rev(t.lnode)
111 if lnoderev in repo.changelog.ancestors([parentrev], lnoderev,
111 if lnoderev in repo.changelog.ancestors([parentrev], lnoderev,
112 inclusive=True):
112 inclusive=True):
113 return True
113 return True
114 return False
114 return False
115
115
116 def apply(self, repo, source, revmap, merges, opts={}):
116 def apply(self, repo, source, revmap, merges, opts={}):
117 '''apply the revisions in revmap one by one in revision order'''
117 '''apply the revisions in revmap one by one in revision order'''
118 revs = sorted(revmap)
118 revs = sorted(revmap)
119 p1, p2 = repo.dirstate.parents()
119 p1, p2 = repo.dirstate.parents()
120 pulls = []
120 pulls = []
121 diffopts = patch.difffeatureopts(self.ui, opts)
121 diffopts = patch.difffeatureopts(self.ui, opts)
122 diffopts.git = True
122 diffopts.git = True
123
123
124 lock = wlock = tr = None
124 lock = wlock = tr = None
125 try:
125 try:
126 wlock = repo.wlock()
126 wlock = repo.wlock()
127 lock = repo.lock()
127 lock = repo.lock()
128 tr = repo.transaction('transplant')
128 tr = repo.transaction('transplant')
129 for rev in revs:
129 for rev in revs:
130 node = revmap[rev]
130 node = revmap[rev]
131 revstr = '%s:%s' % (rev, short(node))
131 revstr = '%s:%s' % (rev, short(node))
132
132
133 if self.applied(repo, node, p1):
133 if self.applied(repo, node, p1):
134 self.ui.warn(_('skipping already applied revision %s\n') %
134 self.ui.warn(_('skipping already applied revision %s\n') %
135 revstr)
135 revstr)
136 continue
136 continue
137
137
138 parents = source.changelog.parents(node)
138 parents = source.changelog.parents(node)
139 if not (opts.get('filter') or opts.get('log')):
139 if not (opts.get('filter') or opts.get('log')):
140 # If the changeset parent is the same as the
140 # If the changeset parent is the same as the
141 # wdir's parent, just pull it.
141 # wdir's parent, just pull it.
142 if parents[0] == p1:
142 if parents[0] == p1:
143 pulls.append(node)
143 pulls.append(node)
144 p1 = node
144 p1 = node
145 continue
145 continue
146 if pulls:
146 if pulls:
147 if source != repo:
147 if source != repo:
148 exchange.pull(repo, source.peer(), heads=pulls)
148 exchange.pull(repo, source.peer(), heads=pulls)
149 merge.update(repo, pulls[-1], False, False, None)
149 merge.update(repo, pulls[-1], False, False, None)
150 p1, p2 = repo.dirstate.parents()
150 p1, p2 = repo.dirstate.parents()
151 pulls = []
151 pulls = []
152
152
153 domerge = False
153 domerge = False
154 if node in merges:
154 if node in merges:
155 # pulling all the merge revs at once would mean we
155 # pulling all the merge revs at once would mean we
156 # couldn't transplant after the latest even if
156 # couldn't transplant after the latest even if
157 # transplants before them fail.
157 # transplants before them fail.
158 domerge = True
158 domerge = True
159 if not hasnode(repo, node):
159 if not hasnode(repo, node):
160 exchange.pull(repo, source.peer(), heads=[node])
160 exchange.pull(repo, source.peer(), heads=[node])
161
161
162 skipmerge = False
162 skipmerge = False
163 if parents[1] != revlog.nullid:
163 if parents[1] != revlog.nullid:
164 if not opts.get('parent'):
164 if not opts.get('parent'):
165 self.ui.note(_('skipping merge changeset %s:%s\n')
165 self.ui.note(_('skipping merge changeset %s:%s\n')
166 % (rev, short(node)))
166 % (rev, short(node)))
167 skipmerge = True
167 skipmerge = True
168 else:
168 else:
169 parent = source.lookup(opts['parent'])
169 parent = source.lookup(opts['parent'])
170 if parent not in parents:
170 if parent not in parents:
171 raise util.Abort(_('%s is not a parent of %s') %
171 raise util.Abort(_('%s is not a parent of %s') %
172 (short(parent), short(node)))
172 (short(parent), short(node)))
173 else:
173 else:
174 parent = parents[0]
174 parent = parents[0]
175
175
176 if skipmerge:
176 if skipmerge:
177 patchfile = None
177 patchfile = None
178 else:
178 else:
179 fd, patchfile = tempfile.mkstemp(prefix='hg-transplant-')
179 fd, patchfile = tempfile.mkstemp(prefix='hg-transplant-')
180 fp = os.fdopen(fd, 'w')
180 fp = os.fdopen(fd, 'w')
181 gen = patch.diff(source, parent, node, opts=diffopts)
181 gen = patch.diff(source, parent, node, opts=diffopts)
182 for chunk in gen:
182 for chunk in gen:
183 fp.write(chunk)
183 fp.write(chunk)
184 fp.close()
184 fp.close()
185
185
186 del revmap[rev]
186 del revmap[rev]
187 if patchfile or domerge:
187 if patchfile or domerge:
188 try:
188 try:
189 try:
189 try:
190 n = self.applyone(repo, node,
190 n = self.applyone(repo, node,
191 source.changelog.read(node),
191 source.changelog.read(node),
192 patchfile, merge=domerge,
192 patchfile, merge=domerge,
193 log=opts.get('log'),
193 log=opts.get('log'),
194 filter=opts.get('filter'))
194 filter=opts.get('filter'))
195 except TransplantError:
195 except TransplantError:
196 # Do not rollback, it is up to the user to
196 # Do not rollback, it is up to the user to
197 # fix the merge or cancel everything
197 # fix the merge or cancel everything
198 tr.close()
198 tr.close()
199 raise
199 raise
200 if n and domerge:
200 if n and domerge:
201 self.ui.status(_('%s merged at %s\n') % (revstr,
201 self.ui.status(_('%s merged at %s\n') % (revstr,
202 short(n)))
202 short(n)))
203 elif n:
203 elif n:
204 self.ui.status(_('%s transplanted to %s\n')
204 self.ui.status(_('%s transplanted to %s\n')
205 % (short(node),
205 % (short(node),
206 short(n)))
206 short(n)))
207 finally:
207 finally:
208 if patchfile:
208 if patchfile:
209 os.unlink(patchfile)
209 os.unlink(patchfile)
210 tr.close()
210 tr.close()
211 if pulls:
211 if pulls:
212 exchange.pull(repo, source.peer(), heads=pulls)
212 exchange.pull(repo, source.peer(), heads=pulls)
213 merge.update(repo, pulls[-1], False, False, None)
213 merge.update(repo, pulls[-1], False, False, None)
214 finally:
214 finally:
215 self.saveseries(revmap, merges)
215 self.saveseries(revmap, merges)
216 self.transplants.write()
216 self.transplants.write()
217 if tr:
217 if tr:
218 tr.release()
218 tr.release()
219 lock.release()
219 lock.release()
220 wlock.release()
220 wlock.release()
221
221
222 def filter(self, filter, node, changelog, patchfile):
222 def filter(self, filter, node, changelog, patchfile):
223 '''arbitrarily rewrite changeset before applying it'''
223 '''arbitrarily rewrite changeset before applying it'''
224
224
225 self.ui.status(_('filtering %s\n') % patchfile)
225 self.ui.status(_('filtering %s\n') % patchfile)
226 user, date, msg = (changelog[1], changelog[2], changelog[4])
226 user, date, msg = (changelog[1], changelog[2], changelog[4])
227 fd, headerfile = tempfile.mkstemp(prefix='hg-transplant-')
227 fd, headerfile = tempfile.mkstemp(prefix='hg-transplant-')
228 fp = os.fdopen(fd, 'w')
228 fp = os.fdopen(fd, 'w')
229 fp.write("# HG changeset patch\n")
229 fp.write("# HG changeset patch\n")
230 fp.write("# User %s\n" % user)
230 fp.write("# User %s\n" % user)
231 fp.write("# Date %d %d\n" % date)
231 fp.write("# Date %d %d\n" % date)
232 fp.write(msg + '\n')
232 fp.write(msg + '\n')
233 fp.close()
233 fp.close()
234
234
235 try:
235 try:
236 self.ui.system('%s %s %s' % (filter, util.shellquote(headerfile),
236 self.ui.system('%s %s %s' % (filter, util.shellquote(headerfile),
237 util.shellquote(patchfile)),
237 util.shellquote(patchfile)),
238 environ={'HGUSER': changelog[1],
238 environ={'HGUSER': changelog[1],
239 'HGREVISION': revlog.hex(node),
239 'HGREVISION': revlog.hex(node),
240 },
240 },
241 onerr=util.Abort, errprefix=_('filter failed'))
241 onerr=util.Abort, errprefix=_('filter failed'))
242 user, date, msg = self.parselog(file(headerfile))[1:4]
242 user, date, msg = self.parselog(file(headerfile))[1:4]
243 finally:
243 finally:
244 os.unlink(headerfile)
244 os.unlink(headerfile)
245
245
246 return (user, date, msg)
246 return (user, date, msg)
247
247
248 def applyone(self, repo, node, cl, patchfile, merge=False, log=False,
248 def applyone(self, repo, node, cl, patchfile, merge=False, log=False,
249 filter=None):
249 filter=None):
250 '''apply the patch in patchfile to the repository as a transplant'''
250 '''apply the patch in patchfile to the repository as a transplant'''
251 (manifest, user, (time, timezone), files, message) = cl[:5]
251 (manifest, user, (time, timezone), files, message) = cl[:5]
252 date = "%d %d" % (time, timezone)
252 date = "%d %d" % (time, timezone)
253 extra = {'transplant_source': node}
253 extra = {'transplant_source': node}
254 if filter:
254 if filter:
255 (user, date, message) = self.filter(filter, node, cl, patchfile)
255 (user, date, message) = self.filter(filter, node, cl, patchfile)
256
256
257 if log:
257 if log:
258 # we don't translate messages inserted into commits
258 # we don't translate messages inserted into commits
259 message += '\n(transplanted from %s)' % revlog.hex(node)
259 message += '\n(transplanted from %s)' % revlog.hex(node)
260
260
261 self.ui.status(_('applying %s\n') % short(node))
261 self.ui.status(_('applying %s\n') % short(node))
262 self.ui.note('%s %s\n%s\n' % (user, date, message))
262 self.ui.note('%s %s\n%s\n' % (user, date, message))
263
263
264 if not patchfile and not merge:
264 if not patchfile and not merge:
265 raise util.Abort(_('can only omit patchfile if merging'))
265 raise util.Abort(_('can only omit patchfile if merging'))
266 if patchfile:
266 if patchfile:
267 try:
267 try:
268 files = set()
268 files = set()
269 patch.patch(self.ui, repo, patchfile, files=files, eolmode=None)
269 patch.patch(self.ui, repo, patchfile, files=files, eolmode=None)
270 files = list(files)
270 files = list(files)
271 except Exception, inst:
271 except Exception, inst:
272 seriespath = os.path.join(self.path, 'series')
272 seriespath = os.path.join(self.path, 'series')
273 if os.path.exists(seriespath):
273 if os.path.exists(seriespath):
274 os.unlink(seriespath)
274 os.unlink(seriespath)
275 p1 = repo.dirstate.p1()
275 p1 = repo.dirstate.p1()
276 p2 = node
276 p2 = node
277 self.log(user, date, message, p1, p2, merge=merge)
277 self.log(user, date, message, p1, p2, merge=merge)
278 self.ui.write(str(inst) + '\n')
278 self.ui.write(str(inst) + '\n')
279 raise TransplantError(_('fix up the merge and run '
279 raise TransplantError(_('fix up the merge and run '
280 'hg transplant --continue'))
280 'hg transplant --continue'))
281 else:
281 else:
282 files = None
282 files = None
283 if merge:
283 if merge:
284 p1, p2 = repo.dirstate.parents()
284 p1, p2 = repo.dirstate.parents()
285 repo.setparents(p1, node)
285 repo.setparents(p1, node)
286 m = match.always(repo.root, '')
286 m = match.always(repo.root, '')
287 else:
287 else:
288 m = match.exact(repo.root, '', files)
288 m = match.exact(repo.root, '', files)
289
289
290 n = repo.commit(message, user, date, extra=extra, match=m,
290 n = repo.commit(message, user, date, extra=extra, match=m,
291 editor=self.getcommiteditor())
291 editor=self.getcommiteditor())
292 if not n:
292 if not n:
293 self.ui.warn(_('skipping emptied changeset %s\n') % short(node))
293 self.ui.warn(_('skipping emptied changeset %s\n') % short(node))
294 return None
294 return None
295 if not merge:
295 if not merge:
296 self.transplants.set(n, node)
296 self.transplants.set(n, node)
297
297
298 return n
298 return n
299
299
300 def resume(self, repo, source, opts):
300 def resume(self, repo, source, opts):
301 '''recover last transaction and apply remaining changesets'''
301 '''recover last transaction and apply remaining changesets'''
302 if os.path.exists(os.path.join(self.path, 'journal')):
302 if os.path.exists(os.path.join(self.path, 'journal')):
303 n, node = self.recover(repo, source, opts)
303 n, node = self.recover(repo, source, opts)
304 if n:
304 if n:
305 self.ui.status(_('%s transplanted as %s\n') % (short(node),
305 self.ui.status(_('%s transplanted as %s\n') % (short(node),
306 short(n)))
306 short(n)))
307 else:
307 else:
308 self.ui.status(_('%s skipped due to empty diff\n')
308 self.ui.status(_('%s skipped due to empty diff\n')
309 % (short(node),))
309 % (short(node),))
310 seriespath = os.path.join(self.path, 'series')
310 seriespath = os.path.join(self.path, 'series')
311 if not os.path.exists(seriespath):
311 if not os.path.exists(seriespath):
312 self.transplants.write()
312 self.transplants.write()
313 return
313 return
314 nodes, merges = self.readseries()
314 nodes, merges = self.readseries()
315 revmap = {}
315 revmap = {}
316 for n in nodes:
316 for n in nodes:
317 revmap[source.changelog.rev(n)] = n
317 revmap[source.changelog.rev(n)] = n
318 os.unlink(seriespath)
318 os.unlink(seriespath)
319
319
320 self.apply(repo, source, revmap, merges, opts)
320 self.apply(repo, source, revmap, merges, opts)
321
321
322 def recover(self, repo, source, opts):
322 def recover(self, repo, source, opts):
323 '''commit working directory using journal metadata'''
323 '''commit working directory using journal metadata'''
324 node, user, date, message, parents = self.readlog()
324 node, user, date, message, parents = self.readlog()
325 merge = False
325 merge = False
326
326
327 if not user or not date or not message or not parents[0]:
327 if not user or not date or not message or not parents[0]:
328 raise util.Abort(_('transplant log file is corrupt'))
328 raise util.Abort(_('transplant log file is corrupt'))
329
329
330 parent = parents[0]
330 parent = parents[0]
331 if len(parents) > 1:
331 if len(parents) > 1:
332 if opts.get('parent'):
332 if opts.get('parent'):
333 parent = source.lookup(opts['parent'])
333 parent = source.lookup(opts['parent'])
334 if parent not in parents:
334 if parent not in parents:
335 raise util.Abort(_('%s is not a parent of %s') %
335 raise util.Abort(_('%s is not a parent of %s') %
336 (short(parent), short(node)))
336 (short(parent), short(node)))
337 else:
337 else:
338 merge = True
338 merge = True
339
339
340 extra = {'transplant_source': node}
340 extra = {'transplant_source': node}
341 wlock = repo.wlock()
341 wlock = repo.wlock()
342 try:
342 try:
343 p1, p2 = repo.dirstate.parents()
343 p1, p2 = repo.dirstate.parents()
344 if p1 != parent:
344 if p1 != parent:
345 raise util.Abort(
345 raise util.Abort(_('working directory not at transplant '
346 _('working dir not at transplant parent %s') %
346 'parent %s') % revlog.hex(parent))
347 revlog.hex(parent))
348 if merge:
347 if merge:
349 repo.setparents(p1, parents[1])
348 repo.setparents(p1, parents[1])
350 modified, added, removed, deleted = repo.status()[:4]
349 modified, added, removed, deleted = repo.status()[:4]
351 if merge or modified or added or removed or deleted:
350 if merge or modified or added or removed or deleted:
352 n = repo.commit(message, user, date, extra=extra,
351 n = repo.commit(message, user, date, extra=extra,
353 editor=self.getcommiteditor())
352 editor=self.getcommiteditor())
354 if not n:
353 if not n:
355 raise util.Abort(_('commit failed'))
354 raise util.Abort(_('commit failed'))
356 if not merge:
355 if not merge:
357 self.transplants.set(n, node)
356 self.transplants.set(n, node)
358 else:
357 else:
359 n = None
358 n = None
360 self.unlog()
359 self.unlog()
361
360
362 return n, node
361 return n, node
363 finally:
362 finally:
364 wlock.release()
363 wlock.release()
365
364
366 def readseries(self):
365 def readseries(self):
367 nodes = []
366 nodes = []
368 merges = []
367 merges = []
369 cur = nodes
368 cur = nodes
370 for line in self.opener.read('series').splitlines():
369 for line in self.opener.read('series').splitlines():
371 if line.startswith('# Merges'):
370 if line.startswith('# Merges'):
372 cur = merges
371 cur = merges
373 continue
372 continue
374 cur.append(revlog.bin(line))
373 cur.append(revlog.bin(line))
375
374
376 return (nodes, merges)
375 return (nodes, merges)
377
376
378 def saveseries(self, revmap, merges):
377 def saveseries(self, revmap, merges):
379 if not revmap:
378 if not revmap:
380 return
379 return
381
380
382 if not os.path.isdir(self.path):
381 if not os.path.isdir(self.path):
383 os.mkdir(self.path)
382 os.mkdir(self.path)
384 series = self.opener('series', 'w')
383 series = self.opener('series', 'w')
385 for rev in sorted(revmap):
384 for rev in sorted(revmap):
386 series.write(revlog.hex(revmap[rev]) + '\n')
385 series.write(revlog.hex(revmap[rev]) + '\n')
387 if merges:
386 if merges:
388 series.write('# Merges\n')
387 series.write('# Merges\n')
389 for m in merges:
388 for m in merges:
390 series.write(revlog.hex(m) + '\n')
389 series.write(revlog.hex(m) + '\n')
391 series.close()
390 series.close()
392
391
393 def parselog(self, fp):
392 def parselog(self, fp):
394 parents = []
393 parents = []
395 message = []
394 message = []
396 node = revlog.nullid
395 node = revlog.nullid
397 inmsg = False
396 inmsg = False
398 user = None
397 user = None
399 date = None
398 date = None
400 for line in fp.read().splitlines():
399 for line in fp.read().splitlines():
401 if inmsg:
400 if inmsg:
402 message.append(line)
401 message.append(line)
403 elif line.startswith('# User '):
402 elif line.startswith('# User '):
404 user = line[7:]
403 user = line[7:]
405 elif line.startswith('# Date '):
404 elif line.startswith('# Date '):
406 date = line[7:]
405 date = line[7:]
407 elif line.startswith('# Node ID '):
406 elif line.startswith('# Node ID '):
408 node = revlog.bin(line[10:])
407 node = revlog.bin(line[10:])
409 elif line.startswith('# Parent '):
408 elif line.startswith('# Parent '):
410 parents.append(revlog.bin(line[9:]))
409 parents.append(revlog.bin(line[9:]))
411 elif not line.startswith('# '):
410 elif not line.startswith('# '):
412 inmsg = True
411 inmsg = True
413 message.append(line)
412 message.append(line)
414 if None in (user, date):
413 if None in (user, date):
415 raise util.Abort(_("filter corrupted changeset (no user or date)"))
414 raise util.Abort(_("filter corrupted changeset (no user or date)"))
416 return (node, user, date, '\n'.join(message), parents)
415 return (node, user, date, '\n'.join(message), parents)
417
416
418 def log(self, user, date, message, p1, p2, merge=False):
417 def log(self, user, date, message, p1, p2, merge=False):
419 '''journal changelog metadata for later recover'''
418 '''journal changelog metadata for later recover'''
420
419
421 if not os.path.isdir(self.path):
420 if not os.path.isdir(self.path):
422 os.mkdir(self.path)
421 os.mkdir(self.path)
423 fp = self.opener('journal', 'w')
422 fp = self.opener('journal', 'w')
424 fp.write('# User %s\n' % user)
423 fp.write('# User %s\n' % user)
425 fp.write('# Date %s\n' % date)
424 fp.write('# Date %s\n' % date)
426 fp.write('# Node ID %s\n' % revlog.hex(p2))
425 fp.write('# Node ID %s\n' % revlog.hex(p2))
427 fp.write('# Parent ' + revlog.hex(p1) + '\n')
426 fp.write('# Parent ' + revlog.hex(p1) + '\n')
428 if merge:
427 if merge:
429 fp.write('# Parent ' + revlog.hex(p2) + '\n')
428 fp.write('# Parent ' + revlog.hex(p2) + '\n')
430 fp.write(message.rstrip() + '\n')
429 fp.write(message.rstrip() + '\n')
431 fp.close()
430 fp.close()
432
431
433 def readlog(self):
432 def readlog(self):
434 return self.parselog(self.opener('journal'))
433 return self.parselog(self.opener('journal'))
435
434
436 def unlog(self):
435 def unlog(self):
437 '''remove changelog journal'''
436 '''remove changelog journal'''
438 absdst = os.path.join(self.path, 'journal')
437 absdst = os.path.join(self.path, 'journal')
439 if os.path.exists(absdst):
438 if os.path.exists(absdst):
440 os.unlink(absdst)
439 os.unlink(absdst)
441
440
442 def transplantfilter(self, repo, source, root):
441 def transplantfilter(self, repo, source, root):
443 def matchfn(node):
442 def matchfn(node):
444 if self.applied(repo, node, root):
443 if self.applied(repo, node, root):
445 return False
444 return False
446 if source.changelog.parents(node)[1] != revlog.nullid:
445 if source.changelog.parents(node)[1] != revlog.nullid:
447 return False
446 return False
448 extra = source.changelog.read(node)[5]
447 extra = source.changelog.read(node)[5]
449 cnode = extra.get('transplant_source')
448 cnode = extra.get('transplant_source')
450 if cnode and self.applied(repo, cnode, root):
449 if cnode and self.applied(repo, cnode, root):
451 return False
450 return False
452 return True
451 return True
453
452
454 return matchfn
453 return matchfn
455
454
456 def hasnode(repo, node):
455 def hasnode(repo, node):
457 try:
456 try:
458 return repo.changelog.rev(node) is not None
457 return repo.changelog.rev(node) is not None
459 except error.RevlogError:
458 except error.RevlogError:
460 return False
459 return False
461
460
462 def browserevs(ui, repo, nodes, opts):
461 def browserevs(ui, repo, nodes, opts):
463 '''interactively transplant changesets'''
462 '''interactively transplant changesets'''
464 displayer = cmdutil.show_changeset(ui, repo, opts)
463 displayer = cmdutil.show_changeset(ui, repo, opts)
465 transplants = []
464 transplants = []
466 merges = []
465 merges = []
467 prompt = _('apply changeset? [ynmpcq?]:'
466 prompt = _('apply changeset? [ynmpcq?]:'
468 '$$ &yes, transplant this changeset'
467 '$$ &yes, transplant this changeset'
469 '$$ &no, skip this changeset'
468 '$$ &no, skip this changeset'
470 '$$ &merge at this changeset'
469 '$$ &merge at this changeset'
471 '$$ show &patch'
470 '$$ show &patch'
472 '$$ &commit selected changesets'
471 '$$ &commit selected changesets'
473 '$$ &quit and cancel transplant'
472 '$$ &quit and cancel transplant'
474 '$$ &? (show this help)')
473 '$$ &? (show this help)')
475 for node in nodes:
474 for node in nodes:
476 displayer.show(repo[node])
475 displayer.show(repo[node])
477 action = None
476 action = None
478 while not action:
477 while not action:
479 action = 'ynmpcq?'[ui.promptchoice(prompt)]
478 action = 'ynmpcq?'[ui.promptchoice(prompt)]
480 if action == '?':
479 if action == '?':
481 for c, t in ui.extractchoices(prompt)[1]:
480 for c, t in ui.extractchoices(prompt)[1]:
482 ui.write('%s: %s\n' % (c, t))
481 ui.write('%s: %s\n' % (c, t))
483 action = None
482 action = None
484 elif action == 'p':
483 elif action == 'p':
485 parent = repo.changelog.parents(node)[0]
484 parent = repo.changelog.parents(node)[0]
486 for chunk in patch.diff(repo, parent, node):
485 for chunk in patch.diff(repo, parent, node):
487 ui.write(chunk)
486 ui.write(chunk)
488 action = None
487 action = None
489 if action == 'y':
488 if action == 'y':
490 transplants.append(node)
489 transplants.append(node)
491 elif action == 'm':
490 elif action == 'm':
492 merges.append(node)
491 merges.append(node)
493 elif action == 'c':
492 elif action == 'c':
494 break
493 break
495 elif action == 'q':
494 elif action == 'q':
496 transplants = ()
495 transplants = ()
497 merges = ()
496 merges = ()
498 break
497 break
499 displayer.close()
498 displayer.close()
500 return (transplants, merges)
499 return (transplants, merges)
501
500
502 @command('transplant',
501 @command('transplant',
503 [('s', 'source', '', _('transplant changesets from REPO'), _('REPO')),
502 [('s', 'source', '', _('transplant changesets from REPO'), _('REPO')),
504 ('b', 'branch', [], _('use this source changeset as head'), _('REV')),
503 ('b', 'branch', [], _('use this source changeset as head'), _('REV')),
505 ('a', 'all', None, _('pull all changesets up to the --branch revisions')),
504 ('a', 'all', None, _('pull all changesets up to the --branch revisions')),
506 ('p', 'prune', [], _('skip over REV'), _('REV')),
505 ('p', 'prune', [], _('skip over REV'), _('REV')),
507 ('m', 'merge', [], _('merge at REV'), _('REV')),
506 ('m', 'merge', [], _('merge at REV'), _('REV')),
508 ('', 'parent', '',
507 ('', 'parent', '',
509 _('parent to choose when transplanting merge'), _('REV')),
508 _('parent to choose when transplanting merge'), _('REV')),
510 ('e', 'edit', False, _('invoke editor on commit messages')),
509 ('e', 'edit', False, _('invoke editor on commit messages')),
511 ('', 'log', None, _('append transplant info to log message')),
510 ('', 'log', None, _('append transplant info to log message')),
512 ('c', 'continue', None, _('continue last transplant session '
511 ('c', 'continue', None, _('continue last transplant session '
513 'after fixing conflicts')),
512 'after fixing conflicts')),
514 ('', 'filter', '',
513 ('', 'filter', '',
515 _('filter changesets through command'), _('CMD'))],
514 _('filter changesets through command'), _('CMD'))],
516 _('hg transplant [-s REPO] [-b BRANCH [-a]] [-p REV] '
515 _('hg transplant [-s REPO] [-b BRANCH [-a]] [-p REV] '
517 '[-m REV] [REV]...'))
516 '[-m REV] [REV]...'))
518 def transplant(ui, repo, *revs, **opts):
517 def transplant(ui, repo, *revs, **opts):
519 '''transplant changesets from another branch
518 '''transplant changesets from another branch
520
519
521 Selected changesets will be applied on top of the current working
520 Selected changesets will be applied on top of the current working
522 directory with the log of the original changeset. The changesets
521 directory with the log of the original changeset. The changesets
523 are copied and will thus appear twice in the history with different
522 are copied and will thus appear twice in the history with different
524 identities.
523 identities.
525
524
526 Consider using the graft command if everything is inside the same
525 Consider using the graft command if everything is inside the same
527 repository - it will use merges and will usually give a better result.
526 repository - it will use merges and will usually give a better result.
528 Use the rebase extension if the changesets are unpublished and you want
527 Use the rebase extension if the changesets are unpublished and you want
529 to move them instead of copying them.
528 to move them instead of copying them.
530
529
531 If --log is specified, log messages will have a comment appended
530 If --log is specified, log messages will have a comment appended
532 of the form::
531 of the form::
533
532
534 (transplanted from CHANGESETHASH)
533 (transplanted from CHANGESETHASH)
535
534
536 You can rewrite the changelog message with the --filter option.
535 You can rewrite the changelog message with the --filter option.
537 Its argument will be invoked with the current changelog message as
536 Its argument will be invoked with the current changelog message as
538 $1 and the patch as $2.
537 $1 and the patch as $2.
539
538
540 --source/-s specifies another repository to use for selecting changesets,
539 --source/-s specifies another repository to use for selecting changesets,
541 just as if it temporarily had been pulled.
540 just as if it temporarily had been pulled.
542 If --branch/-b is specified, these revisions will be used as
541 If --branch/-b is specified, these revisions will be used as
543 heads when deciding which changesets to transplant, just as if only
542 heads when deciding which changesets to transplant, just as if only
544 these revisions had been pulled.
543 these revisions had been pulled.
545 If --all/-a is specified, all the revisions up to the heads specified
544 If --all/-a is specified, all the revisions up to the heads specified
546 with --branch will be transplanted.
545 with --branch will be transplanted.
547
546
548 Example:
547 Example:
549
548
550 - transplant all changes up to REV on top of your current revision::
549 - transplant all changes up to REV on top of your current revision::
551
550
552 hg transplant --branch REV --all
551 hg transplant --branch REV --all
553
552
554 You can optionally mark selected transplanted changesets as merge
553 You can optionally mark selected transplanted changesets as merge
555 changesets. You will not be prompted to transplant any ancestors
554 changesets. You will not be prompted to transplant any ancestors
556 of a merged transplant, and you can merge descendants of them
555 of a merged transplant, and you can merge descendants of them
557 normally instead of transplanting them.
556 normally instead of transplanting them.
558
557
559 Merge changesets may be transplanted directly by specifying the
558 Merge changesets may be transplanted directly by specifying the
560 proper parent changeset by calling :hg:`transplant --parent`.
559 proper parent changeset by calling :hg:`transplant --parent`.
561
560
562 If no merges or revisions are provided, :hg:`transplant` will
561 If no merges or revisions are provided, :hg:`transplant` will
563 start an interactive changeset browser.
562 start an interactive changeset browser.
564
563
565 If a changeset application fails, you can fix the merge by hand
564 If a changeset application fails, you can fix the merge by hand
566 and then resume where you left off by calling :hg:`transplant
565 and then resume where you left off by calling :hg:`transplant
567 --continue/-c`.
566 --continue/-c`.
568 '''
567 '''
569 def incwalk(repo, csets, match=util.always):
568 def incwalk(repo, csets, match=util.always):
570 for node in csets:
569 for node in csets:
571 if match(node):
570 if match(node):
572 yield node
571 yield node
573
572
574 def transplantwalk(repo, dest, heads, match=util.always):
573 def transplantwalk(repo, dest, heads, match=util.always):
575 '''Yield all nodes that are ancestors of a head but not ancestors
574 '''Yield all nodes that are ancestors of a head but not ancestors
576 of dest.
575 of dest.
577 If no heads are specified, the heads of repo will be used.'''
576 If no heads are specified, the heads of repo will be used.'''
578 if not heads:
577 if not heads:
579 heads = repo.heads()
578 heads = repo.heads()
580 ancestors = []
579 ancestors = []
581 ctx = repo[dest]
580 ctx = repo[dest]
582 for head in heads:
581 for head in heads:
583 ancestors.append(ctx.ancestor(repo[head]).node())
582 ancestors.append(ctx.ancestor(repo[head]).node())
584 for node in repo.changelog.nodesbetween(ancestors, heads)[0]:
583 for node in repo.changelog.nodesbetween(ancestors, heads)[0]:
585 if match(node):
584 if match(node):
586 yield node
585 yield node
587
586
588 def checkopts(opts, revs):
587 def checkopts(opts, revs):
589 if opts.get('continue'):
588 if opts.get('continue'):
590 if opts.get('branch') or opts.get('all') or opts.get('merge'):
589 if opts.get('branch') or opts.get('all') or opts.get('merge'):
591 raise util.Abort(_('--continue is incompatible with '
590 raise util.Abort(_('--continue is incompatible with '
592 '--branch, --all and --merge'))
591 '--branch, --all and --merge'))
593 return
592 return
594 if not (opts.get('source') or revs or
593 if not (opts.get('source') or revs or
595 opts.get('merge') or opts.get('branch')):
594 opts.get('merge') or opts.get('branch')):
596 raise util.Abort(_('no source URL, branch revision or revision '
595 raise util.Abort(_('no source URL, branch revision or revision '
597 'list provided'))
596 'list provided'))
598 if opts.get('all'):
597 if opts.get('all'):
599 if not opts.get('branch'):
598 if not opts.get('branch'):
600 raise util.Abort(_('--all requires a branch revision'))
599 raise util.Abort(_('--all requires a branch revision'))
601 if revs:
600 if revs:
602 raise util.Abort(_('--all is incompatible with a '
601 raise util.Abort(_('--all is incompatible with a '
603 'revision list'))
602 'revision list'))
604
603
605 checkopts(opts, revs)
604 checkopts(opts, revs)
606
605
607 if not opts.get('log'):
606 if not opts.get('log'):
608 opts['log'] = ui.config('transplant', 'log')
607 opts['log'] = ui.config('transplant', 'log')
609 if not opts.get('filter'):
608 if not opts.get('filter'):
610 opts['filter'] = ui.config('transplant', 'filter')
609 opts['filter'] = ui.config('transplant', 'filter')
611
610
612 tp = transplanter(ui, repo, opts)
611 tp = transplanter(ui, repo, opts)
613
612
614 cmdutil.checkunfinished(repo)
613 cmdutil.checkunfinished(repo)
615 p1, p2 = repo.dirstate.parents()
614 p1, p2 = repo.dirstate.parents()
616 if len(repo) > 0 and p1 == revlog.nullid:
615 if len(repo) > 0 and p1 == revlog.nullid:
617 raise util.Abort(_('no revision checked out'))
616 raise util.Abort(_('no revision checked out'))
618 if not opts.get('continue'):
617 if not opts.get('continue'):
619 if p2 != revlog.nullid:
618 if p2 != revlog.nullid:
620 raise util.Abort(_('outstanding uncommitted merges'))
619 raise util.Abort(_('outstanding uncommitted merges'))
621 m, a, r, d = repo.status()[:4]
620 m, a, r, d = repo.status()[:4]
622 if m or a or r or d:
621 if m or a or r or d:
623 raise util.Abort(_('outstanding local changes'))
622 raise util.Abort(_('outstanding local changes'))
624
623
625 sourcerepo = opts.get('source')
624 sourcerepo = opts.get('source')
626 if sourcerepo:
625 if sourcerepo:
627 peer = hg.peer(repo, opts, ui.expandpath(sourcerepo))
626 peer = hg.peer(repo, opts, ui.expandpath(sourcerepo))
628 heads = map(peer.lookup, opts.get('branch', ()))
627 heads = map(peer.lookup, opts.get('branch', ()))
629 source, csets, cleanupfn = bundlerepo.getremotechanges(ui, repo, peer,
628 source, csets, cleanupfn = bundlerepo.getremotechanges(ui, repo, peer,
630 onlyheads=heads, force=True)
629 onlyheads=heads, force=True)
631 else:
630 else:
632 source = repo
631 source = repo
633 heads = map(source.lookup, opts.get('branch', ()))
632 heads = map(source.lookup, opts.get('branch', ()))
634 cleanupfn = None
633 cleanupfn = None
635
634
636 try:
635 try:
637 if opts.get('continue'):
636 if opts.get('continue'):
638 tp.resume(repo, source, opts)
637 tp.resume(repo, source, opts)
639 return
638 return
640
639
641 tf = tp.transplantfilter(repo, source, p1)
640 tf = tp.transplantfilter(repo, source, p1)
642 if opts.get('prune'):
641 if opts.get('prune'):
643 prune = set(source.lookup(r)
642 prune = set(source.lookup(r)
644 for r in scmutil.revrange(source, opts.get('prune')))
643 for r in scmutil.revrange(source, opts.get('prune')))
645 matchfn = lambda x: tf(x) and x not in prune
644 matchfn = lambda x: tf(x) and x not in prune
646 else:
645 else:
647 matchfn = tf
646 matchfn = tf
648 merges = map(source.lookup, opts.get('merge', ()))
647 merges = map(source.lookup, opts.get('merge', ()))
649 revmap = {}
648 revmap = {}
650 if revs:
649 if revs:
651 for r in scmutil.revrange(source, revs):
650 for r in scmutil.revrange(source, revs):
652 revmap[int(r)] = source.lookup(r)
651 revmap[int(r)] = source.lookup(r)
653 elif opts.get('all') or not merges:
652 elif opts.get('all') or not merges:
654 if source != repo:
653 if source != repo:
655 alltransplants = incwalk(source, csets, match=matchfn)
654 alltransplants = incwalk(source, csets, match=matchfn)
656 else:
655 else:
657 alltransplants = transplantwalk(source, p1, heads,
656 alltransplants = transplantwalk(source, p1, heads,
658 match=matchfn)
657 match=matchfn)
659 if opts.get('all'):
658 if opts.get('all'):
660 revs = alltransplants
659 revs = alltransplants
661 else:
660 else:
662 revs, newmerges = browserevs(ui, source, alltransplants, opts)
661 revs, newmerges = browserevs(ui, source, alltransplants, opts)
663 merges.extend(newmerges)
662 merges.extend(newmerges)
664 for r in revs:
663 for r in revs:
665 revmap[source.changelog.rev(r)] = r
664 revmap[source.changelog.rev(r)] = r
666 for r in merges:
665 for r in merges:
667 revmap[source.changelog.rev(r)] = r
666 revmap[source.changelog.rev(r)] = r
668
667
669 tp.apply(repo, source, revmap, merges, opts)
668 tp.apply(repo, source, revmap, merges, opts)
670 finally:
669 finally:
671 if cleanupfn:
670 if cleanupfn:
672 cleanupfn()
671 cleanupfn()
673
672
674 def revsettransplanted(repo, subset, x):
673 def revsettransplanted(repo, subset, x):
675 """``transplanted([set])``
674 """``transplanted([set])``
676 Transplanted changesets in set, or all transplanted changesets.
675 Transplanted changesets in set, or all transplanted changesets.
677 """
676 """
678 if x:
677 if x:
679 s = revset.getset(repo, subset, x)
678 s = revset.getset(repo, subset, x)
680 else:
679 else:
681 s = subset
680 s = subset
682 return revset.baseset([r for r in s if
681 return revset.baseset([r for r in s if
683 repo[r].extra().get('transplant_source')])
682 repo[r].extra().get('transplant_source')])
684
683
685 def kwtransplanted(repo, ctx, **args):
684 def kwtransplanted(repo, ctx, **args):
686 """:transplanted: String. The node identifier of the transplanted
685 """:transplanted: String. The node identifier of the transplanted
687 changeset if any."""
686 changeset if any."""
688 n = ctx.extra().get('transplant_source')
687 n = ctx.extra().get('transplant_source')
689 return n and revlog.hex(n) or ''
688 return n and revlog.hex(n) or ''
690
689
691 def extsetup(ui):
690 def extsetup(ui):
692 revset.symbols['transplanted'] = revsettransplanted
691 revset.symbols['transplanted'] = revsettransplanted
693 templatekw.keywords['transplanted'] = kwtransplanted
692 templatekw.keywords['transplanted'] = kwtransplanted
694 cmdutil.unfinishedstates.append(
693 cmdutil.unfinishedstates.append(
695 ['series', True, False, _('transplant in progress'),
694 ['series', True, False, _('transplant in progress'),
696 _("use 'hg transplant --continue' or 'hg update' to abort")])
695 _("use 'hg transplant --continue' or 'hg update' to abort")])
697
696
698 # tell hggettext to extract docstrings from these functions:
697 # tell hggettext to extract docstrings from these functions:
699 i18nfunctions = [revsettransplanted, kwtransplanted]
698 i18nfunctions = [revsettransplanted, kwtransplanted]
@@ -1,6370 +1,6370 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 of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _
10 from i18n import _
11 import os, re, difflib, time, tempfile, errno, shlex
11 import os, re, difflib, time, tempfile, errno, shlex
12 import sys, socket
12 import sys, socket
13 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import hg, scmutil, util, revlog, copies, error, bookmarks
14 import patch, help, encoding, templatekw, discovery
14 import patch, help, encoding, templatekw, discovery
15 import archival, changegroup, cmdutil, hbisect
15 import archival, changegroup, cmdutil, hbisect
16 import sshserver, hgweb, commandserver
16 import sshserver, hgweb, commandserver
17 import extensions
17 import extensions
18 from hgweb import server as hgweb_server
18 from hgweb import server as hgweb_server
19 import merge as mergemod
19 import merge as mergemod
20 import minirst, revset, fileset
20 import minirst, revset, fileset
21 import dagparser, context, simplemerge, graphmod, copies
21 import dagparser, context, simplemerge, graphmod, copies
22 import random
22 import random
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
24 import phases, obsolete, exchange, bundle2
24 import phases, obsolete, exchange, bundle2
25 import ui as uimod
25 import ui as uimod
26
26
27 table = {}
27 table = {}
28
28
29 command = cmdutil.command(table)
29 command = cmdutil.command(table)
30
30
31 # Space delimited list of commands that don't require local repositories.
31 # Space delimited list of commands that don't require local repositories.
32 # This should be populated by passing norepo=True into the @command decorator.
32 # This should be populated by passing norepo=True into the @command decorator.
33 norepo = ''
33 norepo = ''
34 # Space delimited list of commands that optionally require local repositories.
34 # Space delimited list of commands that optionally require local repositories.
35 # This should be populated by passing optionalrepo=True into the @command
35 # This should be populated by passing optionalrepo=True into the @command
36 # decorator.
36 # decorator.
37 optionalrepo = ''
37 optionalrepo = ''
38 # Space delimited list of commands that will examine arguments looking for
38 # Space delimited list of commands that will examine arguments looking for
39 # a repository. This should be populated by passing inferrepo=True into the
39 # a repository. This should be populated by passing inferrepo=True into the
40 # @command decorator.
40 # @command decorator.
41 inferrepo = ''
41 inferrepo = ''
42
42
43 # common command options
43 # common command options
44
44
45 globalopts = [
45 globalopts = [
46 ('R', 'repository', '',
46 ('R', 'repository', '',
47 _('repository root directory or name of overlay bundle file'),
47 _('repository root directory or name of overlay bundle file'),
48 _('REPO')),
48 _('REPO')),
49 ('', 'cwd', '',
49 ('', 'cwd', '',
50 _('change working directory'), _('DIR')),
50 _('change working directory'), _('DIR')),
51 ('y', 'noninteractive', None,
51 ('y', 'noninteractive', None,
52 _('do not prompt, automatically pick the first choice for all prompts')),
52 _('do not prompt, automatically pick the first choice for all prompts')),
53 ('q', 'quiet', None, _('suppress output')),
53 ('q', 'quiet', None, _('suppress output')),
54 ('v', 'verbose', None, _('enable additional output')),
54 ('v', 'verbose', None, _('enable additional output')),
55 ('', 'config', [],
55 ('', 'config', [],
56 _('set/override config option (use \'section.name=value\')'),
56 _('set/override config option (use \'section.name=value\')'),
57 _('CONFIG')),
57 _('CONFIG')),
58 ('', 'debug', None, _('enable debugging output')),
58 ('', 'debug', None, _('enable debugging output')),
59 ('', 'debugger', None, _('start debugger')),
59 ('', 'debugger', None, _('start debugger')),
60 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
60 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
61 _('ENCODE')),
61 _('ENCODE')),
62 ('', 'encodingmode', encoding.encodingmode,
62 ('', 'encodingmode', encoding.encodingmode,
63 _('set the charset encoding mode'), _('MODE')),
63 _('set the charset encoding mode'), _('MODE')),
64 ('', 'traceback', None, _('always print a traceback on exception')),
64 ('', 'traceback', None, _('always print a traceback on exception')),
65 ('', 'time', None, _('time how long the command takes')),
65 ('', 'time', None, _('time how long the command takes')),
66 ('', 'profile', None, _('print command execution profile')),
66 ('', 'profile', None, _('print command execution profile')),
67 ('', 'version', None, _('output version information and exit')),
67 ('', 'version', None, _('output version information and exit')),
68 ('h', 'help', None, _('display help and exit')),
68 ('h', 'help', None, _('display help and exit')),
69 ('', 'hidden', False, _('consider hidden changesets')),
69 ('', 'hidden', False, _('consider hidden changesets')),
70 ]
70 ]
71
71
72 dryrunopts = [('n', 'dry-run', None,
72 dryrunopts = [('n', 'dry-run', None,
73 _('do not perform actions, just print output'))]
73 _('do not perform actions, just print output'))]
74
74
75 remoteopts = [
75 remoteopts = [
76 ('e', 'ssh', '',
76 ('e', 'ssh', '',
77 _('specify ssh command to use'), _('CMD')),
77 _('specify ssh command to use'), _('CMD')),
78 ('', 'remotecmd', '',
78 ('', 'remotecmd', '',
79 _('specify hg command to run on the remote side'), _('CMD')),
79 _('specify hg command to run on the remote side'), _('CMD')),
80 ('', 'insecure', None,
80 ('', 'insecure', None,
81 _('do not verify server certificate (ignoring web.cacerts config)')),
81 _('do not verify server certificate (ignoring web.cacerts config)')),
82 ]
82 ]
83
83
84 walkopts = [
84 walkopts = [
85 ('I', 'include', [],
85 ('I', 'include', [],
86 _('include names matching the given patterns'), _('PATTERN')),
86 _('include names matching the given patterns'), _('PATTERN')),
87 ('X', 'exclude', [],
87 ('X', 'exclude', [],
88 _('exclude names matching the given patterns'), _('PATTERN')),
88 _('exclude names matching the given patterns'), _('PATTERN')),
89 ]
89 ]
90
90
91 commitopts = [
91 commitopts = [
92 ('m', 'message', '',
92 ('m', 'message', '',
93 _('use text as commit message'), _('TEXT')),
93 _('use text as commit message'), _('TEXT')),
94 ('l', 'logfile', '',
94 ('l', 'logfile', '',
95 _('read commit message from file'), _('FILE')),
95 _('read commit message from file'), _('FILE')),
96 ]
96 ]
97
97
98 commitopts2 = [
98 commitopts2 = [
99 ('d', 'date', '',
99 ('d', 'date', '',
100 _('record the specified date as commit date'), _('DATE')),
100 _('record the specified date as commit date'), _('DATE')),
101 ('u', 'user', '',
101 ('u', 'user', '',
102 _('record the specified user as committer'), _('USER')),
102 _('record the specified user as committer'), _('USER')),
103 ]
103 ]
104
104
105 # hidden for now
105 # hidden for now
106 formatteropts = [
106 formatteropts = [
107 ('T', 'template', '',
107 ('T', 'template', '',
108 _('display with template (DEPRECATED)'), _('TEMPLATE')),
108 _('display with template (DEPRECATED)'), _('TEMPLATE')),
109 ]
109 ]
110
110
111 templateopts = [
111 templateopts = [
112 ('', 'style', '',
112 ('', 'style', '',
113 _('display using template map file (DEPRECATED)'), _('STYLE')),
113 _('display using template map file (DEPRECATED)'), _('STYLE')),
114 ('T', 'template', '',
114 ('T', 'template', '',
115 _('display with template'), _('TEMPLATE')),
115 _('display with template'), _('TEMPLATE')),
116 ]
116 ]
117
117
118 logopts = [
118 logopts = [
119 ('p', 'patch', None, _('show patch')),
119 ('p', 'patch', None, _('show patch')),
120 ('g', 'git', None, _('use git extended diff format')),
120 ('g', 'git', None, _('use git extended diff format')),
121 ('l', 'limit', '',
121 ('l', 'limit', '',
122 _('limit number of changes displayed'), _('NUM')),
122 _('limit number of changes displayed'), _('NUM')),
123 ('M', 'no-merges', None, _('do not show merges')),
123 ('M', 'no-merges', None, _('do not show merges')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
125 ('G', 'graph', None, _("show the revision DAG")),
125 ('G', 'graph', None, _("show the revision DAG")),
126 ] + templateopts
126 ] + templateopts
127
127
128 diffopts = [
128 diffopts = [
129 ('a', 'text', None, _('treat all files as text')),
129 ('a', 'text', None, _('treat all files as text')),
130 ('g', 'git', None, _('use git extended diff format')),
130 ('g', 'git', None, _('use git extended diff format')),
131 ('', 'nodates', None, _('omit dates from diff headers'))
131 ('', 'nodates', None, _('omit dates from diff headers'))
132 ]
132 ]
133
133
134 diffwsopts = [
134 diffwsopts = [
135 ('w', 'ignore-all-space', None,
135 ('w', 'ignore-all-space', None,
136 _('ignore white space when comparing lines')),
136 _('ignore white space when comparing lines')),
137 ('b', 'ignore-space-change', None,
137 ('b', 'ignore-space-change', None,
138 _('ignore changes in the amount of white space')),
138 _('ignore changes in the amount of white space')),
139 ('B', 'ignore-blank-lines', None,
139 ('B', 'ignore-blank-lines', None,
140 _('ignore changes whose lines are all blank')),
140 _('ignore changes whose lines are all blank')),
141 ]
141 ]
142
142
143 diffopts2 = [
143 diffopts2 = [
144 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
144 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
145 ('p', 'show-function', None, _('show which function each change is in')),
145 ('p', 'show-function', None, _('show which function each change is in')),
146 ('', 'reverse', None, _('produce a diff that undoes the changes')),
146 ('', 'reverse', None, _('produce a diff that undoes the changes')),
147 ] + diffwsopts + [
147 ] + diffwsopts + [
148 ('U', 'unified', '',
148 ('U', 'unified', '',
149 _('number of lines of context to show'), _('NUM')),
149 _('number of lines of context to show'), _('NUM')),
150 ('', 'stat', None, _('output diffstat-style summary of changes')),
150 ('', 'stat', None, _('output diffstat-style summary of changes')),
151 ]
151 ]
152
152
153 mergetoolopts = [
153 mergetoolopts = [
154 ('t', 'tool', '', _('specify merge tool')),
154 ('t', 'tool', '', _('specify merge tool')),
155 ]
155 ]
156
156
157 similarityopts = [
157 similarityopts = [
158 ('s', 'similarity', '',
158 ('s', 'similarity', '',
159 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
159 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
160 ]
160 ]
161
161
162 subrepoopts = [
162 subrepoopts = [
163 ('S', 'subrepos', None,
163 ('S', 'subrepos', None,
164 _('recurse into subrepositories'))
164 _('recurse into subrepositories'))
165 ]
165 ]
166
166
167 # Commands start here, listed alphabetically
167 # Commands start here, listed alphabetically
168
168
169 @command('^add',
169 @command('^add',
170 walkopts + subrepoopts + dryrunopts,
170 walkopts + subrepoopts + dryrunopts,
171 _('[OPTION]... [FILE]...'),
171 _('[OPTION]... [FILE]...'),
172 inferrepo=True)
172 inferrepo=True)
173 def add(ui, repo, *pats, **opts):
173 def add(ui, repo, *pats, **opts):
174 """add the specified files on the next commit
174 """add the specified files on the next commit
175
175
176 Schedule files to be version controlled and added to the
176 Schedule files to be version controlled and added to the
177 repository.
177 repository.
178
178
179 The files will be added to the repository at the next commit. To
179 The files will be added to the repository at the next commit. To
180 undo an add before that, see :hg:`forget`.
180 undo an add before that, see :hg:`forget`.
181
181
182 If no names are given, add all files to the repository.
182 If no names are given, add all files to the repository.
183
183
184 .. container:: verbose
184 .. container:: verbose
185
185
186 An example showing how new (unknown) files are added
186 An example showing how new (unknown) files are added
187 automatically by :hg:`add`::
187 automatically by :hg:`add`::
188
188
189 $ ls
189 $ ls
190 foo.c
190 foo.c
191 $ hg status
191 $ hg status
192 ? foo.c
192 ? foo.c
193 $ hg add
193 $ hg add
194 adding foo.c
194 adding foo.c
195 $ hg status
195 $ hg status
196 A foo.c
196 A foo.c
197
197
198 Returns 0 if all files are successfully added.
198 Returns 0 if all files are successfully added.
199 """
199 """
200
200
201 m = scmutil.match(repo[None], pats, opts)
201 m = scmutil.match(repo[None], pats, opts)
202 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
202 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
203 return rejected and 1 or 0
203 return rejected and 1 or 0
204
204
205 @command('addremove',
205 @command('addremove',
206 similarityopts + subrepoopts + walkopts + dryrunopts,
206 similarityopts + subrepoopts + walkopts + dryrunopts,
207 _('[OPTION]... [FILE]...'),
207 _('[OPTION]... [FILE]...'),
208 inferrepo=True)
208 inferrepo=True)
209 def addremove(ui, repo, *pats, **opts):
209 def addremove(ui, repo, *pats, **opts):
210 """add all new files, delete all missing files
210 """add all new files, delete all missing files
211
211
212 Add all new files and remove all missing files from the
212 Add all new files and remove all missing files from the
213 repository.
213 repository.
214
214
215 New files are ignored if they match any of the patterns in
215 New files are ignored if they match any of the patterns in
216 ``.hgignore``. As with add, these changes take effect at the next
216 ``.hgignore``. As with add, these changes take effect at the next
217 commit.
217 commit.
218
218
219 Use the -s/--similarity option to detect renamed files. This
219 Use the -s/--similarity option to detect renamed files. This
220 option takes a percentage between 0 (disabled) and 100 (files must
220 option takes a percentage between 0 (disabled) and 100 (files must
221 be identical) as its parameter. With a parameter greater than 0,
221 be identical) as its parameter. With a parameter greater than 0,
222 this compares every removed file with every added file and records
222 this compares every removed file with every added file and records
223 those similar enough as renames. Detecting renamed files this way
223 those similar enough as renames. Detecting renamed files this way
224 can be expensive. After using this option, :hg:`status -C` can be
224 can be expensive. After using this option, :hg:`status -C` can be
225 used to check which files were identified as moved or renamed. If
225 used to check which files were identified as moved or renamed. If
226 not specified, -s/--similarity defaults to 100 and only renames of
226 not specified, -s/--similarity defaults to 100 and only renames of
227 identical files are detected.
227 identical files are detected.
228
228
229 Returns 0 if all files are successfully added.
229 Returns 0 if all files are successfully added.
230 """
230 """
231 try:
231 try:
232 sim = float(opts.get('similarity') or 100)
232 sim = float(opts.get('similarity') or 100)
233 except ValueError:
233 except ValueError:
234 raise util.Abort(_('similarity must be a number'))
234 raise util.Abort(_('similarity must be a number'))
235 if sim < 0 or sim > 100:
235 if sim < 0 or sim > 100:
236 raise util.Abort(_('similarity must be between 0 and 100'))
236 raise util.Abort(_('similarity must be between 0 and 100'))
237 matcher = scmutil.match(repo[None], pats, opts)
237 matcher = scmutil.match(repo[None], pats, opts)
238 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
238 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
239
239
240 @command('^annotate|blame',
240 @command('^annotate|blame',
241 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
241 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
242 ('', 'follow', None,
242 ('', 'follow', None,
243 _('follow copies/renames and list the filename (DEPRECATED)')),
243 _('follow copies/renames and list the filename (DEPRECATED)')),
244 ('', 'no-follow', None, _("don't follow copies and renames")),
244 ('', 'no-follow', None, _("don't follow copies and renames")),
245 ('a', 'text', None, _('treat all files as text')),
245 ('a', 'text', None, _('treat all files as text')),
246 ('u', 'user', None, _('list the author (long with -v)')),
246 ('u', 'user', None, _('list the author (long with -v)')),
247 ('f', 'file', None, _('list the filename')),
247 ('f', 'file', None, _('list the filename')),
248 ('d', 'date', None, _('list the date (short with -q)')),
248 ('d', 'date', None, _('list the date (short with -q)')),
249 ('n', 'number', None, _('list the revision number (default)')),
249 ('n', 'number', None, _('list the revision number (default)')),
250 ('c', 'changeset', None, _('list the changeset')),
250 ('c', 'changeset', None, _('list the changeset')),
251 ('l', 'line-number', None, _('show line number at the first appearance'))
251 ('l', 'line-number', None, _('show line number at the first appearance'))
252 ] + diffwsopts + walkopts + formatteropts,
252 ] + diffwsopts + walkopts + formatteropts,
253 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
253 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
254 inferrepo=True)
254 inferrepo=True)
255 def annotate(ui, repo, *pats, **opts):
255 def annotate(ui, repo, *pats, **opts):
256 """show changeset information by line for each file
256 """show changeset information by line for each file
257
257
258 List changes in files, showing the revision id responsible for
258 List changes in files, showing the revision id responsible for
259 each line
259 each line
260
260
261 This command is useful for discovering when a change was made and
261 This command is useful for discovering when a change was made and
262 by whom.
262 by whom.
263
263
264 Without the -a/--text option, annotate will avoid processing files
264 Without the -a/--text option, annotate will avoid processing files
265 it detects as binary. With -a, annotate will annotate the file
265 it detects as binary. With -a, annotate will annotate the file
266 anyway, although the results will probably be neither useful
266 anyway, although the results will probably be neither useful
267 nor desirable.
267 nor desirable.
268
268
269 Returns 0 on success.
269 Returns 0 on success.
270 """
270 """
271 if not pats:
271 if not pats:
272 raise util.Abort(_('at least one filename or pattern is required'))
272 raise util.Abort(_('at least one filename or pattern is required'))
273
273
274 if opts.get('follow'):
274 if opts.get('follow'):
275 # --follow is deprecated and now just an alias for -f/--file
275 # --follow is deprecated and now just an alias for -f/--file
276 # to mimic the behavior of Mercurial before version 1.5
276 # to mimic the behavior of Mercurial before version 1.5
277 opts['file'] = True
277 opts['file'] = True
278
278
279 fm = ui.formatter('annotate', opts)
279 fm = ui.formatter('annotate', opts)
280 if ui.quiet:
280 if ui.quiet:
281 datefunc = util.shortdate
281 datefunc = util.shortdate
282 else:
282 else:
283 datefunc = util.datestr
283 datefunc = util.datestr
284 hexfn = fm.hexfunc
284 hexfn = fm.hexfunc
285
285
286 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
286 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
287 ('number', ' ', lambda x: x[0].rev(), str),
287 ('number', ' ', lambda x: x[0].rev(), str),
288 ('changeset', ' ', lambda x: hexfn(x[0].node()), str),
288 ('changeset', ' ', lambda x: hexfn(x[0].node()), str),
289 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
289 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
290 ('file', ' ', lambda x: x[0].path(), str),
290 ('file', ' ', lambda x: x[0].path(), str),
291 ('line_number', ':', lambda x: x[1], str),
291 ('line_number', ':', lambda x: x[1], str),
292 ]
292 ]
293 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
293 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
294
294
295 if (not opts.get('user') and not opts.get('changeset')
295 if (not opts.get('user') and not opts.get('changeset')
296 and not opts.get('date') and not opts.get('file')):
296 and not opts.get('date') and not opts.get('file')):
297 opts['number'] = True
297 opts['number'] = True
298
298
299 linenumber = opts.get('line_number') is not None
299 linenumber = opts.get('line_number') is not None
300 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
300 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
301 raise util.Abort(_('at least one of -n/-c is required for -l'))
301 raise util.Abort(_('at least one of -n/-c is required for -l'))
302
302
303 if fm:
303 if fm:
304 def makefunc(get, fmt):
304 def makefunc(get, fmt):
305 return get
305 return get
306 else:
306 else:
307 def makefunc(get, fmt):
307 def makefunc(get, fmt):
308 return lambda x: fmt(get(x))
308 return lambda x: fmt(get(x))
309 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
309 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
310 if opts.get(op)]
310 if opts.get(op)]
311 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
311 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
312 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
312 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
313 if opts.get(op))
313 if opts.get(op))
314
314
315 def bad(x, y):
315 def bad(x, y):
316 raise util.Abort("%s: %s" % (x, y))
316 raise util.Abort("%s: %s" % (x, y))
317
317
318 ctx = scmutil.revsingle(repo, opts.get('rev'))
318 ctx = scmutil.revsingle(repo, opts.get('rev'))
319 m = scmutil.match(ctx, pats, opts)
319 m = scmutil.match(ctx, pats, opts)
320 m.bad = bad
320 m.bad = bad
321 follow = not opts.get('no_follow')
321 follow = not opts.get('no_follow')
322 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
322 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
323 whitespace=True)
323 whitespace=True)
324 for abs in ctx.walk(m):
324 for abs in ctx.walk(m):
325 fctx = ctx[abs]
325 fctx = ctx[abs]
326 if not opts.get('text') and util.binary(fctx.data()):
326 if not opts.get('text') and util.binary(fctx.data()):
327 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
327 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
328 continue
328 continue
329
329
330 lines = fctx.annotate(follow=follow, linenumber=linenumber,
330 lines = fctx.annotate(follow=follow, linenumber=linenumber,
331 diffopts=diffopts)
331 diffopts=diffopts)
332 formats = []
332 formats = []
333 pieces = []
333 pieces = []
334
334
335 for f, sep in funcmap:
335 for f, sep in funcmap:
336 l = [f(n) for n, dummy in lines]
336 l = [f(n) for n, dummy in lines]
337 if l:
337 if l:
338 if fm:
338 if fm:
339 formats.append(['%s' for x in l])
339 formats.append(['%s' for x in l])
340 else:
340 else:
341 sizes = [encoding.colwidth(x) for x in l]
341 sizes = [encoding.colwidth(x) for x in l]
342 ml = max(sizes)
342 ml = max(sizes)
343 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
343 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
344 pieces.append(l)
344 pieces.append(l)
345
345
346 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
346 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
347 fm.startitem()
347 fm.startitem()
348 fm.write(fields, "".join(f), *p)
348 fm.write(fields, "".join(f), *p)
349 fm.write('line', ": %s", l[1])
349 fm.write('line', ": %s", l[1])
350
350
351 if lines and not lines[-1][1].endswith('\n'):
351 if lines and not lines[-1][1].endswith('\n'):
352 fm.plain('\n')
352 fm.plain('\n')
353
353
354 fm.end()
354 fm.end()
355
355
356 @command('archive',
356 @command('archive',
357 [('', 'no-decode', None, _('do not pass files through decoders')),
357 [('', 'no-decode', None, _('do not pass files through decoders')),
358 ('p', 'prefix', '', _('directory prefix for files in archive'),
358 ('p', 'prefix', '', _('directory prefix for files in archive'),
359 _('PREFIX')),
359 _('PREFIX')),
360 ('r', 'rev', '', _('revision to distribute'), _('REV')),
360 ('r', 'rev', '', _('revision to distribute'), _('REV')),
361 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
361 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
362 ] + subrepoopts + walkopts,
362 ] + subrepoopts + walkopts,
363 _('[OPTION]... DEST'))
363 _('[OPTION]... DEST'))
364 def archive(ui, repo, dest, **opts):
364 def archive(ui, repo, dest, **opts):
365 '''create an unversioned archive of a repository revision
365 '''create an unversioned archive of a repository revision
366
366
367 By default, the revision used is the parent of the working
367 By default, the revision used is the parent of the working
368 directory; use -r/--rev to specify a different revision.
368 directory; use -r/--rev to specify a different revision.
369
369
370 The archive type is automatically detected based on file
370 The archive type is automatically detected based on file
371 extension (or override using -t/--type).
371 extension (or override using -t/--type).
372
372
373 .. container:: verbose
373 .. container:: verbose
374
374
375 Examples:
375 Examples:
376
376
377 - create a zip file containing the 1.0 release::
377 - create a zip file containing the 1.0 release::
378
378
379 hg archive -r 1.0 project-1.0.zip
379 hg archive -r 1.0 project-1.0.zip
380
380
381 - create a tarball excluding .hg files::
381 - create a tarball excluding .hg files::
382
382
383 hg archive project.tar.gz -X ".hg*"
383 hg archive project.tar.gz -X ".hg*"
384
384
385 Valid types are:
385 Valid types are:
386
386
387 :``files``: a directory full of files (default)
387 :``files``: a directory full of files (default)
388 :``tar``: tar archive, uncompressed
388 :``tar``: tar archive, uncompressed
389 :``tbz2``: tar archive, compressed using bzip2
389 :``tbz2``: tar archive, compressed using bzip2
390 :``tgz``: tar archive, compressed using gzip
390 :``tgz``: tar archive, compressed using gzip
391 :``uzip``: zip archive, uncompressed
391 :``uzip``: zip archive, uncompressed
392 :``zip``: zip archive, compressed using deflate
392 :``zip``: zip archive, compressed using deflate
393
393
394 The exact name of the destination archive or directory is given
394 The exact name of the destination archive or directory is given
395 using a format string; see :hg:`help export` for details.
395 using a format string; see :hg:`help export` for details.
396
396
397 Each member added to an archive file has a directory prefix
397 Each member added to an archive file has a directory prefix
398 prepended. Use -p/--prefix to specify a format string for the
398 prepended. Use -p/--prefix to specify a format string for the
399 prefix. The default is the basename of the archive, with suffixes
399 prefix. The default is the basename of the archive, with suffixes
400 removed.
400 removed.
401
401
402 Returns 0 on success.
402 Returns 0 on success.
403 '''
403 '''
404
404
405 ctx = scmutil.revsingle(repo, opts.get('rev'))
405 ctx = scmutil.revsingle(repo, opts.get('rev'))
406 if not ctx:
406 if not ctx:
407 raise util.Abort(_('no working directory: please specify a revision'))
407 raise util.Abort(_('no working directory: please specify a revision'))
408 node = ctx.node()
408 node = ctx.node()
409 dest = cmdutil.makefilename(repo, dest, node)
409 dest = cmdutil.makefilename(repo, dest, node)
410 if os.path.realpath(dest) == repo.root:
410 if os.path.realpath(dest) == repo.root:
411 raise util.Abort(_('repository root cannot be destination'))
411 raise util.Abort(_('repository root cannot be destination'))
412
412
413 kind = opts.get('type') or archival.guesskind(dest) or 'files'
413 kind = opts.get('type') or archival.guesskind(dest) or 'files'
414 prefix = opts.get('prefix')
414 prefix = opts.get('prefix')
415
415
416 if dest == '-':
416 if dest == '-':
417 if kind == 'files':
417 if kind == 'files':
418 raise util.Abort(_('cannot archive plain files to stdout'))
418 raise util.Abort(_('cannot archive plain files to stdout'))
419 dest = cmdutil.makefileobj(repo, dest)
419 dest = cmdutil.makefileobj(repo, dest)
420 if not prefix:
420 if not prefix:
421 prefix = os.path.basename(repo.root) + '-%h'
421 prefix = os.path.basename(repo.root) + '-%h'
422
422
423 prefix = cmdutil.makefilename(repo, prefix, node)
423 prefix = cmdutil.makefilename(repo, prefix, node)
424 matchfn = scmutil.match(ctx, [], opts)
424 matchfn = scmutil.match(ctx, [], opts)
425 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
425 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
426 matchfn, prefix, subrepos=opts.get('subrepos'))
426 matchfn, prefix, subrepos=opts.get('subrepos'))
427
427
428 @command('backout',
428 @command('backout',
429 [('', 'merge', None, _('merge with old dirstate parent after backout')),
429 [('', 'merge', None, _('merge with old dirstate parent after backout')),
430 ('', 'commit', None, _('commit if no conflicts were encountered')),
430 ('', 'commit', None, _('commit if no conflicts were encountered')),
431 ('', 'parent', '',
431 ('', 'parent', '',
432 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
432 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
433 ('r', 'rev', '', _('revision to backout'), _('REV')),
433 ('r', 'rev', '', _('revision to backout'), _('REV')),
434 ('e', 'edit', False, _('invoke editor on commit messages')),
434 ('e', 'edit', False, _('invoke editor on commit messages')),
435 ] + mergetoolopts + walkopts + commitopts + commitopts2,
435 ] + mergetoolopts + walkopts + commitopts + commitopts2,
436 _('[OPTION]... [-r] REV'))
436 _('[OPTION]... [-r] REV'))
437 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
437 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
438 '''reverse effect of earlier changeset
438 '''reverse effect of earlier changeset
439
439
440 Prepare a new changeset with the effect of REV undone in the
440 Prepare a new changeset with the effect of REV undone in the
441 current working directory.
441 current working directory.
442
442
443 If REV is the parent of the working directory, then this new changeset
443 If REV is the parent of the working directory, then this new changeset
444 is committed automatically. Otherwise, hg needs to merge the
444 is committed automatically. Otherwise, hg needs to merge the
445 changes and the merged result is left uncommitted.
445 changes and the merged result is left uncommitted.
446
446
447 .. note::
447 .. note::
448
448
449 backout cannot be used to fix either an unwanted or
449 backout cannot be used to fix either an unwanted or
450 incorrect merge.
450 incorrect merge.
451
451
452 .. container:: verbose
452 .. container:: verbose
453
453
454 By default, the pending changeset will have one parent,
454 By default, the pending changeset will have one parent,
455 maintaining a linear history. With --merge, the pending
455 maintaining a linear history. With --merge, the pending
456 changeset will instead have two parents: the old parent of the
456 changeset will instead have two parents: the old parent of the
457 working directory and a new child of REV that simply undoes REV.
457 working directory and a new child of REV that simply undoes REV.
458
458
459 Before version 1.7, the behavior without --merge was equivalent
459 Before version 1.7, the behavior without --merge was equivalent
460 to specifying --merge followed by :hg:`update --clean .` to
460 to specifying --merge followed by :hg:`update --clean .` to
461 cancel the merge and leave the child of REV as a head to be
461 cancel the merge and leave the child of REV as a head to be
462 merged separately.
462 merged separately.
463
463
464 See :hg:`help dates` for a list of formats valid for -d/--date.
464 See :hg:`help dates` for a list of formats valid for -d/--date.
465
465
466 Returns 0 on success, 1 if nothing to backout or there are unresolved
466 Returns 0 on success, 1 if nothing to backout or there are unresolved
467 files.
467 files.
468 '''
468 '''
469 if rev and node:
469 if rev and node:
470 raise util.Abort(_("please specify just one revision"))
470 raise util.Abort(_("please specify just one revision"))
471
471
472 if not rev:
472 if not rev:
473 rev = node
473 rev = node
474
474
475 if not rev:
475 if not rev:
476 raise util.Abort(_("please specify a revision to backout"))
476 raise util.Abort(_("please specify a revision to backout"))
477
477
478 date = opts.get('date')
478 date = opts.get('date')
479 if date:
479 if date:
480 opts['date'] = util.parsedate(date)
480 opts['date'] = util.parsedate(date)
481
481
482 cmdutil.checkunfinished(repo)
482 cmdutil.checkunfinished(repo)
483 cmdutil.bailifchanged(repo)
483 cmdutil.bailifchanged(repo)
484 node = scmutil.revsingle(repo, rev).node()
484 node = scmutil.revsingle(repo, rev).node()
485
485
486 op1, op2 = repo.dirstate.parents()
486 op1, op2 = repo.dirstate.parents()
487 if not repo.changelog.isancestor(node, op1):
487 if not repo.changelog.isancestor(node, op1):
488 raise util.Abort(_('cannot backout change that is not an ancestor'))
488 raise util.Abort(_('cannot backout change that is not an ancestor'))
489
489
490 p1, p2 = repo.changelog.parents(node)
490 p1, p2 = repo.changelog.parents(node)
491 if p1 == nullid:
491 if p1 == nullid:
492 raise util.Abort(_('cannot backout a change with no parents'))
492 raise util.Abort(_('cannot backout a change with no parents'))
493 if p2 != nullid:
493 if p2 != nullid:
494 if not opts.get('parent'):
494 if not opts.get('parent'):
495 raise util.Abort(_('cannot backout a merge changeset'))
495 raise util.Abort(_('cannot backout a merge changeset'))
496 p = repo.lookup(opts['parent'])
496 p = repo.lookup(opts['parent'])
497 if p not in (p1, p2):
497 if p not in (p1, p2):
498 raise util.Abort(_('%s is not a parent of %s') %
498 raise util.Abort(_('%s is not a parent of %s') %
499 (short(p), short(node)))
499 (short(p), short(node)))
500 parent = p
500 parent = p
501 else:
501 else:
502 if opts.get('parent'):
502 if opts.get('parent'):
503 raise util.Abort(_('cannot use --parent on non-merge changeset'))
503 raise util.Abort(_('cannot use --parent on non-merge changeset'))
504 parent = p1
504 parent = p1
505
505
506 # the backout should appear on the same branch
506 # the backout should appear on the same branch
507 wlock = repo.wlock()
507 wlock = repo.wlock()
508 try:
508 try:
509 branch = repo.dirstate.branch()
509 branch = repo.dirstate.branch()
510 bheads = repo.branchheads(branch)
510 bheads = repo.branchheads(branch)
511 rctx = scmutil.revsingle(repo, hex(parent))
511 rctx = scmutil.revsingle(repo, hex(parent))
512 if not opts.get('merge') and op1 != node:
512 if not opts.get('merge') and op1 != node:
513 try:
513 try:
514 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
514 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
515 'backout')
515 'backout')
516 repo.dirstate.beginparentchange()
516 repo.dirstate.beginparentchange()
517 stats = mergemod.update(repo, parent, True, True, False,
517 stats = mergemod.update(repo, parent, True, True, False,
518 node, False)
518 node, False)
519 repo.setparents(op1, op2)
519 repo.setparents(op1, op2)
520 repo.dirstate.endparentchange()
520 repo.dirstate.endparentchange()
521 hg._showstats(repo, stats)
521 hg._showstats(repo, stats)
522 if stats[3]:
522 if stats[3]:
523 repo.ui.status(_("use 'hg resolve' to retry unresolved "
523 repo.ui.status(_("use 'hg resolve' to retry unresolved "
524 "file merges\n"))
524 "file merges\n"))
525 return 1
525 return 1
526 elif not commit:
526 elif not commit:
527 msg = _("changeset %s backed out, "
527 msg = _("changeset %s backed out, "
528 "don't forget to commit.\n")
528 "don't forget to commit.\n")
529 ui.status(msg % short(node))
529 ui.status(msg % short(node))
530 return 0
530 return 0
531 finally:
531 finally:
532 ui.setconfig('ui', 'forcemerge', '', '')
532 ui.setconfig('ui', 'forcemerge', '', '')
533 else:
533 else:
534 hg.clean(repo, node, show_stats=False)
534 hg.clean(repo, node, show_stats=False)
535 repo.dirstate.setbranch(branch)
535 repo.dirstate.setbranch(branch)
536 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
536 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
537
537
538
538
539 def commitfunc(ui, repo, message, match, opts):
539 def commitfunc(ui, repo, message, match, opts):
540 editform = 'backout'
540 editform = 'backout'
541 e = cmdutil.getcommiteditor(editform=editform, **opts)
541 e = cmdutil.getcommiteditor(editform=editform, **opts)
542 if not message:
542 if not message:
543 # we don't translate commit messages
543 # we don't translate commit messages
544 message = "Backed out changeset %s" % short(node)
544 message = "Backed out changeset %s" % short(node)
545 e = cmdutil.getcommiteditor(edit=True, editform=editform)
545 e = cmdutil.getcommiteditor(edit=True, editform=editform)
546 return repo.commit(message, opts.get('user'), opts.get('date'),
546 return repo.commit(message, opts.get('user'), opts.get('date'),
547 match, editor=e)
547 match, editor=e)
548 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
548 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
549 if not newnode:
549 if not newnode:
550 ui.status(_("nothing changed\n"))
550 ui.status(_("nothing changed\n"))
551 return 1
551 return 1
552 cmdutil.commitstatus(repo, newnode, branch, bheads)
552 cmdutil.commitstatus(repo, newnode, branch, bheads)
553
553
554 def nice(node):
554 def nice(node):
555 return '%d:%s' % (repo.changelog.rev(node), short(node))
555 return '%d:%s' % (repo.changelog.rev(node), short(node))
556 ui.status(_('changeset %s backs out changeset %s\n') %
556 ui.status(_('changeset %s backs out changeset %s\n') %
557 (nice(repo.changelog.tip()), nice(node)))
557 (nice(repo.changelog.tip()), nice(node)))
558 if opts.get('merge') and op1 != node:
558 if opts.get('merge') and op1 != node:
559 hg.clean(repo, op1, show_stats=False)
559 hg.clean(repo, op1, show_stats=False)
560 ui.status(_('merging with changeset %s\n')
560 ui.status(_('merging with changeset %s\n')
561 % nice(repo.changelog.tip()))
561 % nice(repo.changelog.tip()))
562 try:
562 try:
563 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
563 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
564 'backout')
564 'backout')
565 return hg.merge(repo, hex(repo.changelog.tip()))
565 return hg.merge(repo, hex(repo.changelog.tip()))
566 finally:
566 finally:
567 ui.setconfig('ui', 'forcemerge', '', '')
567 ui.setconfig('ui', 'forcemerge', '', '')
568 finally:
568 finally:
569 wlock.release()
569 wlock.release()
570 return 0
570 return 0
571
571
572 @command('bisect',
572 @command('bisect',
573 [('r', 'reset', False, _('reset bisect state')),
573 [('r', 'reset', False, _('reset bisect state')),
574 ('g', 'good', False, _('mark changeset good')),
574 ('g', 'good', False, _('mark changeset good')),
575 ('b', 'bad', False, _('mark changeset bad')),
575 ('b', 'bad', False, _('mark changeset bad')),
576 ('s', 'skip', False, _('skip testing changeset')),
576 ('s', 'skip', False, _('skip testing changeset')),
577 ('e', 'extend', False, _('extend the bisect range')),
577 ('e', 'extend', False, _('extend the bisect range')),
578 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
578 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
579 ('U', 'noupdate', False, _('do not update to target'))],
579 ('U', 'noupdate', False, _('do not update to target'))],
580 _("[-gbsr] [-U] [-c CMD] [REV]"))
580 _("[-gbsr] [-U] [-c CMD] [REV]"))
581 def bisect(ui, repo, rev=None, extra=None, command=None,
581 def bisect(ui, repo, rev=None, extra=None, command=None,
582 reset=None, good=None, bad=None, skip=None, extend=None,
582 reset=None, good=None, bad=None, skip=None, extend=None,
583 noupdate=None):
583 noupdate=None):
584 """subdivision search of changesets
584 """subdivision search of changesets
585
585
586 This command helps to find changesets which introduce problems. To
586 This command helps to find changesets which introduce problems. To
587 use, mark the earliest changeset you know exhibits the problem as
587 use, mark the earliest changeset you know exhibits the problem as
588 bad, then mark the latest changeset which is free from the problem
588 bad, then mark the latest changeset which is free from the problem
589 as good. Bisect will update your working directory to a revision
589 as good. Bisect will update your working directory to a revision
590 for testing (unless the -U/--noupdate option is specified). Once
590 for testing (unless the -U/--noupdate option is specified). Once
591 you have performed tests, mark the working directory as good or
591 you have performed tests, mark the working directory as good or
592 bad, and bisect will either update to another candidate changeset
592 bad, and bisect will either update to another candidate changeset
593 or announce that it has found the bad revision.
593 or announce that it has found the bad revision.
594
594
595 As a shortcut, you can also use the revision argument to mark a
595 As a shortcut, you can also use the revision argument to mark a
596 revision as good or bad without checking it out first.
596 revision as good or bad without checking it out first.
597
597
598 If you supply a command, it will be used for automatic bisection.
598 If you supply a command, it will be used for automatic bisection.
599 The environment variable HG_NODE will contain the ID of the
599 The environment variable HG_NODE will contain the ID of the
600 changeset being tested. The exit status of the command will be
600 changeset being tested. The exit status of the command will be
601 used to mark revisions as good or bad: status 0 means good, 125
601 used to mark revisions as good or bad: status 0 means good, 125
602 means to skip the revision, 127 (command not found) will abort the
602 means to skip the revision, 127 (command not found) will abort the
603 bisection, and any other non-zero exit status means the revision
603 bisection, and any other non-zero exit status means the revision
604 is bad.
604 is bad.
605
605
606 .. container:: verbose
606 .. container:: verbose
607
607
608 Some examples:
608 Some examples:
609
609
610 - start a bisection with known bad revision 34, and good revision 12::
610 - start a bisection with known bad revision 34, and good revision 12::
611
611
612 hg bisect --bad 34
612 hg bisect --bad 34
613 hg bisect --good 12
613 hg bisect --good 12
614
614
615 - advance the current bisection by marking current revision as good or
615 - advance the current bisection by marking current revision as good or
616 bad::
616 bad::
617
617
618 hg bisect --good
618 hg bisect --good
619 hg bisect --bad
619 hg bisect --bad
620
620
621 - mark the current revision, or a known revision, to be skipped (e.g. if
621 - mark the current revision, or a known revision, to be skipped (e.g. if
622 that revision is not usable because of another issue)::
622 that revision is not usable because of another issue)::
623
623
624 hg bisect --skip
624 hg bisect --skip
625 hg bisect --skip 23
625 hg bisect --skip 23
626
626
627 - skip all revisions that do not touch directories ``foo`` or ``bar``::
627 - skip all revisions that do not touch directories ``foo`` or ``bar``::
628
628
629 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
629 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
630
630
631 - forget the current bisection::
631 - forget the current bisection::
632
632
633 hg bisect --reset
633 hg bisect --reset
634
634
635 - use 'make && make tests' to automatically find the first broken
635 - use 'make && make tests' to automatically find the first broken
636 revision::
636 revision::
637
637
638 hg bisect --reset
638 hg bisect --reset
639 hg bisect --bad 34
639 hg bisect --bad 34
640 hg bisect --good 12
640 hg bisect --good 12
641 hg bisect --command "make && make tests"
641 hg bisect --command "make && make tests"
642
642
643 - see all changesets whose states are already known in the current
643 - see all changesets whose states are already known in the current
644 bisection::
644 bisection::
645
645
646 hg log -r "bisect(pruned)"
646 hg log -r "bisect(pruned)"
647
647
648 - see the changeset currently being bisected (especially useful
648 - see the changeset currently being bisected (especially useful
649 if running with -U/--noupdate)::
649 if running with -U/--noupdate)::
650
650
651 hg log -r "bisect(current)"
651 hg log -r "bisect(current)"
652
652
653 - see all changesets that took part in the current bisection::
653 - see all changesets that took part in the current bisection::
654
654
655 hg log -r "bisect(range)"
655 hg log -r "bisect(range)"
656
656
657 - you can even get a nice graph::
657 - you can even get a nice graph::
658
658
659 hg log --graph -r "bisect(range)"
659 hg log --graph -r "bisect(range)"
660
660
661 See :hg:`help revsets` for more about the `bisect()` keyword.
661 See :hg:`help revsets` for more about the `bisect()` keyword.
662
662
663 Returns 0 on success.
663 Returns 0 on success.
664 """
664 """
665 def extendbisectrange(nodes, good):
665 def extendbisectrange(nodes, good):
666 # bisect is incomplete when it ends on a merge node and
666 # bisect is incomplete when it ends on a merge node and
667 # one of the parent was not checked.
667 # one of the parent was not checked.
668 parents = repo[nodes[0]].parents()
668 parents = repo[nodes[0]].parents()
669 if len(parents) > 1:
669 if len(parents) > 1:
670 if good:
670 if good:
671 side = state['bad']
671 side = state['bad']
672 else:
672 else:
673 side = state['good']
673 side = state['good']
674 num = len(set(i.node() for i in parents) & set(side))
674 num = len(set(i.node() for i in parents) & set(side))
675 if num == 1:
675 if num == 1:
676 return parents[0].ancestor(parents[1])
676 return parents[0].ancestor(parents[1])
677 return None
677 return None
678
678
679 def print_result(nodes, good):
679 def print_result(nodes, good):
680 displayer = cmdutil.show_changeset(ui, repo, {})
680 displayer = cmdutil.show_changeset(ui, repo, {})
681 if len(nodes) == 1:
681 if len(nodes) == 1:
682 # narrowed it down to a single revision
682 # narrowed it down to a single revision
683 if good:
683 if good:
684 ui.write(_("The first good revision is:\n"))
684 ui.write(_("The first good revision is:\n"))
685 else:
685 else:
686 ui.write(_("The first bad revision is:\n"))
686 ui.write(_("The first bad revision is:\n"))
687 displayer.show(repo[nodes[0]])
687 displayer.show(repo[nodes[0]])
688 extendnode = extendbisectrange(nodes, good)
688 extendnode = extendbisectrange(nodes, good)
689 if extendnode is not None:
689 if extendnode is not None:
690 ui.write(_('Not all ancestors of this changeset have been'
690 ui.write(_('Not all ancestors of this changeset have been'
691 ' checked.\nUse bisect --extend to continue the '
691 ' checked.\nUse bisect --extend to continue the '
692 'bisection from\nthe common ancestor, %s.\n')
692 'bisection from\nthe common ancestor, %s.\n')
693 % extendnode)
693 % extendnode)
694 else:
694 else:
695 # multiple possible revisions
695 # multiple possible revisions
696 if good:
696 if good:
697 ui.write(_("Due to skipped revisions, the first "
697 ui.write(_("Due to skipped revisions, the first "
698 "good revision could be any of:\n"))
698 "good revision could be any of:\n"))
699 else:
699 else:
700 ui.write(_("Due to skipped revisions, the first "
700 ui.write(_("Due to skipped revisions, the first "
701 "bad revision could be any of:\n"))
701 "bad revision could be any of:\n"))
702 for n in nodes:
702 for n in nodes:
703 displayer.show(repo[n])
703 displayer.show(repo[n])
704 displayer.close()
704 displayer.close()
705
705
706 def check_state(state, interactive=True):
706 def check_state(state, interactive=True):
707 if not state['good'] or not state['bad']:
707 if not state['good'] or not state['bad']:
708 if (good or bad or skip or reset) and interactive:
708 if (good or bad or skip or reset) and interactive:
709 return
709 return
710 if not state['good']:
710 if not state['good']:
711 raise util.Abort(_('cannot bisect (no known good revisions)'))
711 raise util.Abort(_('cannot bisect (no known good revisions)'))
712 else:
712 else:
713 raise util.Abort(_('cannot bisect (no known bad revisions)'))
713 raise util.Abort(_('cannot bisect (no known bad revisions)'))
714 return True
714 return True
715
715
716 # backward compatibility
716 # backward compatibility
717 if rev in "good bad reset init".split():
717 if rev in "good bad reset init".split():
718 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
718 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
719 cmd, rev, extra = rev, extra, None
719 cmd, rev, extra = rev, extra, None
720 if cmd == "good":
720 if cmd == "good":
721 good = True
721 good = True
722 elif cmd == "bad":
722 elif cmd == "bad":
723 bad = True
723 bad = True
724 else:
724 else:
725 reset = True
725 reset = True
726 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
726 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
727 raise util.Abort(_('incompatible arguments'))
727 raise util.Abort(_('incompatible arguments'))
728
728
729 cmdutil.checkunfinished(repo)
729 cmdutil.checkunfinished(repo)
730
730
731 if reset:
731 if reset:
732 p = repo.join("bisect.state")
732 p = repo.join("bisect.state")
733 if os.path.exists(p):
733 if os.path.exists(p):
734 os.unlink(p)
734 os.unlink(p)
735 return
735 return
736
736
737 state = hbisect.load_state(repo)
737 state = hbisect.load_state(repo)
738
738
739 if command:
739 if command:
740 changesets = 1
740 changesets = 1
741 if noupdate:
741 if noupdate:
742 try:
742 try:
743 node = state['current'][0]
743 node = state['current'][0]
744 except LookupError:
744 except LookupError:
745 raise util.Abort(_('current bisect revision is unknown - '
745 raise util.Abort(_('current bisect revision is unknown - '
746 'start a new bisect to fix'))
746 'start a new bisect to fix'))
747 else:
747 else:
748 node, p2 = repo.dirstate.parents()
748 node, p2 = repo.dirstate.parents()
749 if p2 != nullid:
749 if p2 != nullid:
750 raise util.Abort(_('current bisect revision is a merge'))
750 raise util.Abort(_('current bisect revision is a merge'))
751 try:
751 try:
752 while changesets:
752 while changesets:
753 # update state
753 # update state
754 state['current'] = [node]
754 state['current'] = [node]
755 hbisect.save_state(repo, state)
755 hbisect.save_state(repo, state)
756 status = ui.system(command, environ={'HG_NODE': hex(node)})
756 status = ui.system(command, environ={'HG_NODE': hex(node)})
757 if status == 125:
757 if status == 125:
758 transition = "skip"
758 transition = "skip"
759 elif status == 0:
759 elif status == 0:
760 transition = "good"
760 transition = "good"
761 # status < 0 means process was killed
761 # status < 0 means process was killed
762 elif status == 127:
762 elif status == 127:
763 raise util.Abort(_("failed to execute %s") % command)
763 raise util.Abort(_("failed to execute %s") % command)
764 elif status < 0:
764 elif status < 0:
765 raise util.Abort(_("%s killed") % command)
765 raise util.Abort(_("%s killed") % command)
766 else:
766 else:
767 transition = "bad"
767 transition = "bad"
768 ctx = scmutil.revsingle(repo, rev, node)
768 ctx = scmutil.revsingle(repo, rev, node)
769 rev = None # clear for future iterations
769 rev = None # clear for future iterations
770 state[transition].append(ctx.node())
770 state[transition].append(ctx.node())
771 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
771 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
772 check_state(state, interactive=False)
772 check_state(state, interactive=False)
773 # bisect
773 # bisect
774 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
774 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
775 # update to next check
775 # update to next check
776 node = nodes[0]
776 node = nodes[0]
777 if not noupdate:
777 if not noupdate:
778 cmdutil.bailifchanged(repo)
778 cmdutil.bailifchanged(repo)
779 hg.clean(repo, node, show_stats=False)
779 hg.clean(repo, node, show_stats=False)
780 finally:
780 finally:
781 state['current'] = [node]
781 state['current'] = [node]
782 hbisect.save_state(repo, state)
782 hbisect.save_state(repo, state)
783 print_result(nodes, bgood)
783 print_result(nodes, bgood)
784 return
784 return
785
785
786 # update state
786 # update state
787
787
788 if rev:
788 if rev:
789 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
789 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
790 else:
790 else:
791 nodes = [repo.lookup('.')]
791 nodes = [repo.lookup('.')]
792
792
793 if good or bad or skip:
793 if good or bad or skip:
794 if good:
794 if good:
795 state['good'] += nodes
795 state['good'] += nodes
796 elif bad:
796 elif bad:
797 state['bad'] += nodes
797 state['bad'] += nodes
798 elif skip:
798 elif skip:
799 state['skip'] += nodes
799 state['skip'] += nodes
800 hbisect.save_state(repo, state)
800 hbisect.save_state(repo, state)
801
801
802 if not check_state(state):
802 if not check_state(state):
803 return
803 return
804
804
805 # actually bisect
805 # actually bisect
806 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
806 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
807 if extend:
807 if extend:
808 if not changesets:
808 if not changesets:
809 extendnode = extendbisectrange(nodes, good)
809 extendnode = extendbisectrange(nodes, good)
810 if extendnode is not None:
810 if extendnode is not None:
811 ui.write(_("Extending search to changeset %d:%s\n")
811 ui.write(_("Extending search to changeset %d:%s\n")
812 % (extendnode.rev(), extendnode))
812 % (extendnode.rev(), extendnode))
813 state['current'] = [extendnode.node()]
813 state['current'] = [extendnode.node()]
814 hbisect.save_state(repo, state)
814 hbisect.save_state(repo, state)
815 if noupdate:
815 if noupdate:
816 return
816 return
817 cmdutil.bailifchanged(repo)
817 cmdutil.bailifchanged(repo)
818 return hg.clean(repo, extendnode.node())
818 return hg.clean(repo, extendnode.node())
819 raise util.Abort(_("nothing to extend"))
819 raise util.Abort(_("nothing to extend"))
820
820
821 if changesets == 0:
821 if changesets == 0:
822 print_result(nodes, good)
822 print_result(nodes, good)
823 else:
823 else:
824 assert len(nodes) == 1 # only a single node can be tested next
824 assert len(nodes) == 1 # only a single node can be tested next
825 node = nodes[0]
825 node = nodes[0]
826 # compute the approximate number of remaining tests
826 # compute the approximate number of remaining tests
827 tests, size = 0, 2
827 tests, size = 0, 2
828 while size <= changesets:
828 while size <= changesets:
829 tests, size = tests + 1, size * 2
829 tests, size = tests + 1, size * 2
830 rev = repo.changelog.rev(node)
830 rev = repo.changelog.rev(node)
831 ui.write(_("Testing changeset %d:%s "
831 ui.write(_("Testing changeset %d:%s "
832 "(%d changesets remaining, ~%d tests)\n")
832 "(%d changesets remaining, ~%d tests)\n")
833 % (rev, short(node), changesets, tests))
833 % (rev, short(node), changesets, tests))
834 state['current'] = [node]
834 state['current'] = [node]
835 hbisect.save_state(repo, state)
835 hbisect.save_state(repo, state)
836 if not noupdate:
836 if not noupdate:
837 cmdutil.bailifchanged(repo)
837 cmdutil.bailifchanged(repo)
838 return hg.clean(repo, node)
838 return hg.clean(repo, node)
839
839
840 @command('bookmarks|bookmark',
840 @command('bookmarks|bookmark',
841 [('f', 'force', False, _('force')),
841 [('f', 'force', False, _('force')),
842 ('r', 'rev', '', _('revision'), _('REV')),
842 ('r', 'rev', '', _('revision'), _('REV')),
843 ('d', 'delete', False, _('delete a given bookmark')),
843 ('d', 'delete', False, _('delete a given bookmark')),
844 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
844 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
845 ('i', 'inactive', False, _('mark a bookmark inactive')),
845 ('i', 'inactive', False, _('mark a bookmark inactive')),
846 ] + formatteropts,
846 ] + formatteropts,
847 _('hg bookmarks [OPTIONS]... [NAME]...'))
847 _('hg bookmarks [OPTIONS]... [NAME]...'))
848 def bookmark(ui, repo, *names, **opts):
848 def bookmark(ui, repo, *names, **opts):
849 '''create a new bookmark or list existing bookmarks
849 '''create a new bookmark or list existing bookmarks
850
850
851 Bookmarks are labels on changesets to help track lines of development.
851 Bookmarks are labels on changesets to help track lines of development.
852 Bookmarks are unversioned and can be moved, renamed and deleted.
852 Bookmarks are unversioned and can be moved, renamed and deleted.
853 Deleting or moving a bookmark has no effect on the associated changesets.
853 Deleting or moving a bookmark has no effect on the associated changesets.
854
854
855 Creating or updating to a bookmark causes it to be marked as 'active'.
855 Creating or updating to a bookmark causes it to be marked as 'active'.
856 The active bookmark is indicated with a '*'.
856 The active bookmark is indicated with a '*'.
857 When a commit is made, the active bookmark will advance to the new commit.
857 When a commit is made, the active bookmark will advance to the new commit.
858 A plain :hg:`update` will also advance an active bookmark, if possible.
858 A plain :hg:`update` will also advance an active bookmark, if possible.
859 Updating away from a bookmark will cause it to be deactivated.
859 Updating away from a bookmark will cause it to be deactivated.
860
860
861 Bookmarks can be pushed and pulled between repositories (see
861 Bookmarks can be pushed and pulled between repositories (see
862 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
862 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
863 diverged, a new 'divergent bookmark' of the form 'name@path' will
863 diverged, a new 'divergent bookmark' of the form 'name@path' will
864 be created. Using :hg:`merge` will resolve the divergence.
864 be created. Using :hg:`merge` will resolve the divergence.
865
865
866 A bookmark named '@' has the special property that :hg:`clone` will
866 A bookmark named '@' has the special property that :hg:`clone` will
867 check it out by default if it exists.
867 check it out by default if it exists.
868
868
869 .. container:: verbose
869 .. container:: verbose
870
870
871 Examples:
871 Examples:
872
872
873 - create an active bookmark for a new line of development::
873 - create an active bookmark for a new line of development::
874
874
875 hg book new-feature
875 hg book new-feature
876
876
877 - create an inactive bookmark as a place marker::
877 - create an inactive bookmark as a place marker::
878
878
879 hg book -i reviewed
879 hg book -i reviewed
880
880
881 - create an inactive bookmark on another changeset::
881 - create an inactive bookmark on another changeset::
882
882
883 hg book -r .^ tested
883 hg book -r .^ tested
884
884
885 - move the '@' bookmark from another branch::
885 - move the '@' bookmark from another branch::
886
886
887 hg book -f @
887 hg book -f @
888 '''
888 '''
889 force = opts.get('force')
889 force = opts.get('force')
890 rev = opts.get('rev')
890 rev = opts.get('rev')
891 delete = opts.get('delete')
891 delete = opts.get('delete')
892 rename = opts.get('rename')
892 rename = opts.get('rename')
893 inactive = opts.get('inactive')
893 inactive = opts.get('inactive')
894
894
895 def checkformat(mark):
895 def checkformat(mark):
896 mark = mark.strip()
896 mark = mark.strip()
897 if not mark:
897 if not mark:
898 raise util.Abort(_("bookmark names cannot consist entirely of "
898 raise util.Abort(_("bookmark names cannot consist entirely of "
899 "whitespace"))
899 "whitespace"))
900 scmutil.checknewlabel(repo, mark, 'bookmark')
900 scmutil.checknewlabel(repo, mark, 'bookmark')
901 return mark
901 return mark
902
902
903 def checkconflict(repo, mark, cur, force=False, target=None):
903 def checkconflict(repo, mark, cur, force=False, target=None):
904 if mark in marks and not force:
904 if mark in marks and not force:
905 if target:
905 if target:
906 if marks[mark] == target and target == cur:
906 if marks[mark] == target and target == cur:
907 # re-activating a bookmark
907 # re-activating a bookmark
908 return
908 return
909 anc = repo.changelog.ancestors([repo[target].rev()])
909 anc = repo.changelog.ancestors([repo[target].rev()])
910 bmctx = repo[marks[mark]]
910 bmctx = repo[marks[mark]]
911 divs = [repo[b].node() for b in marks
911 divs = [repo[b].node() for b in marks
912 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
912 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
913
913
914 # allow resolving a single divergent bookmark even if moving
914 # allow resolving a single divergent bookmark even if moving
915 # the bookmark across branches when a revision is specified
915 # the bookmark across branches when a revision is specified
916 # that contains a divergent bookmark
916 # that contains a divergent bookmark
917 if bmctx.rev() not in anc and target in divs:
917 if bmctx.rev() not in anc and target in divs:
918 bookmarks.deletedivergent(repo, [target], mark)
918 bookmarks.deletedivergent(repo, [target], mark)
919 return
919 return
920
920
921 deletefrom = [b for b in divs
921 deletefrom = [b for b in divs
922 if repo[b].rev() in anc or b == target]
922 if repo[b].rev() in anc or b == target]
923 bookmarks.deletedivergent(repo, deletefrom, mark)
923 bookmarks.deletedivergent(repo, deletefrom, mark)
924 if bookmarks.validdest(repo, bmctx, repo[target]):
924 if bookmarks.validdest(repo, bmctx, repo[target]):
925 ui.status(_("moving bookmark '%s' forward from %s\n") %
925 ui.status(_("moving bookmark '%s' forward from %s\n") %
926 (mark, short(bmctx.node())))
926 (mark, short(bmctx.node())))
927 return
927 return
928 raise util.Abort(_("bookmark '%s' already exists "
928 raise util.Abort(_("bookmark '%s' already exists "
929 "(use -f to force)") % mark)
929 "(use -f to force)") % mark)
930 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
930 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
931 and not force):
931 and not force):
932 raise util.Abort(
932 raise util.Abort(
933 _("a bookmark cannot have the name of an existing branch"))
933 _("a bookmark cannot have the name of an existing branch"))
934
934
935 if delete and rename:
935 if delete and rename:
936 raise util.Abort(_("--delete and --rename are incompatible"))
936 raise util.Abort(_("--delete and --rename are incompatible"))
937 if delete and rev:
937 if delete and rev:
938 raise util.Abort(_("--rev is incompatible with --delete"))
938 raise util.Abort(_("--rev is incompatible with --delete"))
939 if rename and rev:
939 if rename and rev:
940 raise util.Abort(_("--rev is incompatible with --rename"))
940 raise util.Abort(_("--rev is incompatible with --rename"))
941 if not names and (delete or rev):
941 if not names and (delete or rev):
942 raise util.Abort(_("bookmark name required"))
942 raise util.Abort(_("bookmark name required"))
943
943
944 if delete or rename or names or inactive:
944 if delete or rename or names or inactive:
945 wlock = repo.wlock()
945 wlock = repo.wlock()
946 try:
946 try:
947 cur = repo.changectx('.').node()
947 cur = repo.changectx('.').node()
948 marks = repo._bookmarks
948 marks = repo._bookmarks
949 if delete:
949 if delete:
950 for mark in names:
950 for mark in names:
951 if mark not in marks:
951 if mark not in marks:
952 raise util.Abort(_("bookmark '%s' does not exist") %
952 raise util.Abort(_("bookmark '%s' does not exist") %
953 mark)
953 mark)
954 if mark == repo._bookmarkcurrent:
954 if mark == repo._bookmarkcurrent:
955 bookmarks.unsetcurrent(repo)
955 bookmarks.unsetcurrent(repo)
956 del marks[mark]
956 del marks[mark]
957 marks.write()
957 marks.write()
958
958
959 elif rename:
959 elif rename:
960 if not names:
960 if not names:
961 raise util.Abort(_("new bookmark name required"))
961 raise util.Abort(_("new bookmark name required"))
962 elif len(names) > 1:
962 elif len(names) > 1:
963 raise util.Abort(_("only one new bookmark name allowed"))
963 raise util.Abort(_("only one new bookmark name allowed"))
964 mark = checkformat(names[0])
964 mark = checkformat(names[0])
965 if rename not in marks:
965 if rename not in marks:
966 raise util.Abort(_("bookmark '%s' does not exist") % rename)
966 raise util.Abort(_("bookmark '%s' does not exist") % rename)
967 checkconflict(repo, mark, cur, force)
967 checkconflict(repo, mark, cur, force)
968 marks[mark] = marks[rename]
968 marks[mark] = marks[rename]
969 if repo._bookmarkcurrent == rename and not inactive:
969 if repo._bookmarkcurrent == rename and not inactive:
970 bookmarks.setcurrent(repo, mark)
970 bookmarks.setcurrent(repo, mark)
971 del marks[rename]
971 del marks[rename]
972 marks.write()
972 marks.write()
973
973
974 elif names:
974 elif names:
975 newact = None
975 newact = None
976 for mark in names:
976 for mark in names:
977 mark = checkformat(mark)
977 mark = checkformat(mark)
978 if newact is None:
978 if newact is None:
979 newact = mark
979 newact = mark
980 if inactive and mark == repo._bookmarkcurrent:
980 if inactive and mark == repo._bookmarkcurrent:
981 bookmarks.unsetcurrent(repo)
981 bookmarks.unsetcurrent(repo)
982 return
982 return
983 tgt = cur
983 tgt = cur
984 if rev:
984 if rev:
985 tgt = scmutil.revsingle(repo, rev).node()
985 tgt = scmutil.revsingle(repo, rev).node()
986 checkconflict(repo, mark, cur, force, tgt)
986 checkconflict(repo, mark, cur, force, tgt)
987 marks[mark] = tgt
987 marks[mark] = tgt
988 if not inactive and cur == marks[newact] and not rev:
988 if not inactive and cur == marks[newact] and not rev:
989 bookmarks.setcurrent(repo, newact)
989 bookmarks.setcurrent(repo, newact)
990 elif cur != tgt and newact == repo._bookmarkcurrent:
990 elif cur != tgt and newact == repo._bookmarkcurrent:
991 bookmarks.unsetcurrent(repo)
991 bookmarks.unsetcurrent(repo)
992 marks.write()
992 marks.write()
993
993
994 elif inactive:
994 elif inactive:
995 if len(marks) == 0:
995 if len(marks) == 0:
996 ui.status(_("no bookmarks set\n"))
996 ui.status(_("no bookmarks set\n"))
997 elif not repo._bookmarkcurrent:
997 elif not repo._bookmarkcurrent:
998 ui.status(_("no active bookmark\n"))
998 ui.status(_("no active bookmark\n"))
999 else:
999 else:
1000 bookmarks.unsetcurrent(repo)
1000 bookmarks.unsetcurrent(repo)
1001 finally:
1001 finally:
1002 wlock.release()
1002 wlock.release()
1003 else: # show bookmarks
1003 else: # show bookmarks
1004 fm = ui.formatter('bookmarks', opts)
1004 fm = ui.formatter('bookmarks', opts)
1005 hexfn = fm.hexfunc
1005 hexfn = fm.hexfunc
1006 marks = repo._bookmarks
1006 marks = repo._bookmarks
1007 if len(marks) == 0 and not fm:
1007 if len(marks) == 0 and not fm:
1008 ui.status(_("no bookmarks set\n"))
1008 ui.status(_("no bookmarks set\n"))
1009 for bmark, n in sorted(marks.iteritems()):
1009 for bmark, n in sorted(marks.iteritems()):
1010 current = repo._bookmarkcurrent
1010 current = repo._bookmarkcurrent
1011 if bmark == current:
1011 if bmark == current:
1012 prefix, label = '*', 'bookmarks.current'
1012 prefix, label = '*', 'bookmarks.current'
1013 else:
1013 else:
1014 prefix, label = ' ', ''
1014 prefix, label = ' ', ''
1015
1015
1016 fm.startitem()
1016 fm.startitem()
1017 if not ui.quiet:
1017 if not ui.quiet:
1018 fm.plain(' %s ' % prefix, label=label)
1018 fm.plain(' %s ' % prefix, label=label)
1019 fm.write('bookmark', '%s', bmark, label=label)
1019 fm.write('bookmark', '%s', bmark, label=label)
1020 pad = " " * (25 - encoding.colwidth(bmark))
1020 pad = " " * (25 - encoding.colwidth(bmark))
1021 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1021 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1022 repo.changelog.rev(n), hexfn(n), label=label)
1022 repo.changelog.rev(n), hexfn(n), label=label)
1023 fm.data(active=(bmark == current))
1023 fm.data(active=(bmark == current))
1024 fm.plain('\n')
1024 fm.plain('\n')
1025 fm.end()
1025 fm.end()
1026
1026
1027 @command('branch',
1027 @command('branch',
1028 [('f', 'force', None,
1028 [('f', 'force', None,
1029 _('set branch name even if it shadows an existing branch')),
1029 _('set branch name even if it shadows an existing branch')),
1030 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1030 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1031 _('[-fC] [NAME]'))
1031 _('[-fC] [NAME]'))
1032 def branch(ui, repo, label=None, **opts):
1032 def branch(ui, repo, label=None, **opts):
1033 """set or show the current branch name
1033 """set or show the current branch name
1034
1034
1035 .. note::
1035 .. note::
1036
1036
1037 Branch names are permanent and global. Use :hg:`bookmark` to create a
1037 Branch names are permanent and global. Use :hg:`bookmark` to create a
1038 light-weight bookmark instead. See :hg:`help glossary` for more
1038 light-weight bookmark instead. See :hg:`help glossary` for more
1039 information about named branches and bookmarks.
1039 information about named branches and bookmarks.
1040
1040
1041 With no argument, show the current branch name. With one argument,
1041 With no argument, show the current branch name. With one argument,
1042 set the working directory branch name (the branch will not exist
1042 set the working directory branch name (the branch will not exist
1043 in the repository until the next commit). Standard practice
1043 in the repository until the next commit). Standard practice
1044 recommends that primary development take place on the 'default'
1044 recommends that primary development take place on the 'default'
1045 branch.
1045 branch.
1046
1046
1047 Unless -f/--force is specified, branch will not let you set a
1047 Unless -f/--force is specified, branch will not let you set a
1048 branch name that already exists.
1048 branch name that already exists.
1049
1049
1050 Use -C/--clean to reset the working directory branch to that of
1050 Use -C/--clean to reset the working directory branch to that of
1051 the parent of the working directory, negating a previous branch
1051 the parent of the working directory, negating a previous branch
1052 change.
1052 change.
1053
1053
1054 Use the command :hg:`update` to switch to an existing branch. Use
1054 Use the command :hg:`update` to switch to an existing branch. Use
1055 :hg:`commit --close-branch` to mark this branch as closed.
1055 :hg:`commit --close-branch` to mark this branch as closed.
1056
1056
1057 Returns 0 on success.
1057 Returns 0 on success.
1058 """
1058 """
1059 if label:
1059 if label:
1060 label = label.strip()
1060 label = label.strip()
1061
1061
1062 if not opts.get('clean') and not label:
1062 if not opts.get('clean') and not label:
1063 ui.write("%s\n" % repo.dirstate.branch())
1063 ui.write("%s\n" % repo.dirstate.branch())
1064 return
1064 return
1065
1065
1066 wlock = repo.wlock()
1066 wlock = repo.wlock()
1067 try:
1067 try:
1068 if opts.get('clean'):
1068 if opts.get('clean'):
1069 label = repo[None].p1().branch()
1069 label = repo[None].p1().branch()
1070 repo.dirstate.setbranch(label)
1070 repo.dirstate.setbranch(label)
1071 ui.status(_('reset working directory to branch %s\n') % label)
1071 ui.status(_('reset working directory to branch %s\n') % label)
1072 elif label:
1072 elif label:
1073 if not opts.get('force') and label in repo.branchmap():
1073 if not opts.get('force') and label in repo.branchmap():
1074 if label not in [p.branch() for p in repo.parents()]:
1074 if label not in [p.branch() for p in repo.parents()]:
1075 raise util.Abort(_('a branch of the same name already'
1075 raise util.Abort(_('a branch of the same name already'
1076 ' exists'),
1076 ' exists'),
1077 # i18n: "it" refers to an existing branch
1077 # i18n: "it" refers to an existing branch
1078 hint=_("use 'hg update' to switch to it"))
1078 hint=_("use 'hg update' to switch to it"))
1079 scmutil.checknewlabel(repo, label, 'branch')
1079 scmutil.checknewlabel(repo, label, 'branch')
1080 repo.dirstate.setbranch(label)
1080 repo.dirstate.setbranch(label)
1081 ui.status(_('marked working directory as branch %s\n') % label)
1081 ui.status(_('marked working directory as branch %s\n') % label)
1082 ui.status(_('(branches are permanent and global, '
1082 ui.status(_('(branches are permanent and global, '
1083 'did you want a bookmark?)\n'))
1083 'did you want a bookmark?)\n'))
1084 finally:
1084 finally:
1085 wlock.release()
1085 wlock.release()
1086
1086
1087 @command('branches',
1087 @command('branches',
1088 [('a', 'active', False,
1088 [('a', 'active', False,
1089 _('show only branches that have unmerged heads (DEPRECATED)')),
1089 _('show only branches that have unmerged heads (DEPRECATED)')),
1090 ('c', 'closed', False, _('show normal and closed branches')),
1090 ('c', 'closed', False, _('show normal and closed branches')),
1091 ] + formatteropts,
1091 ] + formatteropts,
1092 _('[-ac]'))
1092 _('[-ac]'))
1093 def branches(ui, repo, active=False, closed=False, **opts):
1093 def branches(ui, repo, active=False, closed=False, **opts):
1094 """list repository named branches
1094 """list repository named branches
1095
1095
1096 List the repository's named branches, indicating which ones are
1096 List the repository's named branches, indicating which ones are
1097 inactive. If -c/--closed is specified, also list branches which have
1097 inactive. If -c/--closed is specified, also list branches which have
1098 been marked closed (see :hg:`commit --close-branch`).
1098 been marked closed (see :hg:`commit --close-branch`).
1099
1099
1100 Use the command :hg:`update` to switch to an existing branch.
1100 Use the command :hg:`update` to switch to an existing branch.
1101
1101
1102 Returns 0.
1102 Returns 0.
1103 """
1103 """
1104
1104
1105 fm = ui.formatter('branches', opts)
1105 fm = ui.formatter('branches', opts)
1106 hexfunc = fm.hexfunc
1106 hexfunc = fm.hexfunc
1107
1107
1108 allheads = set(repo.heads())
1108 allheads = set(repo.heads())
1109 branches = []
1109 branches = []
1110 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1110 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1111 isactive = not isclosed and bool(set(heads) & allheads)
1111 isactive = not isclosed and bool(set(heads) & allheads)
1112 branches.append((tag, repo[tip], isactive, not isclosed))
1112 branches.append((tag, repo[tip], isactive, not isclosed))
1113 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1113 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1114 reverse=True)
1114 reverse=True)
1115
1115
1116 for tag, ctx, isactive, isopen in branches:
1116 for tag, ctx, isactive, isopen in branches:
1117 if active and not isactive:
1117 if active and not isactive:
1118 continue
1118 continue
1119 if isactive:
1119 if isactive:
1120 label = 'branches.active'
1120 label = 'branches.active'
1121 notice = ''
1121 notice = ''
1122 elif not isopen:
1122 elif not isopen:
1123 if not closed:
1123 if not closed:
1124 continue
1124 continue
1125 label = 'branches.closed'
1125 label = 'branches.closed'
1126 notice = _(' (closed)')
1126 notice = _(' (closed)')
1127 else:
1127 else:
1128 label = 'branches.inactive'
1128 label = 'branches.inactive'
1129 notice = _(' (inactive)')
1129 notice = _(' (inactive)')
1130 current = (tag == repo.dirstate.branch())
1130 current = (tag == repo.dirstate.branch())
1131 if current:
1131 if current:
1132 label = 'branches.current'
1132 label = 'branches.current'
1133
1133
1134 fm.startitem()
1134 fm.startitem()
1135 fm.write('branch', '%s', tag, label=label)
1135 fm.write('branch', '%s', tag, label=label)
1136 rev = ctx.rev()
1136 rev = ctx.rev()
1137 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1137 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1138 fmt = ' ' * padsize + ' %d:%s'
1138 fmt = ' ' * padsize + ' %d:%s'
1139 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1139 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1140 label='log.changeset changeset.%s' % ctx.phasestr())
1140 label='log.changeset changeset.%s' % ctx.phasestr())
1141 fm.data(active=isactive, closed=not isopen, current=current)
1141 fm.data(active=isactive, closed=not isopen, current=current)
1142 if not ui.quiet:
1142 if not ui.quiet:
1143 fm.plain(notice)
1143 fm.plain(notice)
1144 fm.plain('\n')
1144 fm.plain('\n')
1145 fm.end()
1145 fm.end()
1146
1146
1147 @command('bundle',
1147 @command('bundle',
1148 [('f', 'force', None, _('run even when the destination is unrelated')),
1148 [('f', 'force', None, _('run even when the destination is unrelated')),
1149 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1149 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1150 _('REV')),
1150 _('REV')),
1151 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1151 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1152 _('BRANCH')),
1152 _('BRANCH')),
1153 ('', 'base', [],
1153 ('', 'base', [],
1154 _('a base changeset assumed to be available at the destination'),
1154 _('a base changeset assumed to be available at the destination'),
1155 _('REV')),
1155 _('REV')),
1156 ('a', 'all', None, _('bundle all changesets in the repository')),
1156 ('a', 'all', None, _('bundle all changesets in the repository')),
1157 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1157 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1158 ] + remoteopts,
1158 ] + remoteopts,
1159 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1159 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1160 def bundle(ui, repo, fname, dest=None, **opts):
1160 def bundle(ui, repo, fname, dest=None, **opts):
1161 """create a changegroup file
1161 """create a changegroup file
1162
1162
1163 Generate a compressed changegroup file collecting changesets not
1163 Generate a compressed changegroup file collecting changesets not
1164 known to be in another repository.
1164 known to be in another repository.
1165
1165
1166 If you omit the destination repository, then hg assumes the
1166 If you omit the destination repository, then hg assumes the
1167 destination will have all the nodes you specify with --base
1167 destination will have all the nodes you specify with --base
1168 parameters. To create a bundle containing all changesets, use
1168 parameters. To create a bundle containing all changesets, use
1169 -a/--all (or --base null).
1169 -a/--all (or --base null).
1170
1170
1171 You can change compression method with the -t/--type option.
1171 You can change compression method with the -t/--type option.
1172 The available compression methods are: none, bzip2, and
1172 The available compression methods are: none, bzip2, and
1173 gzip (by default, bundles are compressed using bzip2).
1173 gzip (by default, bundles are compressed using bzip2).
1174
1174
1175 The bundle file can then be transferred using conventional means
1175 The bundle file can then be transferred using conventional means
1176 and applied to another repository with the unbundle or pull
1176 and applied to another repository with the unbundle or pull
1177 command. This is useful when direct push and pull are not
1177 command. This is useful when direct push and pull are not
1178 available or when exporting an entire repository is undesirable.
1178 available or when exporting an entire repository is undesirable.
1179
1179
1180 Applying bundles preserves all changeset contents including
1180 Applying bundles preserves all changeset contents including
1181 permissions, copy/rename information, and revision history.
1181 permissions, copy/rename information, and revision history.
1182
1182
1183 Returns 0 on success, 1 if no changes found.
1183 Returns 0 on success, 1 if no changes found.
1184 """
1184 """
1185 revs = None
1185 revs = None
1186 if 'rev' in opts:
1186 if 'rev' in opts:
1187 revs = scmutil.revrange(repo, opts['rev'])
1187 revs = scmutil.revrange(repo, opts['rev'])
1188
1188
1189 bundletype = opts.get('type', 'bzip2').lower()
1189 bundletype = opts.get('type', 'bzip2').lower()
1190 btypes = {'none': 'HG10UN',
1190 btypes = {'none': 'HG10UN',
1191 'bzip2': 'HG10BZ',
1191 'bzip2': 'HG10BZ',
1192 'gzip': 'HG10GZ',
1192 'gzip': 'HG10GZ',
1193 'bundle2': 'HG2Y'}
1193 'bundle2': 'HG2Y'}
1194 bundletype = btypes.get(bundletype)
1194 bundletype = btypes.get(bundletype)
1195 if bundletype not in changegroup.bundletypes:
1195 if bundletype not in changegroup.bundletypes:
1196 raise util.Abort(_('unknown bundle type specified with --type'))
1196 raise util.Abort(_('unknown bundle type specified with --type'))
1197
1197
1198 if opts.get('all'):
1198 if opts.get('all'):
1199 base = ['null']
1199 base = ['null']
1200 else:
1200 else:
1201 base = scmutil.revrange(repo, opts.get('base'))
1201 base = scmutil.revrange(repo, opts.get('base'))
1202 # TODO: get desired bundlecaps from command line.
1202 # TODO: get desired bundlecaps from command line.
1203 bundlecaps = None
1203 bundlecaps = None
1204 if base:
1204 if base:
1205 if dest:
1205 if dest:
1206 raise util.Abort(_("--base is incompatible with specifying "
1206 raise util.Abort(_("--base is incompatible with specifying "
1207 "a destination"))
1207 "a destination"))
1208 common = [repo.lookup(rev) for rev in base]
1208 common = [repo.lookup(rev) for rev in base]
1209 heads = revs and map(repo.lookup, revs) or revs
1209 heads = revs and map(repo.lookup, revs) or revs
1210 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1210 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1211 common=common, bundlecaps=bundlecaps)
1211 common=common, bundlecaps=bundlecaps)
1212 outgoing = None
1212 outgoing = None
1213 else:
1213 else:
1214 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1214 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1215 dest, branches = hg.parseurl(dest, opts.get('branch'))
1215 dest, branches = hg.parseurl(dest, opts.get('branch'))
1216 other = hg.peer(repo, opts, dest)
1216 other = hg.peer(repo, opts, dest)
1217 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1217 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1218 heads = revs and map(repo.lookup, revs) or revs
1218 heads = revs and map(repo.lookup, revs) or revs
1219 outgoing = discovery.findcommonoutgoing(repo, other,
1219 outgoing = discovery.findcommonoutgoing(repo, other,
1220 onlyheads=heads,
1220 onlyheads=heads,
1221 force=opts.get('force'),
1221 force=opts.get('force'),
1222 portable=True)
1222 portable=True)
1223 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1223 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1224 bundlecaps)
1224 bundlecaps)
1225 if not cg:
1225 if not cg:
1226 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1226 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1227 return 1
1227 return 1
1228
1228
1229 changegroup.writebundle(ui, cg, fname, bundletype)
1229 changegroup.writebundle(ui, cg, fname, bundletype)
1230
1230
1231 @command('cat',
1231 @command('cat',
1232 [('o', 'output', '',
1232 [('o', 'output', '',
1233 _('print output to file with formatted name'), _('FORMAT')),
1233 _('print output to file with formatted name'), _('FORMAT')),
1234 ('r', 'rev', '', _('print the given revision'), _('REV')),
1234 ('r', 'rev', '', _('print the given revision'), _('REV')),
1235 ('', 'decode', None, _('apply any matching decode filter')),
1235 ('', 'decode', None, _('apply any matching decode filter')),
1236 ] + walkopts,
1236 ] + walkopts,
1237 _('[OPTION]... FILE...'),
1237 _('[OPTION]... FILE...'),
1238 inferrepo=True)
1238 inferrepo=True)
1239 def cat(ui, repo, file1, *pats, **opts):
1239 def cat(ui, repo, file1, *pats, **opts):
1240 """output the current or given revision of files
1240 """output the current or given revision of files
1241
1241
1242 Print the specified files as they were at the given revision. If
1242 Print the specified files as they were at the given revision. If
1243 no revision is given, the parent of the working directory is used.
1243 no revision is given, the parent of the working directory is used.
1244
1244
1245 Output may be to a file, in which case the name of the file is
1245 Output may be to a file, in which case the name of the file is
1246 given using a format string. The formatting rules as follows:
1246 given using a format string. The formatting rules as follows:
1247
1247
1248 :``%%``: literal "%" character
1248 :``%%``: literal "%" character
1249 :``%s``: basename of file being printed
1249 :``%s``: basename of file being printed
1250 :``%d``: dirname of file being printed, or '.' if in repository root
1250 :``%d``: dirname of file being printed, or '.' if in repository root
1251 :``%p``: root-relative path name of file being printed
1251 :``%p``: root-relative path name of file being printed
1252 :``%H``: changeset hash (40 hexadecimal digits)
1252 :``%H``: changeset hash (40 hexadecimal digits)
1253 :``%R``: changeset revision number
1253 :``%R``: changeset revision number
1254 :``%h``: short-form changeset hash (12 hexadecimal digits)
1254 :``%h``: short-form changeset hash (12 hexadecimal digits)
1255 :``%r``: zero-padded changeset revision number
1255 :``%r``: zero-padded changeset revision number
1256 :``%b``: basename of the exporting repository
1256 :``%b``: basename of the exporting repository
1257
1257
1258 Returns 0 on success.
1258 Returns 0 on success.
1259 """
1259 """
1260 ctx = scmutil.revsingle(repo, opts.get('rev'))
1260 ctx = scmutil.revsingle(repo, opts.get('rev'))
1261 m = scmutil.match(ctx, (file1,) + pats, opts)
1261 m = scmutil.match(ctx, (file1,) + pats, opts)
1262
1262
1263 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1263 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1264
1264
1265 @command('^clone',
1265 @command('^clone',
1266 [('U', 'noupdate', None, _('the clone will include an empty working '
1266 [('U', 'noupdate', None, _('the clone will include an empty working '
1267 'directory (only a repository)')),
1267 'directory (only a repository)')),
1268 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1268 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1269 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1269 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1270 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1270 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1271 ('', 'pull', None, _('use pull protocol to copy metadata')),
1271 ('', 'pull', None, _('use pull protocol to copy metadata')),
1272 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1272 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1273 ] + remoteopts,
1273 ] + remoteopts,
1274 _('[OPTION]... SOURCE [DEST]'),
1274 _('[OPTION]... SOURCE [DEST]'),
1275 norepo=True)
1275 norepo=True)
1276 def clone(ui, source, dest=None, **opts):
1276 def clone(ui, source, dest=None, **opts):
1277 """make a copy of an existing repository
1277 """make a copy of an existing repository
1278
1278
1279 Create a copy of an existing repository in a new directory.
1279 Create a copy of an existing repository in a new directory.
1280
1280
1281 If no destination directory name is specified, it defaults to the
1281 If no destination directory name is specified, it defaults to the
1282 basename of the source.
1282 basename of the source.
1283
1283
1284 The location of the source is added to the new repository's
1284 The location of the source is added to the new repository's
1285 ``.hg/hgrc`` file, as the default to be used for future pulls.
1285 ``.hg/hgrc`` file, as the default to be used for future pulls.
1286
1286
1287 Only local paths and ``ssh://`` URLs are supported as
1287 Only local paths and ``ssh://`` URLs are supported as
1288 destinations. For ``ssh://`` destinations, no working directory or
1288 destinations. For ``ssh://`` destinations, no working directory or
1289 ``.hg/hgrc`` will be created on the remote side.
1289 ``.hg/hgrc`` will be created on the remote side.
1290
1290
1291 To pull only a subset of changesets, specify one or more revisions
1291 To pull only a subset of changesets, specify one or more revisions
1292 identifiers with -r/--rev or branches with -b/--branch. The
1292 identifiers with -r/--rev or branches with -b/--branch. The
1293 resulting clone will contain only the specified changesets and
1293 resulting clone will contain only the specified changesets and
1294 their ancestors. These options (or 'clone src#rev dest') imply
1294 their ancestors. These options (or 'clone src#rev dest') imply
1295 --pull, even for local source repositories. Note that specifying a
1295 --pull, even for local source repositories. Note that specifying a
1296 tag will include the tagged changeset but not the changeset
1296 tag will include the tagged changeset but not the changeset
1297 containing the tag.
1297 containing the tag.
1298
1298
1299 If the source repository has a bookmark called '@' set, that
1299 If the source repository has a bookmark called '@' set, that
1300 revision will be checked out in the new repository by default.
1300 revision will be checked out in the new repository by default.
1301
1301
1302 To check out a particular version, use -u/--update, or
1302 To check out a particular version, use -u/--update, or
1303 -U/--noupdate to create a clone with no working directory.
1303 -U/--noupdate to create a clone with no working directory.
1304
1304
1305 .. container:: verbose
1305 .. container:: verbose
1306
1306
1307 For efficiency, hardlinks are used for cloning whenever the
1307 For efficiency, hardlinks are used for cloning whenever the
1308 source and destination are on the same filesystem (note this
1308 source and destination are on the same filesystem (note this
1309 applies only to the repository data, not to the working
1309 applies only to the repository data, not to the working
1310 directory). Some filesystems, such as AFS, implement hardlinking
1310 directory). Some filesystems, such as AFS, implement hardlinking
1311 incorrectly, but do not report errors. In these cases, use the
1311 incorrectly, but do not report errors. In these cases, use the
1312 --pull option to avoid hardlinking.
1312 --pull option to avoid hardlinking.
1313
1313
1314 In some cases, you can clone repositories and the working
1314 In some cases, you can clone repositories and the working
1315 directory using full hardlinks with ::
1315 directory using full hardlinks with ::
1316
1316
1317 $ cp -al REPO REPOCLONE
1317 $ cp -al REPO REPOCLONE
1318
1318
1319 This is the fastest way to clone, but it is not always safe. The
1319 This is the fastest way to clone, but it is not always safe. The
1320 operation is not atomic (making sure REPO is not modified during
1320 operation is not atomic (making sure REPO is not modified during
1321 the operation is up to you) and you have to make sure your
1321 the operation is up to you) and you have to make sure your
1322 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1322 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1323 so). Also, this is not compatible with certain extensions that
1323 so). Also, this is not compatible with certain extensions that
1324 place their metadata under the .hg directory, such as mq.
1324 place their metadata under the .hg directory, such as mq.
1325
1325
1326 Mercurial will update the working directory to the first applicable
1326 Mercurial will update the working directory to the first applicable
1327 revision from this list:
1327 revision from this list:
1328
1328
1329 a) null if -U or the source repository has no changesets
1329 a) null if -U or the source repository has no changesets
1330 b) if -u . and the source repository is local, the first parent of
1330 b) if -u . and the source repository is local, the first parent of
1331 the source repository's working directory
1331 the source repository's working directory
1332 c) the changeset specified with -u (if a branch name, this means the
1332 c) the changeset specified with -u (if a branch name, this means the
1333 latest head of that branch)
1333 latest head of that branch)
1334 d) the changeset specified with -r
1334 d) the changeset specified with -r
1335 e) the tipmost head specified with -b
1335 e) the tipmost head specified with -b
1336 f) the tipmost head specified with the url#branch source syntax
1336 f) the tipmost head specified with the url#branch source syntax
1337 g) the revision marked with the '@' bookmark, if present
1337 g) the revision marked with the '@' bookmark, if present
1338 h) the tipmost head of the default branch
1338 h) the tipmost head of the default branch
1339 i) tip
1339 i) tip
1340
1340
1341 Examples:
1341 Examples:
1342
1342
1343 - clone a remote repository to a new directory named hg/::
1343 - clone a remote repository to a new directory named hg/::
1344
1344
1345 hg clone http://selenic.com/hg
1345 hg clone http://selenic.com/hg
1346
1346
1347 - create a lightweight local clone::
1347 - create a lightweight local clone::
1348
1348
1349 hg clone project/ project-feature/
1349 hg clone project/ project-feature/
1350
1350
1351 - clone from an absolute path on an ssh server (note double-slash)::
1351 - clone from an absolute path on an ssh server (note double-slash)::
1352
1352
1353 hg clone ssh://user@server//home/projects/alpha/
1353 hg clone ssh://user@server//home/projects/alpha/
1354
1354
1355 - do a high-speed clone over a LAN while checking out a
1355 - do a high-speed clone over a LAN while checking out a
1356 specified version::
1356 specified version::
1357
1357
1358 hg clone --uncompressed http://server/repo -u 1.5
1358 hg clone --uncompressed http://server/repo -u 1.5
1359
1359
1360 - create a repository without changesets after a particular revision::
1360 - create a repository without changesets after a particular revision::
1361
1361
1362 hg clone -r 04e544 experimental/ good/
1362 hg clone -r 04e544 experimental/ good/
1363
1363
1364 - clone (and track) a particular named branch::
1364 - clone (and track) a particular named branch::
1365
1365
1366 hg clone http://selenic.com/hg#stable
1366 hg clone http://selenic.com/hg#stable
1367
1367
1368 See :hg:`help urls` for details on specifying URLs.
1368 See :hg:`help urls` for details on specifying URLs.
1369
1369
1370 Returns 0 on success.
1370 Returns 0 on success.
1371 """
1371 """
1372 if opts.get('noupdate') and opts.get('updaterev'):
1372 if opts.get('noupdate') and opts.get('updaterev'):
1373 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1373 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1374
1374
1375 r = hg.clone(ui, opts, source, dest,
1375 r = hg.clone(ui, opts, source, dest,
1376 pull=opts.get('pull'),
1376 pull=opts.get('pull'),
1377 stream=opts.get('uncompressed'),
1377 stream=opts.get('uncompressed'),
1378 rev=opts.get('rev'),
1378 rev=opts.get('rev'),
1379 update=opts.get('updaterev') or not opts.get('noupdate'),
1379 update=opts.get('updaterev') or not opts.get('noupdate'),
1380 branch=opts.get('branch'))
1380 branch=opts.get('branch'))
1381
1381
1382 return r is None
1382 return r is None
1383
1383
1384 @command('^commit|ci',
1384 @command('^commit|ci',
1385 [('A', 'addremove', None,
1385 [('A', 'addremove', None,
1386 _('mark new/missing files as added/removed before committing')),
1386 _('mark new/missing files as added/removed before committing')),
1387 ('', 'close-branch', None,
1387 ('', 'close-branch', None,
1388 _('mark a branch as closed, hiding it from the branch list')),
1388 _('mark a branch as closed, hiding it from the branch list')),
1389 ('', 'amend', None, _('amend the parent of the working dir')),
1389 ('', 'amend', None, _('amend the parent of the working directory')),
1390 ('s', 'secret', None, _('use the secret phase for committing')),
1390 ('s', 'secret', None, _('use the secret phase for committing')),
1391 ('e', 'edit', None, _('invoke editor on commit messages')),
1391 ('e', 'edit', None, _('invoke editor on commit messages')),
1392 ('i', 'interactive', None, _('use interactive mode')),
1392 ('i', 'interactive', None, _('use interactive mode')),
1393 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1393 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1394 _('[OPTION]... [FILE]...'),
1394 _('[OPTION]... [FILE]...'),
1395 inferrepo=True)
1395 inferrepo=True)
1396 def commit(ui, repo, *pats, **opts):
1396 def commit(ui, repo, *pats, **opts):
1397 """commit the specified files or all outstanding changes
1397 """commit the specified files or all outstanding changes
1398
1398
1399 Commit changes to the given files into the repository. Unlike a
1399 Commit changes to the given files into the repository. Unlike a
1400 centralized SCM, this operation is a local operation. See
1400 centralized SCM, this operation is a local operation. See
1401 :hg:`push` for a way to actively distribute your changes.
1401 :hg:`push` for a way to actively distribute your changes.
1402
1402
1403 If a list of files is omitted, all changes reported by :hg:`status`
1403 If a list of files is omitted, all changes reported by :hg:`status`
1404 will be committed.
1404 will be committed.
1405
1405
1406 If you are committing the result of a merge, do not provide any
1406 If you are committing the result of a merge, do not provide any
1407 filenames or -I/-X filters.
1407 filenames or -I/-X filters.
1408
1408
1409 If no commit message is specified, Mercurial starts your
1409 If no commit message is specified, Mercurial starts your
1410 configured editor where you can enter a message. In case your
1410 configured editor where you can enter a message. In case your
1411 commit fails, you will find a backup of your message in
1411 commit fails, you will find a backup of your message in
1412 ``.hg/last-message.txt``.
1412 ``.hg/last-message.txt``.
1413
1413
1414 The --amend flag can be used to amend the parent of the
1414 The --amend flag can be used to amend the parent of the
1415 working directory with a new commit that contains the changes
1415 working directory with a new commit that contains the changes
1416 in the parent in addition to those currently reported by :hg:`status`,
1416 in the parent in addition to those currently reported by :hg:`status`,
1417 if there are any. The old commit is stored in a backup bundle in
1417 if there are any. The old commit is stored in a backup bundle in
1418 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1418 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1419 on how to restore it).
1419 on how to restore it).
1420
1420
1421 Message, user and date are taken from the amended commit unless
1421 Message, user and date are taken from the amended commit unless
1422 specified. When a message isn't specified on the command line,
1422 specified. When a message isn't specified on the command line,
1423 the editor will open with the message of the amended commit.
1423 the editor will open with the message of the amended commit.
1424
1424
1425 It is not possible to amend public changesets (see :hg:`help phases`)
1425 It is not possible to amend public changesets (see :hg:`help phases`)
1426 or changesets that have children.
1426 or changesets that have children.
1427
1427
1428 See :hg:`help dates` for a list of formats valid for -d/--date.
1428 See :hg:`help dates` for a list of formats valid for -d/--date.
1429
1429
1430 Returns 0 on success, 1 if nothing changed.
1430 Returns 0 on success, 1 if nothing changed.
1431 """
1431 """
1432 if opts.get('interactive'):
1432 if opts.get('interactive'):
1433 opts.pop('interactive')
1433 opts.pop('interactive')
1434 cmdutil.dorecord(ui, repo, commit, 'commit', False,
1434 cmdutil.dorecord(ui, repo, commit, 'commit', False,
1435 cmdutil.recordfilter, *pats, **opts)
1435 cmdutil.recordfilter, *pats, **opts)
1436 return
1436 return
1437
1437
1438 if opts.get('subrepos'):
1438 if opts.get('subrepos'):
1439 if opts.get('amend'):
1439 if opts.get('amend'):
1440 raise util.Abort(_('cannot amend with --subrepos'))
1440 raise util.Abort(_('cannot amend with --subrepos'))
1441 # Let --subrepos on the command line override config setting.
1441 # Let --subrepos on the command line override config setting.
1442 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1442 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1443
1443
1444 cmdutil.checkunfinished(repo, commit=True)
1444 cmdutil.checkunfinished(repo, commit=True)
1445
1445
1446 branch = repo[None].branch()
1446 branch = repo[None].branch()
1447 bheads = repo.branchheads(branch)
1447 bheads = repo.branchheads(branch)
1448
1448
1449 extra = {}
1449 extra = {}
1450 if opts.get('close_branch'):
1450 if opts.get('close_branch'):
1451 extra['close'] = 1
1451 extra['close'] = 1
1452
1452
1453 if not bheads:
1453 if not bheads:
1454 raise util.Abort(_('can only close branch heads'))
1454 raise util.Abort(_('can only close branch heads'))
1455 elif opts.get('amend'):
1455 elif opts.get('amend'):
1456 if repo.parents()[0].p1().branch() != branch and \
1456 if repo.parents()[0].p1().branch() != branch and \
1457 repo.parents()[0].p2().branch() != branch:
1457 repo.parents()[0].p2().branch() != branch:
1458 raise util.Abort(_('can only close branch heads'))
1458 raise util.Abort(_('can only close branch heads'))
1459
1459
1460 if opts.get('amend'):
1460 if opts.get('amend'):
1461 if ui.configbool('ui', 'commitsubrepos'):
1461 if ui.configbool('ui', 'commitsubrepos'):
1462 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1462 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1463
1463
1464 old = repo['.']
1464 old = repo['.']
1465 if not old.mutable():
1465 if not old.mutable():
1466 raise util.Abort(_('cannot amend public changesets'))
1466 raise util.Abort(_('cannot amend public changesets'))
1467 if len(repo[None].parents()) > 1:
1467 if len(repo[None].parents()) > 1:
1468 raise util.Abort(_('cannot amend while merging'))
1468 raise util.Abort(_('cannot amend while merging'))
1469 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1469 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1470 if not allowunstable and old.children():
1470 if not allowunstable and old.children():
1471 raise util.Abort(_('cannot amend changeset with children'))
1471 raise util.Abort(_('cannot amend changeset with children'))
1472
1472
1473 # commitfunc is used only for temporary amend commit by cmdutil.amend
1473 # commitfunc is used only for temporary amend commit by cmdutil.amend
1474 def commitfunc(ui, repo, message, match, opts):
1474 def commitfunc(ui, repo, message, match, opts):
1475 return repo.commit(message,
1475 return repo.commit(message,
1476 opts.get('user') or old.user(),
1476 opts.get('user') or old.user(),
1477 opts.get('date') or old.date(),
1477 opts.get('date') or old.date(),
1478 match,
1478 match,
1479 extra=extra)
1479 extra=extra)
1480
1480
1481 current = repo._bookmarkcurrent
1481 current = repo._bookmarkcurrent
1482 marks = old.bookmarks()
1482 marks = old.bookmarks()
1483 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1483 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1484 if node == old.node():
1484 if node == old.node():
1485 ui.status(_("nothing changed\n"))
1485 ui.status(_("nothing changed\n"))
1486 return 1
1486 return 1
1487 elif marks:
1487 elif marks:
1488 ui.debug('moving bookmarks %r from %s to %s\n' %
1488 ui.debug('moving bookmarks %r from %s to %s\n' %
1489 (marks, old.hex(), hex(node)))
1489 (marks, old.hex(), hex(node)))
1490 newmarks = repo._bookmarks
1490 newmarks = repo._bookmarks
1491 for bm in marks:
1491 for bm in marks:
1492 newmarks[bm] = node
1492 newmarks[bm] = node
1493 if bm == current:
1493 if bm == current:
1494 bookmarks.setcurrent(repo, bm)
1494 bookmarks.setcurrent(repo, bm)
1495 newmarks.write()
1495 newmarks.write()
1496 else:
1496 else:
1497 def commitfunc(ui, repo, message, match, opts):
1497 def commitfunc(ui, repo, message, match, opts):
1498 backup = ui.backupconfig('phases', 'new-commit')
1498 backup = ui.backupconfig('phases', 'new-commit')
1499 baseui = repo.baseui
1499 baseui = repo.baseui
1500 basebackup = baseui.backupconfig('phases', 'new-commit')
1500 basebackup = baseui.backupconfig('phases', 'new-commit')
1501 try:
1501 try:
1502 if opts.get('secret'):
1502 if opts.get('secret'):
1503 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1503 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1504 # Propagate to subrepos
1504 # Propagate to subrepos
1505 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1505 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1506
1506
1507 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1507 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1508 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1508 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1509 return repo.commit(message, opts.get('user'), opts.get('date'),
1509 return repo.commit(message, opts.get('user'), opts.get('date'),
1510 match,
1510 match,
1511 editor=editor,
1511 editor=editor,
1512 extra=extra)
1512 extra=extra)
1513 finally:
1513 finally:
1514 ui.restoreconfig(backup)
1514 ui.restoreconfig(backup)
1515 repo.baseui.restoreconfig(basebackup)
1515 repo.baseui.restoreconfig(basebackup)
1516
1516
1517
1517
1518 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1518 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1519
1519
1520 if not node:
1520 if not node:
1521 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1521 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1522 if stat[3]:
1522 if stat[3]:
1523 ui.status(_("nothing changed (%d missing files, see "
1523 ui.status(_("nothing changed (%d missing files, see "
1524 "'hg status')\n") % len(stat[3]))
1524 "'hg status')\n") % len(stat[3]))
1525 else:
1525 else:
1526 ui.status(_("nothing changed\n"))
1526 ui.status(_("nothing changed\n"))
1527 return 1
1527 return 1
1528
1528
1529 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1529 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1530
1530
1531 @command('config|showconfig|debugconfig',
1531 @command('config|showconfig|debugconfig',
1532 [('u', 'untrusted', None, _('show untrusted configuration options')),
1532 [('u', 'untrusted', None, _('show untrusted configuration options')),
1533 ('e', 'edit', None, _('edit user config')),
1533 ('e', 'edit', None, _('edit user config')),
1534 ('l', 'local', None, _('edit repository config')),
1534 ('l', 'local', None, _('edit repository config')),
1535 ('g', 'global', None, _('edit global config'))],
1535 ('g', 'global', None, _('edit global config'))],
1536 _('[-u] [NAME]...'),
1536 _('[-u] [NAME]...'),
1537 optionalrepo=True)
1537 optionalrepo=True)
1538 def config(ui, repo, *values, **opts):
1538 def config(ui, repo, *values, **opts):
1539 """show combined config settings from all hgrc files
1539 """show combined config settings from all hgrc files
1540
1540
1541 With no arguments, print names and values of all config items.
1541 With no arguments, print names and values of all config items.
1542
1542
1543 With one argument of the form section.name, print just the value
1543 With one argument of the form section.name, print just the value
1544 of that config item.
1544 of that config item.
1545
1545
1546 With multiple arguments, print names and values of all config
1546 With multiple arguments, print names and values of all config
1547 items with matching section names.
1547 items with matching section names.
1548
1548
1549 With --edit, start an editor on the user-level config file. With
1549 With --edit, start an editor on the user-level config file. With
1550 --global, edit the system-wide config file. With --local, edit the
1550 --global, edit the system-wide config file. With --local, edit the
1551 repository-level config file.
1551 repository-level config file.
1552
1552
1553 With --debug, the source (filename and line number) is printed
1553 With --debug, the source (filename and line number) is printed
1554 for each config item.
1554 for each config item.
1555
1555
1556 See :hg:`help config` for more information about config files.
1556 See :hg:`help config` for more information about config files.
1557
1557
1558 Returns 0 on success, 1 if NAME does not exist.
1558 Returns 0 on success, 1 if NAME does not exist.
1559
1559
1560 """
1560 """
1561
1561
1562 if opts.get('edit') or opts.get('local') or opts.get('global'):
1562 if opts.get('edit') or opts.get('local') or opts.get('global'):
1563 if opts.get('local') and opts.get('global'):
1563 if opts.get('local') and opts.get('global'):
1564 raise util.Abort(_("can't use --local and --global together"))
1564 raise util.Abort(_("can't use --local and --global together"))
1565
1565
1566 if opts.get('local'):
1566 if opts.get('local'):
1567 if not repo:
1567 if not repo:
1568 raise util.Abort(_("can't use --local outside a repository"))
1568 raise util.Abort(_("can't use --local outside a repository"))
1569 paths = [repo.join('hgrc')]
1569 paths = [repo.join('hgrc')]
1570 elif opts.get('global'):
1570 elif opts.get('global'):
1571 paths = scmutil.systemrcpath()
1571 paths = scmutil.systemrcpath()
1572 else:
1572 else:
1573 paths = scmutil.userrcpath()
1573 paths = scmutil.userrcpath()
1574
1574
1575 for f in paths:
1575 for f in paths:
1576 if os.path.exists(f):
1576 if os.path.exists(f):
1577 break
1577 break
1578 else:
1578 else:
1579 if opts.get('global'):
1579 if opts.get('global'):
1580 samplehgrc = uimod.samplehgrcs['global']
1580 samplehgrc = uimod.samplehgrcs['global']
1581 elif opts.get('local'):
1581 elif opts.get('local'):
1582 samplehgrc = uimod.samplehgrcs['local']
1582 samplehgrc = uimod.samplehgrcs['local']
1583 else:
1583 else:
1584 samplehgrc = uimod.samplehgrcs['user']
1584 samplehgrc = uimod.samplehgrcs['user']
1585
1585
1586 f = paths[0]
1586 f = paths[0]
1587 fp = open(f, "w")
1587 fp = open(f, "w")
1588 fp.write(samplehgrc)
1588 fp.write(samplehgrc)
1589 fp.close()
1589 fp.close()
1590
1590
1591 editor = ui.geteditor()
1591 editor = ui.geteditor()
1592 ui.system("%s \"%s\"" % (editor, f),
1592 ui.system("%s \"%s\"" % (editor, f),
1593 onerr=util.Abort, errprefix=_("edit failed"))
1593 onerr=util.Abort, errprefix=_("edit failed"))
1594 return
1594 return
1595
1595
1596 for f in scmutil.rcpath():
1596 for f in scmutil.rcpath():
1597 ui.debug('read config from: %s\n' % f)
1597 ui.debug('read config from: %s\n' % f)
1598 untrusted = bool(opts.get('untrusted'))
1598 untrusted = bool(opts.get('untrusted'))
1599 if values:
1599 if values:
1600 sections = [v for v in values if '.' not in v]
1600 sections = [v for v in values if '.' not in v]
1601 items = [v for v in values if '.' in v]
1601 items = [v for v in values if '.' in v]
1602 if len(items) > 1 or items and sections:
1602 if len(items) > 1 or items and sections:
1603 raise util.Abort(_('only one config item permitted'))
1603 raise util.Abort(_('only one config item permitted'))
1604 matched = False
1604 matched = False
1605 for section, name, value in ui.walkconfig(untrusted=untrusted):
1605 for section, name, value in ui.walkconfig(untrusted=untrusted):
1606 value = str(value).replace('\n', '\\n')
1606 value = str(value).replace('\n', '\\n')
1607 sectname = section + '.' + name
1607 sectname = section + '.' + name
1608 if values:
1608 if values:
1609 for v in values:
1609 for v in values:
1610 if v == section:
1610 if v == section:
1611 ui.debug('%s: ' %
1611 ui.debug('%s: ' %
1612 ui.configsource(section, name, untrusted))
1612 ui.configsource(section, name, untrusted))
1613 ui.write('%s=%s\n' % (sectname, value))
1613 ui.write('%s=%s\n' % (sectname, value))
1614 matched = True
1614 matched = True
1615 elif v == sectname:
1615 elif v == sectname:
1616 ui.debug('%s: ' %
1616 ui.debug('%s: ' %
1617 ui.configsource(section, name, untrusted))
1617 ui.configsource(section, name, untrusted))
1618 ui.write(value, '\n')
1618 ui.write(value, '\n')
1619 matched = True
1619 matched = True
1620 else:
1620 else:
1621 ui.debug('%s: ' %
1621 ui.debug('%s: ' %
1622 ui.configsource(section, name, untrusted))
1622 ui.configsource(section, name, untrusted))
1623 ui.write('%s=%s\n' % (sectname, value))
1623 ui.write('%s=%s\n' % (sectname, value))
1624 matched = True
1624 matched = True
1625 if matched:
1625 if matched:
1626 return 0
1626 return 0
1627 return 1
1627 return 1
1628
1628
1629 @command('copy|cp',
1629 @command('copy|cp',
1630 [('A', 'after', None, _('record a copy that has already occurred')),
1630 [('A', 'after', None, _('record a copy that has already occurred')),
1631 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1631 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1632 ] + walkopts + dryrunopts,
1632 ] + walkopts + dryrunopts,
1633 _('[OPTION]... [SOURCE]... DEST'))
1633 _('[OPTION]... [SOURCE]... DEST'))
1634 def copy(ui, repo, *pats, **opts):
1634 def copy(ui, repo, *pats, **opts):
1635 """mark files as copied for the next commit
1635 """mark files as copied for the next commit
1636
1636
1637 Mark dest as having copies of source files. If dest is a
1637 Mark dest as having copies of source files. If dest is a
1638 directory, copies are put in that directory. If dest is a file,
1638 directory, copies are put in that directory. If dest is a file,
1639 the source must be a single file.
1639 the source must be a single file.
1640
1640
1641 By default, this command copies the contents of files as they
1641 By default, this command copies the contents of files as they
1642 exist in the working directory. If invoked with -A/--after, the
1642 exist in the working directory. If invoked with -A/--after, the
1643 operation is recorded, but no copying is performed.
1643 operation is recorded, but no copying is performed.
1644
1644
1645 This command takes effect with the next commit. To undo a copy
1645 This command takes effect with the next commit. To undo a copy
1646 before that, see :hg:`revert`.
1646 before that, see :hg:`revert`.
1647
1647
1648 Returns 0 on success, 1 if errors are encountered.
1648 Returns 0 on success, 1 if errors are encountered.
1649 """
1649 """
1650 wlock = repo.wlock(False)
1650 wlock = repo.wlock(False)
1651 try:
1651 try:
1652 return cmdutil.copy(ui, repo, pats, opts)
1652 return cmdutil.copy(ui, repo, pats, opts)
1653 finally:
1653 finally:
1654 wlock.release()
1654 wlock.release()
1655
1655
1656 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1656 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1657 def debugancestor(ui, repo, *args):
1657 def debugancestor(ui, repo, *args):
1658 """find the ancestor revision of two revisions in a given index"""
1658 """find the ancestor revision of two revisions in a given index"""
1659 if len(args) == 3:
1659 if len(args) == 3:
1660 index, rev1, rev2 = args
1660 index, rev1, rev2 = args
1661 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1661 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1662 lookup = r.lookup
1662 lookup = r.lookup
1663 elif len(args) == 2:
1663 elif len(args) == 2:
1664 if not repo:
1664 if not repo:
1665 raise util.Abort(_("there is no Mercurial repository here "
1665 raise util.Abort(_("there is no Mercurial repository here "
1666 "(.hg not found)"))
1666 "(.hg not found)"))
1667 rev1, rev2 = args
1667 rev1, rev2 = args
1668 r = repo.changelog
1668 r = repo.changelog
1669 lookup = repo.lookup
1669 lookup = repo.lookup
1670 else:
1670 else:
1671 raise util.Abort(_('either two or three arguments required'))
1671 raise util.Abort(_('either two or three arguments required'))
1672 a = r.ancestor(lookup(rev1), lookup(rev2))
1672 a = r.ancestor(lookup(rev1), lookup(rev2))
1673 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1673 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1674
1674
1675 @command('debugbuilddag',
1675 @command('debugbuilddag',
1676 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1676 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1677 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1677 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1678 ('n', 'new-file', None, _('add new file at each rev'))],
1678 ('n', 'new-file', None, _('add new file at each rev'))],
1679 _('[OPTION]... [TEXT]'))
1679 _('[OPTION]... [TEXT]'))
1680 def debugbuilddag(ui, repo, text=None,
1680 def debugbuilddag(ui, repo, text=None,
1681 mergeable_file=False,
1681 mergeable_file=False,
1682 overwritten_file=False,
1682 overwritten_file=False,
1683 new_file=False):
1683 new_file=False):
1684 """builds a repo with a given DAG from scratch in the current empty repo
1684 """builds a repo with a given DAG from scratch in the current empty repo
1685
1685
1686 The description of the DAG is read from stdin if not given on the
1686 The description of the DAG is read from stdin if not given on the
1687 command line.
1687 command line.
1688
1688
1689 Elements:
1689 Elements:
1690
1690
1691 - "+n" is a linear run of n nodes based on the current default parent
1691 - "+n" is a linear run of n nodes based on the current default parent
1692 - "." is a single node based on the current default parent
1692 - "." is a single node based on the current default parent
1693 - "$" resets the default parent to null (implied at the start);
1693 - "$" resets the default parent to null (implied at the start);
1694 otherwise the default parent is always the last node created
1694 otherwise the default parent is always the last node created
1695 - "<p" sets the default parent to the backref p
1695 - "<p" sets the default parent to the backref p
1696 - "*p" is a fork at parent p, which is a backref
1696 - "*p" is a fork at parent p, which is a backref
1697 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1697 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1698 - "/p2" is a merge of the preceding node and p2
1698 - "/p2" is a merge of the preceding node and p2
1699 - ":tag" defines a local tag for the preceding node
1699 - ":tag" defines a local tag for the preceding node
1700 - "@branch" sets the named branch for subsequent nodes
1700 - "@branch" sets the named branch for subsequent nodes
1701 - "#...\\n" is a comment up to the end of the line
1701 - "#...\\n" is a comment up to the end of the line
1702
1702
1703 Whitespace between the above elements is ignored.
1703 Whitespace between the above elements is ignored.
1704
1704
1705 A backref is either
1705 A backref is either
1706
1706
1707 - a number n, which references the node curr-n, where curr is the current
1707 - a number n, which references the node curr-n, where curr is the current
1708 node, or
1708 node, or
1709 - the name of a local tag you placed earlier using ":tag", or
1709 - the name of a local tag you placed earlier using ":tag", or
1710 - empty to denote the default parent.
1710 - empty to denote the default parent.
1711
1711
1712 All string valued-elements are either strictly alphanumeric, or must
1712 All string valued-elements are either strictly alphanumeric, or must
1713 be enclosed in double quotes ("..."), with "\\" as escape character.
1713 be enclosed in double quotes ("..."), with "\\" as escape character.
1714 """
1714 """
1715
1715
1716 if text is None:
1716 if text is None:
1717 ui.status(_("reading DAG from stdin\n"))
1717 ui.status(_("reading DAG from stdin\n"))
1718 text = ui.fin.read()
1718 text = ui.fin.read()
1719
1719
1720 cl = repo.changelog
1720 cl = repo.changelog
1721 if len(cl) > 0:
1721 if len(cl) > 0:
1722 raise util.Abort(_('repository is not empty'))
1722 raise util.Abort(_('repository is not empty'))
1723
1723
1724 # determine number of revs in DAG
1724 # determine number of revs in DAG
1725 total = 0
1725 total = 0
1726 for type, data in dagparser.parsedag(text):
1726 for type, data in dagparser.parsedag(text):
1727 if type == 'n':
1727 if type == 'n':
1728 total += 1
1728 total += 1
1729
1729
1730 if mergeable_file:
1730 if mergeable_file:
1731 linesperrev = 2
1731 linesperrev = 2
1732 # make a file with k lines per rev
1732 # make a file with k lines per rev
1733 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1733 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1734 initialmergedlines.append("")
1734 initialmergedlines.append("")
1735
1735
1736 tags = []
1736 tags = []
1737
1737
1738 lock = tr = None
1738 lock = tr = None
1739 try:
1739 try:
1740 lock = repo.lock()
1740 lock = repo.lock()
1741 tr = repo.transaction("builddag")
1741 tr = repo.transaction("builddag")
1742
1742
1743 at = -1
1743 at = -1
1744 atbranch = 'default'
1744 atbranch = 'default'
1745 nodeids = []
1745 nodeids = []
1746 id = 0
1746 id = 0
1747 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1747 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1748 for type, data in dagparser.parsedag(text):
1748 for type, data in dagparser.parsedag(text):
1749 if type == 'n':
1749 if type == 'n':
1750 ui.note(('node %s\n' % str(data)))
1750 ui.note(('node %s\n' % str(data)))
1751 id, ps = data
1751 id, ps = data
1752
1752
1753 files = []
1753 files = []
1754 fctxs = {}
1754 fctxs = {}
1755
1755
1756 p2 = None
1756 p2 = None
1757 if mergeable_file:
1757 if mergeable_file:
1758 fn = "mf"
1758 fn = "mf"
1759 p1 = repo[ps[0]]
1759 p1 = repo[ps[0]]
1760 if len(ps) > 1:
1760 if len(ps) > 1:
1761 p2 = repo[ps[1]]
1761 p2 = repo[ps[1]]
1762 pa = p1.ancestor(p2)
1762 pa = p1.ancestor(p2)
1763 base, local, other = [x[fn].data() for x in (pa, p1,
1763 base, local, other = [x[fn].data() for x in (pa, p1,
1764 p2)]
1764 p2)]
1765 m3 = simplemerge.Merge3Text(base, local, other)
1765 m3 = simplemerge.Merge3Text(base, local, other)
1766 ml = [l.strip() for l in m3.merge_lines()]
1766 ml = [l.strip() for l in m3.merge_lines()]
1767 ml.append("")
1767 ml.append("")
1768 elif at > 0:
1768 elif at > 0:
1769 ml = p1[fn].data().split("\n")
1769 ml = p1[fn].data().split("\n")
1770 else:
1770 else:
1771 ml = initialmergedlines
1771 ml = initialmergedlines
1772 ml[id * linesperrev] += " r%i" % id
1772 ml[id * linesperrev] += " r%i" % id
1773 mergedtext = "\n".join(ml)
1773 mergedtext = "\n".join(ml)
1774 files.append(fn)
1774 files.append(fn)
1775 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1775 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1776
1776
1777 if overwritten_file:
1777 if overwritten_file:
1778 fn = "of"
1778 fn = "of"
1779 files.append(fn)
1779 files.append(fn)
1780 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1780 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1781
1781
1782 if new_file:
1782 if new_file:
1783 fn = "nf%i" % id
1783 fn = "nf%i" % id
1784 files.append(fn)
1784 files.append(fn)
1785 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1785 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1786 if len(ps) > 1:
1786 if len(ps) > 1:
1787 if not p2:
1787 if not p2:
1788 p2 = repo[ps[1]]
1788 p2 = repo[ps[1]]
1789 for fn in p2:
1789 for fn in p2:
1790 if fn.startswith("nf"):
1790 if fn.startswith("nf"):
1791 files.append(fn)
1791 files.append(fn)
1792 fctxs[fn] = p2[fn]
1792 fctxs[fn] = p2[fn]
1793
1793
1794 def fctxfn(repo, cx, path):
1794 def fctxfn(repo, cx, path):
1795 return fctxs.get(path)
1795 return fctxs.get(path)
1796
1796
1797 if len(ps) == 0 or ps[0] < 0:
1797 if len(ps) == 0 or ps[0] < 0:
1798 pars = [None, None]
1798 pars = [None, None]
1799 elif len(ps) == 1:
1799 elif len(ps) == 1:
1800 pars = [nodeids[ps[0]], None]
1800 pars = [nodeids[ps[0]], None]
1801 else:
1801 else:
1802 pars = [nodeids[p] for p in ps]
1802 pars = [nodeids[p] for p in ps]
1803 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1803 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1804 date=(id, 0),
1804 date=(id, 0),
1805 user="debugbuilddag",
1805 user="debugbuilddag",
1806 extra={'branch': atbranch})
1806 extra={'branch': atbranch})
1807 nodeid = repo.commitctx(cx)
1807 nodeid = repo.commitctx(cx)
1808 nodeids.append(nodeid)
1808 nodeids.append(nodeid)
1809 at = id
1809 at = id
1810 elif type == 'l':
1810 elif type == 'l':
1811 id, name = data
1811 id, name = data
1812 ui.note(('tag %s\n' % name))
1812 ui.note(('tag %s\n' % name))
1813 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1813 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1814 elif type == 'a':
1814 elif type == 'a':
1815 ui.note(('branch %s\n' % data))
1815 ui.note(('branch %s\n' % data))
1816 atbranch = data
1816 atbranch = data
1817 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1817 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1818 tr.close()
1818 tr.close()
1819
1819
1820 if tags:
1820 if tags:
1821 repo.vfs.write("localtags", "".join(tags))
1821 repo.vfs.write("localtags", "".join(tags))
1822 finally:
1822 finally:
1823 ui.progress(_('building'), None)
1823 ui.progress(_('building'), None)
1824 release(tr, lock)
1824 release(tr, lock)
1825
1825
1826 @command('debugbundle',
1826 @command('debugbundle',
1827 [('a', 'all', None, _('show all details'))],
1827 [('a', 'all', None, _('show all details'))],
1828 _('FILE'),
1828 _('FILE'),
1829 norepo=True)
1829 norepo=True)
1830 def debugbundle(ui, bundlepath, all=None, **opts):
1830 def debugbundle(ui, bundlepath, all=None, **opts):
1831 """lists the contents of a bundle"""
1831 """lists the contents of a bundle"""
1832 f = hg.openpath(ui, bundlepath)
1832 f = hg.openpath(ui, bundlepath)
1833 try:
1833 try:
1834 gen = exchange.readbundle(ui, f, bundlepath)
1834 gen = exchange.readbundle(ui, f, bundlepath)
1835 if isinstance(gen, bundle2.unbundle20):
1835 if isinstance(gen, bundle2.unbundle20):
1836 return _debugbundle2(ui, gen, all=all, **opts)
1836 return _debugbundle2(ui, gen, all=all, **opts)
1837 if all:
1837 if all:
1838 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1838 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1839
1839
1840 def showchunks(named):
1840 def showchunks(named):
1841 ui.write("\n%s\n" % named)
1841 ui.write("\n%s\n" % named)
1842 chain = None
1842 chain = None
1843 while True:
1843 while True:
1844 chunkdata = gen.deltachunk(chain)
1844 chunkdata = gen.deltachunk(chain)
1845 if not chunkdata:
1845 if not chunkdata:
1846 break
1846 break
1847 node = chunkdata['node']
1847 node = chunkdata['node']
1848 p1 = chunkdata['p1']
1848 p1 = chunkdata['p1']
1849 p2 = chunkdata['p2']
1849 p2 = chunkdata['p2']
1850 cs = chunkdata['cs']
1850 cs = chunkdata['cs']
1851 deltabase = chunkdata['deltabase']
1851 deltabase = chunkdata['deltabase']
1852 delta = chunkdata['delta']
1852 delta = chunkdata['delta']
1853 ui.write("%s %s %s %s %s %s\n" %
1853 ui.write("%s %s %s %s %s %s\n" %
1854 (hex(node), hex(p1), hex(p2),
1854 (hex(node), hex(p1), hex(p2),
1855 hex(cs), hex(deltabase), len(delta)))
1855 hex(cs), hex(deltabase), len(delta)))
1856 chain = node
1856 chain = node
1857
1857
1858 chunkdata = gen.changelogheader()
1858 chunkdata = gen.changelogheader()
1859 showchunks("changelog")
1859 showchunks("changelog")
1860 chunkdata = gen.manifestheader()
1860 chunkdata = gen.manifestheader()
1861 showchunks("manifest")
1861 showchunks("manifest")
1862 while True:
1862 while True:
1863 chunkdata = gen.filelogheader()
1863 chunkdata = gen.filelogheader()
1864 if not chunkdata:
1864 if not chunkdata:
1865 break
1865 break
1866 fname = chunkdata['filename']
1866 fname = chunkdata['filename']
1867 showchunks(fname)
1867 showchunks(fname)
1868 else:
1868 else:
1869 if isinstance(gen, bundle2.unbundle20):
1869 if isinstance(gen, bundle2.unbundle20):
1870 raise util.Abort(_('use debugbundle2 for this file'))
1870 raise util.Abort(_('use debugbundle2 for this file'))
1871 chunkdata = gen.changelogheader()
1871 chunkdata = gen.changelogheader()
1872 chain = None
1872 chain = None
1873 while True:
1873 while True:
1874 chunkdata = gen.deltachunk(chain)
1874 chunkdata = gen.deltachunk(chain)
1875 if not chunkdata:
1875 if not chunkdata:
1876 break
1876 break
1877 node = chunkdata['node']
1877 node = chunkdata['node']
1878 ui.write("%s\n" % hex(node))
1878 ui.write("%s\n" % hex(node))
1879 chain = node
1879 chain = node
1880 finally:
1880 finally:
1881 f.close()
1881 f.close()
1882
1882
1883 def _debugbundle2(ui, gen, **opts):
1883 def _debugbundle2(ui, gen, **opts):
1884 """lists the contents of a bundle2"""
1884 """lists the contents of a bundle2"""
1885 if not isinstance(gen, bundle2.unbundle20):
1885 if not isinstance(gen, bundle2.unbundle20):
1886 raise util.Abort(_('not a bundle2 file'))
1886 raise util.Abort(_('not a bundle2 file'))
1887 ui.write(('Stream params: %s\n' % repr(gen.params)))
1887 ui.write(('Stream params: %s\n' % repr(gen.params)))
1888 for part in gen.iterparts():
1888 for part in gen.iterparts():
1889 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1889 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1890 if part.type == 'b2x:changegroup':
1890 if part.type == 'b2x:changegroup':
1891 version = part.params.get('version', '01')
1891 version = part.params.get('version', '01')
1892 cg = changegroup.packermap[version][1](part, 'UN')
1892 cg = changegroup.packermap[version][1](part, 'UN')
1893 chunkdata = cg.changelogheader()
1893 chunkdata = cg.changelogheader()
1894 chain = None
1894 chain = None
1895 while True:
1895 while True:
1896 chunkdata = cg.deltachunk(chain)
1896 chunkdata = cg.deltachunk(chain)
1897 if not chunkdata:
1897 if not chunkdata:
1898 break
1898 break
1899 node = chunkdata['node']
1899 node = chunkdata['node']
1900 ui.write(" %s\n" % hex(node))
1900 ui.write(" %s\n" % hex(node))
1901 chain = node
1901 chain = node
1902
1902
1903 @command('debugcheckstate', [], '')
1903 @command('debugcheckstate', [], '')
1904 def debugcheckstate(ui, repo):
1904 def debugcheckstate(ui, repo):
1905 """validate the correctness of the current dirstate"""
1905 """validate the correctness of the current dirstate"""
1906 parent1, parent2 = repo.dirstate.parents()
1906 parent1, parent2 = repo.dirstate.parents()
1907 m1 = repo[parent1].manifest()
1907 m1 = repo[parent1].manifest()
1908 m2 = repo[parent2].manifest()
1908 m2 = repo[parent2].manifest()
1909 errors = 0
1909 errors = 0
1910 for f in repo.dirstate:
1910 for f in repo.dirstate:
1911 state = repo.dirstate[f]
1911 state = repo.dirstate[f]
1912 if state in "nr" and f not in m1:
1912 if state in "nr" and f not in m1:
1913 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1913 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1914 errors += 1
1914 errors += 1
1915 if state in "a" and f in m1:
1915 if state in "a" and f in m1:
1916 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1916 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1917 errors += 1
1917 errors += 1
1918 if state in "m" and f not in m1 and f not in m2:
1918 if state in "m" and f not in m1 and f not in m2:
1919 ui.warn(_("%s in state %s, but not in either manifest\n") %
1919 ui.warn(_("%s in state %s, but not in either manifest\n") %
1920 (f, state))
1920 (f, state))
1921 errors += 1
1921 errors += 1
1922 for f in m1:
1922 for f in m1:
1923 state = repo.dirstate[f]
1923 state = repo.dirstate[f]
1924 if state not in "nrm":
1924 if state not in "nrm":
1925 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1925 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1926 errors += 1
1926 errors += 1
1927 if errors:
1927 if errors:
1928 error = _(".hg/dirstate inconsistent with current parent's manifest")
1928 error = _(".hg/dirstate inconsistent with current parent's manifest")
1929 raise util.Abort(error)
1929 raise util.Abort(error)
1930
1930
1931 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1931 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1932 def debugcommands(ui, cmd='', *args):
1932 def debugcommands(ui, cmd='', *args):
1933 """list all available commands and options"""
1933 """list all available commands and options"""
1934 for cmd, vals in sorted(table.iteritems()):
1934 for cmd, vals in sorted(table.iteritems()):
1935 cmd = cmd.split('|')[0].strip('^')
1935 cmd = cmd.split('|')[0].strip('^')
1936 opts = ', '.join([i[1] for i in vals[1]])
1936 opts = ', '.join([i[1] for i in vals[1]])
1937 ui.write('%s: %s\n' % (cmd, opts))
1937 ui.write('%s: %s\n' % (cmd, opts))
1938
1938
1939 @command('debugcomplete',
1939 @command('debugcomplete',
1940 [('o', 'options', None, _('show the command options'))],
1940 [('o', 'options', None, _('show the command options'))],
1941 _('[-o] CMD'),
1941 _('[-o] CMD'),
1942 norepo=True)
1942 norepo=True)
1943 def debugcomplete(ui, cmd='', **opts):
1943 def debugcomplete(ui, cmd='', **opts):
1944 """returns the completion list associated with the given command"""
1944 """returns the completion list associated with the given command"""
1945
1945
1946 if opts.get('options'):
1946 if opts.get('options'):
1947 options = []
1947 options = []
1948 otables = [globalopts]
1948 otables = [globalopts]
1949 if cmd:
1949 if cmd:
1950 aliases, entry = cmdutil.findcmd(cmd, table, False)
1950 aliases, entry = cmdutil.findcmd(cmd, table, False)
1951 otables.append(entry[1])
1951 otables.append(entry[1])
1952 for t in otables:
1952 for t in otables:
1953 for o in t:
1953 for o in t:
1954 if "(DEPRECATED)" in o[3]:
1954 if "(DEPRECATED)" in o[3]:
1955 continue
1955 continue
1956 if o[0]:
1956 if o[0]:
1957 options.append('-%s' % o[0])
1957 options.append('-%s' % o[0])
1958 options.append('--%s' % o[1])
1958 options.append('--%s' % o[1])
1959 ui.write("%s\n" % "\n".join(options))
1959 ui.write("%s\n" % "\n".join(options))
1960 return
1960 return
1961
1961
1962 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1962 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1963 if ui.verbose:
1963 if ui.verbose:
1964 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1964 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1965 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1965 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1966
1966
1967 @command('debugdag',
1967 @command('debugdag',
1968 [('t', 'tags', None, _('use tags as labels')),
1968 [('t', 'tags', None, _('use tags as labels')),
1969 ('b', 'branches', None, _('annotate with branch names')),
1969 ('b', 'branches', None, _('annotate with branch names')),
1970 ('', 'dots', None, _('use dots for runs')),
1970 ('', 'dots', None, _('use dots for runs')),
1971 ('s', 'spaces', None, _('separate elements by spaces'))],
1971 ('s', 'spaces', None, _('separate elements by spaces'))],
1972 _('[OPTION]... [FILE [REV]...]'),
1972 _('[OPTION]... [FILE [REV]...]'),
1973 optionalrepo=True)
1973 optionalrepo=True)
1974 def debugdag(ui, repo, file_=None, *revs, **opts):
1974 def debugdag(ui, repo, file_=None, *revs, **opts):
1975 """format the changelog or an index DAG as a concise textual description
1975 """format the changelog or an index DAG as a concise textual description
1976
1976
1977 If you pass a revlog index, the revlog's DAG is emitted. If you list
1977 If you pass a revlog index, the revlog's DAG is emitted. If you list
1978 revision numbers, they get labeled in the output as rN.
1978 revision numbers, they get labeled in the output as rN.
1979
1979
1980 Otherwise, the changelog DAG of the current repo is emitted.
1980 Otherwise, the changelog DAG of the current repo is emitted.
1981 """
1981 """
1982 spaces = opts.get('spaces')
1982 spaces = opts.get('spaces')
1983 dots = opts.get('dots')
1983 dots = opts.get('dots')
1984 if file_:
1984 if file_:
1985 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1985 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1986 revs = set((int(r) for r in revs))
1986 revs = set((int(r) for r in revs))
1987 def events():
1987 def events():
1988 for r in rlog:
1988 for r in rlog:
1989 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1989 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1990 if p != -1))
1990 if p != -1))
1991 if r in revs:
1991 if r in revs:
1992 yield 'l', (r, "r%i" % r)
1992 yield 'l', (r, "r%i" % r)
1993 elif repo:
1993 elif repo:
1994 cl = repo.changelog
1994 cl = repo.changelog
1995 tags = opts.get('tags')
1995 tags = opts.get('tags')
1996 branches = opts.get('branches')
1996 branches = opts.get('branches')
1997 if tags:
1997 if tags:
1998 labels = {}
1998 labels = {}
1999 for l, n in repo.tags().items():
1999 for l, n in repo.tags().items():
2000 labels.setdefault(cl.rev(n), []).append(l)
2000 labels.setdefault(cl.rev(n), []).append(l)
2001 def events():
2001 def events():
2002 b = "default"
2002 b = "default"
2003 for r in cl:
2003 for r in cl:
2004 if branches:
2004 if branches:
2005 newb = cl.read(cl.node(r))[5]['branch']
2005 newb = cl.read(cl.node(r))[5]['branch']
2006 if newb != b:
2006 if newb != b:
2007 yield 'a', newb
2007 yield 'a', newb
2008 b = newb
2008 b = newb
2009 yield 'n', (r, list(p for p in cl.parentrevs(r)
2009 yield 'n', (r, list(p for p in cl.parentrevs(r)
2010 if p != -1))
2010 if p != -1))
2011 if tags:
2011 if tags:
2012 ls = labels.get(r)
2012 ls = labels.get(r)
2013 if ls:
2013 if ls:
2014 for l in ls:
2014 for l in ls:
2015 yield 'l', (r, l)
2015 yield 'l', (r, l)
2016 else:
2016 else:
2017 raise util.Abort(_('need repo for changelog dag'))
2017 raise util.Abort(_('need repo for changelog dag'))
2018
2018
2019 for line in dagparser.dagtextlines(events(),
2019 for line in dagparser.dagtextlines(events(),
2020 addspaces=spaces,
2020 addspaces=spaces,
2021 wraplabels=True,
2021 wraplabels=True,
2022 wrapannotations=True,
2022 wrapannotations=True,
2023 wrapnonlinear=dots,
2023 wrapnonlinear=dots,
2024 usedots=dots,
2024 usedots=dots,
2025 maxlinewidth=70):
2025 maxlinewidth=70):
2026 ui.write(line)
2026 ui.write(line)
2027 ui.write("\n")
2027 ui.write("\n")
2028
2028
2029 @command('debugdata',
2029 @command('debugdata',
2030 [('c', 'changelog', False, _('open changelog')),
2030 [('c', 'changelog', False, _('open changelog')),
2031 ('m', 'manifest', False, _('open manifest'))],
2031 ('m', 'manifest', False, _('open manifest'))],
2032 _('-c|-m|FILE REV'))
2032 _('-c|-m|FILE REV'))
2033 def debugdata(ui, repo, file_, rev=None, **opts):
2033 def debugdata(ui, repo, file_, rev=None, **opts):
2034 """dump the contents of a data file revision"""
2034 """dump the contents of a data file revision"""
2035 if opts.get('changelog') or opts.get('manifest'):
2035 if opts.get('changelog') or opts.get('manifest'):
2036 file_, rev = None, file_
2036 file_, rev = None, file_
2037 elif rev is None:
2037 elif rev is None:
2038 raise error.CommandError('debugdata', _('invalid arguments'))
2038 raise error.CommandError('debugdata', _('invalid arguments'))
2039 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2039 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2040 try:
2040 try:
2041 ui.write(r.revision(r.lookup(rev)))
2041 ui.write(r.revision(r.lookup(rev)))
2042 except KeyError:
2042 except KeyError:
2043 raise util.Abort(_('invalid revision identifier %s') % rev)
2043 raise util.Abort(_('invalid revision identifier %s') % rev)
2044
2044
2045 @command('debugdate',
2045 @command('debugdate',
2046 [('e', 'extended', None, _('try extended date formats'))],
2046 [('e', 'extended', None, _('try extended date formats'))],
2047 _('[-e] DATE [RANGE]'),
2047 _('[-e] DATE [RANGE]'),
2048 norepo=True, optionalrepo=True)
2048 norepo=True, optionalrepo=True)
2049 def debugdate(ui, date, range=None, **opts):
2049 def debugdate(ui, date, range=None, **opts):
2050 """parse and display a date"""
2050 """parse and display a date"""
2051 if opts["extended"]:
2051 if opts["extended"]:
2052 d = util.parsedate(date, util.extendeddateformats)
2052 d = util.parsedate(date, util.extendeddateformats)
2053 else:
2053 else:
2054 d = util.parsedate(date)
2054 d = util.parsedate(date)
2055 ui.write(("internal: %s %s\n") % d)
2055 ui.write(("internal: %s %s\n") % d)
2056 ui.write(("standard: %s\n") % util.datestr(d))
2056 ui.write(("standard: %s\n") % util.datestr(d))
2057 if range:
2057 if range:
2058 m = util.matchdate(range)
2058 m = util.matchdate(range)
2059 ui.write(("match: %s\n") % m(d[0]))
2059 ui.write(("match: %s\n") % m(d[0]))
2060
2060
2061 @command('debugdiscovery',
2061 @command('debugdiscovery',
2062 [('', 'old', None, _('use old-style discovery')),
2062 [('', 'old', None, _('use old-style discovery')),
2063 ('', 'nonheads', None,
2063 ('', 'nonheads', None,
2064 _('use old-style discovery with non-heads included')),
2064 _('use old-style discovery with non-heads included')),
2065 ] + remoteopts,
2065 ] + remoteopts,
2066 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2066 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2067 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2067 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2068 """runs the changeset discovery protocol in isolation"""
2068 """runs the changeset discovery protocol in isolation"""
2069 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2069 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2070 opts.get('branch'))
2070 opts.get('branch'))
2071 remote = hg.peer(repo, opts, remoteurl)
2071 remote = hg.peer(repo, opts, remoteurl)
2072 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2072 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2073
2073
2074 # make sure tests are repeatable
2074 # make sure tests are repeatable
2075 random.seed(12323)
2075 random.seed(12323)
2076
2076
2077 def doit(localheads, remoteheads, remote=remote):
2077 def doit(localheads, remoteheads, remote=remote):
2078 if opts.get('old'):
2078 if opts.get('old'):
2079 if localheads:
2079 if localheads:
2080 raise util.Abort('cannot use localheads with old style '
2080 raise util.Abort('cannot use localheads with old style '
2081 'discovery')
2081 'discovery')
2082 if not util.safehasattr(remote, 'branches'):
2082 if not util.safehasattr(remote, 'branches'):
2083 # enable in-client legacy support
2083 # enable in-client legacy support
2084 remote = localrepo.locallegacypeer(remote.local())
2084 remote = localrepo.locallegacypeer(remote.local())
2085 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2085 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2086 force=True)
2086 force=True)
2087 common = set(common)
2087 common = set(common)
2088 if not opts.get('nonheads'):
2088 if not opts.get('nonheads'):
2089 ui.write(("unpruned common: %s\n") %
2089 ui.write(("unpruned common: %s\n") %
2090 " ".join(sorted(short(n) for n in common)))
2090 " ".join(sorted(short(n) for n in common)))
2091 dag = dagutil.revlogdag(repo.changelog)
2091 dag = dagutil.revlogdag(repo.changelog)
2092 all = dag.ancestorset(dag.internalizeall(common))
2092 all = dag.ancestorset(dag.internalizeall(common))
2093 common = dag.externalizeall(dag.headsetofconnecteds(all))
2093 common = dag.externalizeall(dag.headsetofconnecteds(all))
2094 else:
2094 else:
2095 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2095 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2096 common = set(common)
2096 common = set(common)
2097 rheads = set(hds)
2097 rheads = set(hds)
2098 lheads = set(repo.heads())
2098 lheads = set(repo.heads())
2099 ui.write(("common heads: %s\n") %
2099 ui.write(("common heads: %s\n") %
2100 " ".join(sorted(short(n) for n in common)))
2100 " ".join(sorted(short(n) for n in common)))
2101 if lheads <= common:
2101 if lheads <= common:
2102 ui.write(("local is subset\n"))
2102 ui.write(("local is subset\n"))
2103 elif rheads <= common:
2103 elif rheads <= common:
2104 ui.write(("remote is subset\n"))
2104 ui.write(("remote is subset\n"))
2105
2105
2106 serverlogs = opts.get('serverlog')
2106 serverlogs = opts.get('serverlog')
2107 if serverlogs:
2107 if serverlogs:
2108 for filename in serverlogs:
2108 for filename in serverlogs:
2109 logfile = open(filename, 'r')
2109 logfile = open(filename, 'r')
2110 try:
2110 try:
2111 line = logfile.readline()
2111 line = logfile.readline()
2112 while line:
2112 while line:
2113 parts = line.strip().split(';')
2113 parts = line.strip().split(';')
2114 op = parts[1]
2114 op = parts[1]
2115 if op == 'cg':
2115 if op == 'cg':
2116 pass
2116 pass
2117 elif op == 'cgss':
2117 elif op == 'cgss':
2118 doit(parts[2].split(' '), parts[3].split(' '))
2118 doit(parts[2].split(' '), parts[3].split(' '))
2119 elif op == 'unb':
2119 elif op == 'unb':
2120 doit(parts[3].split(' '), parts[2].split(' '))
2120 doit(parts[3].split(' '), parts[2].split(' '))
2121 line = logfile.readline()
2121 line = logfile.readline()
2122 finally:
2122 finally:
2123 logfile.close()
2123 logfile.close()
2124
2124
2125 else:
2125 else:
2126 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2126 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2127 opts.get('remote_head'))
2127 opts.get('remote_head'))
2128 localrevs = opts.get('local_head')
2128 localrevs = opts.get('local_head')
2129 doit(localrevs, remoterevs)
2129 doit(localrevs, remoterevs)
2130
2130
2131 @command('debugfileset',
2131 @command('debugfileset',
2132 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2132 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2133 _('[-r REV] FILESPEC'))
2133 _('[-r REV] FILESPEC'))
2134 def debugfileset(ui, repo, expr, **opts):
2134 def debugfileset(ui, repo, expr, **opts):
2135 '''parse and apply a fileset specification'''
2135 '''parse and apply a fileset specification'''
2136 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2136 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2137 if ui.verbose:
2137 if ui.verbose:
2138 tree = fileset.parse(expr)[0]
2138 tree = fileset.parse(expr)[0]
2139 ui.note(tree, "\n")
2139 ui.note(tree, "\n")
2140
2140
2141 for f in ctx.getfileset(expr):
2141 for f in ctx.getfileset(expr):
2142 ui.write("%s\n" % f)
2142 ui.write("%s\n" % f)
2143
2143
2144 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2144 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2145 def debugfsinfo(ui, path="."):
2145 def debugfsinfo(ui, path="."):
2146 """show information detected about current filesystem"""
2146 """show information detected about current filesystem"""
2147 util.writefile('.debugfsinfo', '')
2147 util.writefile('.debugfsinfo', '')
2148 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2148 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2149 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2149 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2150 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2150 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2151 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2151 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2152 and 'yes' or 'no'))
2152 and 'yes' or 'no'))
2153 os.unlink('.debugfsinfo')
2153 os.unlink('.debugfsinfo')
2154
2154
2155 @command('debuggetbundle',
2155 @command('debuggetbundle',
2156 [('H', 'head', [], _('id of head node'), _('ID')),
2156 [('H', 'head', [], _('id of head node'), _('ID')),
2157 ('C', 'common', [], _('id of common node'), _('ID')),
2157 ('C', 'common', [], _('id of common node'), _('ID')),
2158 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2158 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2159 _('REPO FILE [-H|-C ID]...'),
2159 _('REPO FILE [-H|-C ID]...'),
2160 norepo=True)
2160 norepo=True)
2161 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2161 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2162 """retrieves a bundle from a repo
2162 """retrieves a bundle from a repo
2163
2163
2164 Every ID must be a full-length hex node id string. Saves the bundle to the
2164 Every ID must be a full-length hex node id string. Saves the bundle to the
2165 given file.
2165 given file.
2166 """
2166 """
2167 repo = hg.peer(ui, opts, repopath)
2167 repo = hg.peer(ui, opts, repopath)
2168 if not repo.capable('getbundle'):
2168 if not repo.capable('getbundle'):
2169 raise util.Abort("getbundle() not supported by target repository")
2169 raise util.Abort("getbundle() not supported by target repository")
2170 args = {}
2170 args = {}
2171 if common:
2171 if common:
2172 args['common'] = [bin(s) for s in common]
2172 args['common'] = [bin(s) for s in common]
2173 if head:
2173 if head:
2174 args['heads'] = [bin(s) for s in head]
2174 args['heads'] = [bin(s) for s in head]
2175 # TODO: get desired bundlecaps from command line.
2175 # TODO: get desired bundlecaps from command line.
2176 args['bundlecaps'] = None
2176 args['bundlecaps'] = None
2177 bundle = repo.getbundle('debug', **args)
2177 bundle = repo.getbundle('debug', **args)
2178
2178
2179 bundletype = opts.get('type', 'bzip2').lower()
2179 bundletype = opts.get('type', 'bzip2').lower()
2180 btypes = {'none': 'HG10UN',
2180 btypes = {'none': 'HG10UN',
2181 'bzip2': 'HG10BZ',
2181 'bzip2': 'HG10BZ',
2182 'gzip': 'HG10GZ',
2182 'gzip': 'HG10GZ',
2183 'bundle2': 'HG2Y'}
2183 'bundle2': 'HG2Y'}
2184 bundletype = btypes.get(bundletype)
2184 bundletype = btypes.get(bundletype)
2185 if bundletype not in changegroup.bundletypes:
2185 if bundletype not in changegroup.bundletypes:
2186 raise util.Abort(_('unknown bundle type specified with --type'))
2186 raise util.Abort(_('unknown bundle type specified with --type'))
2187 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2187 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2188
2188
2189 @command('debugignore', [], '')
2189 @command('debugignore', [], '')
2190 def debugignore(ui, repo, *values, **opts):
2190 def debugignore(ui, repo, *values, **opts):
2191 """display the combined ignore pattern"""
2191 """display the combined ignore pattern"""
2192 ignore = repo.dirstate._ignore
2192 ignore = repo.dirstate._ignore
2193 includepat = getattr(ignore, 'includepat', None)
2193 includepat = getattr(ignore, 'includepat', None)
2194 if includepat is not None:
2194 if includepat is not None:
2195 ui.write("%s\n" % includepat)
2195 ui.write("%s\n" % includepat)
2196 else:
2196 else:
2197 raise util.Abort(_("no ignore patterns found"))
2197 raise util.Abort(_("no ignore patterns found"))
2198
2198
2199 @command('debugindex',
2199 @command('debugindex',
2200 [('c', 'changelog', False, _('open changelog')),
2200 [('c', 'changelog', False, _('open changelog')),
2201 ('m', 'manifest', False, _('open manifest')),
2201 ('m', 'manifest', False, _('open manifest')),
2202 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2202 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2203 _('[-f FORMAT] -c|-m|FILE'),
2203 _('[-f FORMAT] -c|-m|FILE'),
2204 optionalrepo=True)
2204 optionalrepo=True)
2205 def debugindex(ui, repo, file_=None, **opts):
2205 def debugindex(ui, repo, file_=None, **opts):
2206 """dump the contents of an index file"""
2206 """dump the contents of an index file"""
2207 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2207 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2208 format = opts.get('format', 0)
2208 format = opts.get('format', 0)
2209 if format not in (0, 1):
2209 if format not in (0, 1):
2210 raise util.Abort(_("unknown format %d") % format)
2210 raise util.Abort(_("unknown format %d") % format)
2211
2211
2212 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2212 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2213 if generaldelta:
2213 if generaldelta:
2214 basehdr = ' delta'
2214 basehdr = ' delta'
2215 else:
2215 else:
2216 basehdr = ' base'
2216 basehdr = ' base'
2217
2217
2218 if ui.debugflag:
2218 if ui.debugflag:
2219 shortfn = hex
2219 shortfn = hex
2220 else:
2220 else:
2221 shortfn = short
2221 shortfn = short
2222
2222
2223 # There might not be anything in r, so have a sane default
2223 # There might not be anything in r, so have a sane default
2224 idlen = 12
2224 idlen = 12
2225 for i in r:
2225 for i in r:
2226 idlen = len(shortfn(r.node(i)))
2226 idlen = len(shortfn(r.node(i)))
2227 break
2227 break
2228
2228
2229 if format == 0:
2229 if format == 0:
2230 ui.write(" rev offset length " + basehdr + " linkrev"
2230 ui.write(" rev offset length " + basehdr + " linkrev"
2231 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2231 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2232 elif format == 1:
2232 elif format == 1:
2233 ui.write(" rev flag offset length"
2233 ui.write(" rev flag offset length"
2234 " size " + basehdr + " link p1 p2"
2234 " size " + basehdr + " link p1 p2"
2235 " %s\n" % "nodeid".rjust(idlen))
2235 " %s\n" % "nodeid".rjust(idlen))
2236
2236
2237 for i in r:
2237 for i in r:
2238 node = r.node(i)
2238 node = r.node(i)
2239 if generaldelta:
2239 if generaldelta:
2240 base = r.deltaparent(i)
2240 base = r.deltaparent(i)
2241 else:
2241 else:
2242 base = r.chainbase(i)
2242 base = r.chainbase(i)
2243 if format == 0:
2243 if format == 0:
2244 try:
2244 try:
2245 pp = r.parents(node)
2245 pp = r.parents(node)
2246 except Exception:
2246 except Exception:
2247 pp = [nullid, nullid]
2247 pp = [nullid, nullid]
2248 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2248 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2249 i, r.start(i), r.length(i), base, r.linkrev(i),
2249 i, r.start(i), r.length(i), base, r.linkrev(i),
2250 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2250 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2251 elif format == 1:
2251 elif format == 1:
2252 pr = r.parentrevs(i)
2252 pr = r.parentrevs(i)
2253 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2253 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2254 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2254 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2255 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2255 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2256
2256
2257 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2257 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2258 def debugindexdot(ui, repo, file_):
2258 def debugindexdot(ui, repo, file_):
2259 """dump an index DAG as a graphviz dot file"""
2259 """dump an index DAG as a graphviz dot file"""
2260 r = None
2260 r = None
2261 if repo:
2261 if repo:
2262 filelog = repo.file(file_)
2262 filelog = repo.file(file_)
2263 if len(filelog):
2263 if len(filelog):
2264 r = filelog
2264 r = filelog
2265 if not r:
2265 if not r:
2266 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2266 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2267 ui.write(("digraph G {\n"))
2267 ui.write(("digraph G {\n"))
2268 for i in r:
2268 for i in r:
2269 node = r.node(i)
2269 node = r.node(i)
2270 pp = r.parents(node)
2270 pp = r.parents(node)
2271 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2271 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2272 if pp[1] != nullid:
2272 if pp[1] != nullid:
2273 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2273 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2274 ui.write("}\n")
2274 ui.write("}\n")
2275
2275
2276 @command('debuginstall', [], '', norepo=True)
2276 @command('debuginstall', [], '', norepo=True)
2277 def debuginstall(ui):
2277 def debuginstall(ui):
2278 '''test Mercurial installation
2278 '''test Mercurial installation
2279
2279
2280 Returns 0 on success.
2280 Returns 0 on success.
2281 '''
2281 '''
2282
2282
2283 def writetemp(contents):
2283 def writetemp(contents):
2284 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2284 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2285 f = os.fdopen(fd, "wb")
2285 f = os.fdopen(fd, "wb")
2286 f.write(contents)
2286 f.write(contents)
2287 f.close()
2287 f.close()
2288 return name
2288 return name
2289
2289
2290 problems = 0
2290 problems = 0
2291
2291
2292 # encoding
2292 # encoding
2293 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2293 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2294 try:
2294 try:
2295 encoding.fromlocal("test")
2295 encoding.fromlocal("test")
2296 except util.Abort, inst:
2296 except util.Abort, inst:
2297 ui.write(" %s\n" % inst)
2297 ui.write(" %s\n" % inst)
2298 ui.write(_(" (check that your locale is properly set)\n"))
2298 ui.write(_(" (check that your locale is properly set)\n"))
2299 problems += 1
2299 problems += 1
2300
2300
2301 # Python
2301 # Python
2302 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2302 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2303 ui.status(_("checking Python version (%s)\n")
2303 ui.status(_("checking Python version (%s)\n")
2304 % ("%s.%s.%s" % sys.version_info[:3]))
2304 % ("%s.%s.%s" % sys.version_info[:3]))
2305 ui.status(_("checking Python lib (%s)...\n")
2305 ui.status(_("checking Python lib (%s)...\n")
2306 % os.path.dirname(os.__file__))
2306 % os.path.dirname(os.__file__))
2307
2307
2308 # compiled modules
2308 # compiled modules
2309 ui.status(_("checking installed modules (%s)...\n")
2309 ui.status(_("checking installed modules (%s)...\n")
2310 % os.path.dirname(__file__))
2310 % os.path.dirname(__file__))
2311 try:
2311 try:
2312 import bdiff, mpatch, base85, osutil
2312 import bdiff, mpatch, base85, osutil
2313 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2313 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2314 except Exception, inst:
2314 except Exception, inst:
2315 ui.write(" %s\n" % inst)
2315 ui.write(" %s\n" % inst)
2316 ui.write(_(" One or more extensions could not be found"))
2316 ui.write(_(" One or more extensions could not be found"))
2317 ui.write(_(" (check that you compiled the extensions)\n"))
2317 ui.write(_(" (check that you compiled the extensions)\n"))
2318 problems += 1
2318 problems += 1
2319
2319
2320 # templates
2320 # templates
2321 import templater
2321 import templater
2322 p = templater.templatepaths()
2322 p = templater.templatepaths()
2323 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2323 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2324 if p:
2324 if p:
2325 m = templater.templatepath("map-cmdline.default")
2325 m = templater.templatepath("map-cmdline.default")
2326 if m:
2326 if m:
2327 # template found, check if it is working
2327 # template found, check if it is working
2328 try:
2328 try:
2329 templater.templater(m)
2329 templater.templater(m)
2330 except Exception, inst:
2330 except Exception, inst:
2331 ui.write(" %s\n" % inst)
2331 ui.write(" %s\n" % inst)
2332 p = None
2332 p = None
2333 else:
2333 else:
2334 ui.write(_(" template 'default' not found\n"))
2334 ui.write(_(" template 'default' not found\n"))
2335 p = None
2335 p = None
2336 else:
2336 else:
2337 ui.write(_(" no template directories found\n"))
2337 ui.write(_(" no template directories found\n"))
2338 if not p:
2338 if not p:
2339 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2339 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2340 problems += 1
2340 problems += 1
2341
2341
2342 # editor
2342 # editor
2343 ui.status(_("checking commit editor...\n"))
2343 ui.status(_("checking commit editor...\n"))
2344 editor = ui.geteditor()
2344 editor = ui.geteditor()
2345 cmdpath = util.findexe(shlex.split(editor)[0])
2345 cmdpath = util.findexe(shlex.split(editor)[0])
2346 if not cmdpath:
2346 if not cmdpath:
2347 if editor == 'vi':
2347 if editor == 'vi':
2348 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2348 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2349 ui.write(_(" (specify a commit editor in your configuration"
2349 ui.write(_(" (specify a commit editor in your configuration"
2350 " file)\n"))
2350 " file)\n"))
2351 else:
2351 else:
2352 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2352 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2353 ui.write(_(" (specify a commit editor in your configuration"
2353 ui.write(_(" (specify a commit editor in your configuration"
2354 " file)\n"))
2354 " file)\n"))
2355 problems += 1
2355 problems += 1
2356
2356
2357 # check username
2357 # check username
2358 ui.status(_("checking username...\n"))
2358 ui.status(_("checking username...\n"))
2359 try:
2359 try:
2360 ui.username()
2360 ui.username()
2361 except util.Abort, e:
2361 except util.Abort, e:
2362 ui.write(" %s\n" % e)
2362 ui.write(" %s\n" % e)
2363 ui.write(_(" (specify a username in your configuration file)\n"))
2363 ui.write(_(" (specify a username in your configuration file)\n"))
2364 problems += 1
2364 problems += 1
2365
2365
2366 if not problems:
2366 if not problems:
2367 ui.status(_("no problems detected\n"))
2367 ui.status(_("no problems detected\n"))
2368 else:
2368 else:
2369 ui.write(_("%s problems detected,"
2369 ui.write(_("%s problems detected,"
2370 " please check your install!\n") % problems)
2370 " please check your install!\n") % problems)
2371
2371
2372 return problems
2372 return problems
2373
2373
2374 @command('debugknown', [], _('REPO ID...'), norepo=True)
2374 @command('debugknown', [], _('REPO ID...'), norepo=True)
2375 def debugknown(ui, repopath, *ids, **opts):
2375 def debugknown(ui, repopath, *ids, **opts):
2376 """test whether node ids are known to a repo
2376 """test whether node ids are known to a repo
2377
2377
2378 Every ID must be a full-length hex node id string. Returns a list of 0s
2378 Every ID must be a full-length hex node id string. Returns a list of 0s
2379 and 1s indicating unknown/known.
2379 and 1s indicating unknown/known.
2380 """
2380 """
2381 repo = hg.peer(ui, opts, repopath)
2381 repo = hg.peer(ui, opts, repopath)
2382 if not repo.capable('known'):
2382 if not repo.capable('known'):
2383 raise util.Abort("known() not supported by target repository")
2383 raise util.Abort("known() not supported by target repository")
2384 flags = repo.known([bin(s) for s in ids])
2384 flags = repo.known([bin(s) for s in ids])
2385 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2385 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2386
2386
2387 @command('debuglabelcomplete', [], _('LABEL...'))
2387 @command('debuglabelcomplete', [], _('LABEL...'))
2388 def debuglabelcomplete(ui, repo, *args):
2388 def debuglabelcomplete(ui, repo, *args):
2389 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2389 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2390 debugnamecomplete(ui, repo, *args)
2390 debugnamecomplete(ui, repo, *args)
2391
2391
2392 @command('debugnamecomplete', [], _('NAME...'))
2392 @command('debugnamecomplete', [], _('NAME...'))
2393 def debugnamecomplete(ui, repo, *args):
2393 def debugnamecomplete(ui, repo, *args):
2394 '''complete "names" - tags, open branch names, bookmark names'''
2394 '''complete "names" - tags, open branch names, bookmark names'''
2395
2395
2396 names = set()
2396 names = set()
2397 # since we previously only listed open branches, we will handle that
2397 # since we previously only listed open branches, we will handle that
2398 # specially (after this for loop)
2398 # specially (after this for loop)
2399 for name, ns in repo.names.iteritems():
2399 for name, ns in repo.names.iteritems():
2400 if name != 'branches':
2400 if name != 'branches':
2401 names.update(ns.listnames(repo))
2401 names.update(ns.listnames(repo))
2402 names.update(tag for (tag, heads, tip, closed)
2402 names.update(tag for (tag, heads, tip, closed)
2403 in repo.branchmap().iterbranches() if not closed)
2403 in repo.branchmap().iterbranches() if not closed)
2404 completions = set()
2404 completions = set()
2405 if not args:
2405 if not args:
2406 args = ['']
2406 args = ['']
2407 for a in args:
2407 for a in args:
2408 completions.update(n for n in names if n.startswith(a))
2408 completions.update(n for n in names if n.startswith(a))
2409 ui.write('\n'.join(sorted(completions)))
2409 ui.write('\n'.join(sorted(completions)))
2410 ui.write('\n')
2410 ui.write('\n')
2411
2411
2412 @command('debuglocks',
2412 @command('debuglocks',
2413 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2413 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2414 ('W', 'force-wlock', None,
2414 ('W', 'force-wlock', None,
2415 _('free the working state lock (DANGEROUS)'))],
2415 _('free the working state lock (DANGEROUS)'))],
2416 _('[OPTION]...'))
2416 _('[OPTION]...'))
2417 def debuglocks(ui, repo, **opts):
2417 def debuglocks(ui, repo, **opts):
2418 """show or modify state of locks
2418 """show or modify state of locks
2419
2419
2420 By default, this command will show which locks are held. This
2420 By default, this command will show which locks are held. This
2421 includes the user and process holding the lock, the amount of time
2421 includes the user and process holding the lock, the amount of time
2422 the lock has been held, and the machine name where the process is
2422 the lock has been held, and the machine name where the process is
2423 running if it's not local.
2423 running if it's not local.
2424
2424
2425 Locks protect the integrity of Mercurial's data, so should be
2425 Locks protect the integrity of Mercurial's data, so should be
2426 treated with care. System crashes or other interruptions may cause
2426 treated with care. System crashes or other interruptions may cause
2427 locks to not be properly released, though Mercurial will usually
2427 locks to not be properly released, though Mercurial will usually
2428 detect and remove such stale locks automatically.
2428 detect and remove such stale locks automatically.
2429
2429
2430 However, detecting stale locks may not always be possible (for
2430 However, detecting stale locks may not always be possible (for
2431 instance, on a shared filesystem). Removing locks may also be
2431 instance, on a shared filesystem). Removing locks may also be
2432 blocked by filesystem permissions.
2432 blocked by filesystem permissions.
2433
2433
2434 Returns 0 if no locks are held.
2434 Returns 0 if no locks are held.
2435
2435
2436 """
2436 """
2437
2437
2438 if opts.get('force_lock'):
2438 if opts.get('force_lock'):
2439 repo.svfs.unlink('lock')
2439 repo.svfs.unlink('lock')
2440 if opts.get('force_wlock'):
2440 if opts.get('force_wlock'):
2441 repo.vfs.unlink('wlock')
2441 repo.vfs.unlink('wlock')
2442 if opts.get('force_lock') or opts.get('force_lock'):
2442 if opts.get('force_lock') or opts.get('force_lock'):
2443 return 0
2443 return 0
2444
2444
2445 now = time.time()
2445 now = time.time()
2446 held = 0
2446 held = 0
2447
2447
2448 def report(vfs, name, method):
2448 def report(vfs, name, method):
2449 # this causes stale locks to get reaped for more accurate reporting
2449 # this causes stale locks to get reaped for more accurate reporting
2450 try:
2450 try:
2451 l = method(False)
2451 l = method(False)
2452 except error.LockHeld:
2452 except error.LockHeld:
2453 l = None
2453 l = None
2454
2454
2455 if l:
2455 if l:
2456 l.release()
2456 l.release()
2457 else:
2457 else:
2458 try:
2458 try:
2459 stat = repo.svfs.lstat(name)
2459 stat = repo.svfs.lstat(name)
2460 age = now - stat.st_mtime
2460 age = now - stat.st_mtime
2461 user = util.username(stat.st_uid)
2461 user = util.username(stat.st_uid)
2462 locker = vfs.readlock(name)
2462 locker = vfs.readlock(name)
2463 if ":" in locker:
2463 if ":" in locker:
2464 host, pid = locker.split(':')
2464 host, pid = locker.split(':')
2465 if host == socket.gethostname():
2465 if host == socket.gethostname():
2466 locker = 'user %s, process %s' % (user, pid)
2466 locker = 'user %s, process %s' % (user, pid)
2467 else:
2467 else:
2468 locker = 'user %s, process %s, host %s' \
2468 locker = 'user %s, process %s, host %s' \
2469 % (user, pid, host)
2469 % (user, pid, host)
2470 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2470 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2471 return 1
2471 return 1
2472 except OSError, e:
2472 except OSError, e:
2473 if e.errno != errno.ENOENT:
2473 if e.errno != errno.ENOENT:
2474 raise
2474 raise
2475
2475
2476 ui.write("%-6s free\n" % (name + ":"))
2476 ui.write("%-6s free\n" % (name + ":"))
2477 return 0
2477 return 0
2478
2478
2479 held += report(repo.svfs, "lock", repo.lock)
2479 held += report(repo.svfs, "lock", repo.lock)
2480 held += report(repo.vfs, "wlock", repo.wlock)
2480 held += report(repo.vfs, "wlock", repo.wlock)
2481
2481
2482 return held
2482 return held
2483
2483
2484 @command('debugobsolete',
2484 @command('debugobsolete',
2485 [('', 'flags', 0, _('markers flag')),
2485 [('', 'flags', 0, _('markers flag')),
2486 ('', 'record-parents', False,
2486 ('', 'record-parents', False,
2487 _('record parent information for the precursor')),
2487 _('record parent information for the precursor')),
2488 ('r', 'rev', [], _('display markers relevant to REV')),
2488 ('r', 'rev', [], _('display markers relevant to REV')),
2489 ] + commitopts2,
2489 ] + commitopts2,
2490 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2490 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2491 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2491 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2492 """create arbitrary obsolete marker
2492 """create arbitrary obsolete marker
2493
2493
2494 With no arguments, displays the list of obsolescence markers."""
2494 With no arguments, displays the list of obsolescence markers."""
2495
2495
2496 def parsenodeid(s):
2496 def parsenodeid(s):
2497 try:
2497 try:
2498 # We do not use revsingle/revrange functions here to accept
2498 # We do not use revsingle/revrange functions here to accept
2499 # arbitrary node identifiers, possibly not present in the
2499 # arbitrary node identifiers, possibly not present in the
2500 # local repository.
2500 # local repository.
2501 n = bin(s)
2501 n = bin(s)
2502 if len(n) != len(nullid):
2502 if len(n) != len(nullid):
2503 raise TypeError()
2503 raise TypeError()
2504 return n
2504 return n
2505 except TypeError:
2505 except TypeError:
2506 raise util.Abort('changeset references must be full hexadecimal '
2506 raise util.Abort('changeset references must be full hexadecimal '
2507 'node identifiers')
2507 'node identifiers')
2508
2508
2509 if precursor is not None:
2509 if precursor is not None:
2510 if opts['rev']:
2510 if opts['rev']:
2511 raise util.Abort('cannot select revision when creating marker')
2511 raise util.Abort('cannot select revision when creating marker')
2512 metadata = {}
2512 metadata = {}
2513 metadata['user'] = opts['user'] or ui.username()
2513 metadata['user'] = opts['user'] or ui.username()
2514 succs = tuple(parsenodeid(succ) for succ in successors)
2514 succs = tuple(parsenodeid(succ) for succ in successors)
2515 l = repo.lock()
2515 l = repo.lock()
2516 try:
2516 try:
2517 tr = repo.transaction('debugobsolete')
2517 tr = repo.transaction('debugobsolete')
2518 try:
2518 try:
2519 try:
2519 try:
2520 date = opts.get('date')
2520 date = opts.get('date')
2521 if date:
2521 if date:
2522 date = util.parsedate(date)
2522 date = util.parsedate(date)
2523 else:
2523 else:
2524 date = None
2524 date = None
2525 prec = parsenodeid(precursor)
2525 prec = parsenodeid(precursor)
2526 parents = None
2526 parents = None
2527 if opts['record_parents']:
2527 if opts['record_parents']:
2528 if prec not in repo.unfiltered():
2528 if prec not in repo.unfiltered():
2529 raise util.Abort('cannot used --record-parents on '
2529 raise util.Abort('cannot used --record-parents on '
2530 'unknown changesets')
2530 'unknown changesets')
2531 parents = repo.unfiltered()[prec].parents()
2531 parents = repo.unfiltered()[prec].parents()
2532 parents = tuple(p.node() for p in parents)
2532 parents = tuple(p.node() for p in parents)
2533 repo.obsstore.create(tr, prec, succs, opts['flags'],
2533 repo.obsstore.create(tr, prec, succs, opts['flags'],
2534 parents=parents, date=date,
2534 parents=parents, date=date,
2535 metadata=metadata)
2535 metadata=metadata)
2536 tr.close()
2536 tr.close()
2537 except ValueError, exc:
2537 except ValueError, exc:
2538 raise util.Abort(_('bad obsmarker input: %s') % exc)
2538 raise util.Abort(_('bad obsmarker input: %s') % exc)
2539 finally:
2539 finally:
2540 tr.release()
2540 tr.release()
2541 finally:
2541 finally:
2542 l.release()
2542 l.release()
2543 else:
2543 else:
2544 if opts['rev']:
2544 if opts['rev']:
2545 revs = scmutil.revrange(repo, opts['rev'])
2545 revs = scmutil.revrange(repo, opts['rev'])
2546 nodes = [repo[r].node() for r in revs]
2546 nodes = [repo[r].node() for r in revs]
2547 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2547 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2548 markers.sort(key=lambda x: x._data)
2548 markers.sort(key=lambda x: x._data)
2549 else:
2549 else:
2550 markers = obsolete.getmarkers(repo)
2550 markers = obsolete.getmarkers(repo)
2551
2551
2552 for m in markers:
2552 for m in markers:
2553 cmdutil.showmarker(ui, m)
2553 cmdutil.showmarker(ui, m)
2554
2554
2555 @command('debugpathcomplete',
2555 @command('debugpathcomplete',
2556 [('f', 'full', None, _('complete an entire path')),
2556 [('f', 'full', None, _('complete an entire path')),
2557 ('n', 'normal', None, _('show only normal files')),
2557 ('n', 'normal', None, _('show only normal files')),
2558 ('a', 'added', None, _('show only added files')),
2558 ('a', 'added', None, _('show only added files')),
2559 ('r', 'removed', None, _('show only removed files'))],
2559 ('r', 'removed', None, _('show only removed files'))],
2560 _('FILESPEC...'))
2560 _('FILESPEC...'))
2561 def debugpathcomplete(ui, repo, *specs, **opts):
2561 def debugpathcomplete(ui, repo, *specs, **opts):
2562 '''complete part or all of a tracked path
2562 '''complete part or all of a tracked path
2563
2563
2564 This command supports shells that offer path name completion. It
2564 This command supports shells that offer path name completion. It
2565 currently completes only files already known to the dirstate.
2565 currently completes only files already known to the dirstate.
2566
2566
2567 Completion extends only to the next path segment unless
2567 Completion extends only to the next path segment unless
2568 --full is specified, in which case entire paths are used.'''
2568 --full is specified, in which case entire paths are used.'''
2569
2569
2570 def complete(path, acceptable):
2570 def complete(path, acceptable):
2571 dirstate = repo.dirstate
2571 dirstate = repo.dirstate
2572 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2572 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2573 rootdir = repo.root + os.sep
2573 rootdir = repo.root + os.sep
2574 if spec != repo.root and not spec.startswith(rootdir):
2574 if spec != repo.root and not spec.startswith(rootdir):
2575 return [], []
2575 return [], []
2576 if os.path.isdir(spec):
2576 if os.path.isdir(spec):
2577 spec += '/'
2577 spec += '/'
2578 spec = spec[len(rootdir):]
2578 spec = spec[len(rootdir):]
2579 fixpaths = os.sep != '/'
2579 fixpaths = os.sep != '/'
2580 if fixpaths:
2580 if fixpaths:
2581 spec = spec.replace(os.sep, '/')
2581 spec = spec.replace(os.sep, '/')
2582 speclen = len(spec)
2582 speclen = len(spec)
2583 fullpaths = opts['full']
2583 fullpaths = opts['full']
2584 files, dirs = set(), set()
2584 files, dirs = set(), set()
2585 adddir, addfile = dirs.add, files.add
2585 adddir, addfile = dirs.add, files.add
2586 for f, st in dirstate.iteritems():
2586 for f, st in dirstate.iteritems():
2587 if f.startswith(spec) and st[0] in acceptable:
2587 if f.startswith(spec) and st[0] in acceptable:
2588 if fixpaths:
2588 if fixpaths:
2589 f = f.replace('/', os.sep)
2589 f = f.replace('/', os.sep)
2590 if fullpaths:
2590 if fullpaths:
2591 addfile(f)
2591 addfile(f)
2592 continue
2592 continue
2593 s = f.find(os.sep, speclen)
2593 s = f.find(os.sep, speclen)
2594 if s >= 0:
2594 if s >= 0:
2595 adddir(f[:s])
2595 adddir(f[:s])
2596 else:
2596 else:
2597 addfile(f)
2597 addfile(f)
2598 return files, dirs
2598 return files, dirs
2599
2599
2600 acceptable = ''
2600 acceptable = ''
2601 if opts['normal']:
2601 if opts['normal']:
2602 acceptable += 'nm'
2602 acceptable += 'nm'
2603 if opts['added']:
2603 if opts['added']:
2604 acceptable += 'a'
2604 acceptable += 'a'
2605 if opts['removed']:
2605 if opts['removed']:
2606 acceptable += 'r'
2606 acceptable += 'r'
2607 cwd = repo.getcwd()
2607 cwd = repo.getcwd()
2608 if not specs:
2608 if not specs:
2609 specs = ['.']
2609 specs = ['.']
2610
2610
2611 files, dirs = set(), set()
2611 files, dirs = set(), set()
2612 for spec in specs:
2612 for spec in specs:
2613 f, d = complete(spec, acceptable or 'nmar')
2613 f, d = complete(spec, acceptable or 'nmar')
2614 files.update(f)
2614 files.update(f)
2615 dirs.update(d)
2615 dirs.update(d)
2616 files.update(dirs)
2616 files.update(dirs)
2617 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2617 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2618 ui.write('\n')
2618 ui.write('\n')
2619
2619
2620 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2620 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2621 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2621 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2622 '''access the pushkey key/value protocol
2622 '''access the pushkey key/value protocol
2623
2623
2624 With two args, list the keys in the given namespace.
2624 With two args, list the keys in the given namespace.
2625
2625
2626 With five args, set a key to new if it currently is set to old.
2626 With five args, set a key to new if it currently is set to old.
2627 Reports success or failure.
2627 Reports success or failure.
2628 '''
2628 '''
2629
2629
2630 target = hg.peer(ui, {}, repopath)
2630 target = hg.peer(ui, {}, repopath)
2631 if keyinfo:
2631 if keyinfo:
2632 key, old, new = keyinfo
2632 key, old, new = keyinfo
2633 r = target.pushkey(namespace, key, old, new)
2633 r = target.pushkey(namespace, key, old, new)
2634 ui.status(str(r) + '\n')
2634 ui.status(str(r) + '\n')
2635 return not r
2635 return not r
2636 else:
2636 else:
2637 for k, v in sorted(target.listkeys(namespace).iteritems()):
2637 for k, v in sorted(target.listkeys(namespace).iteritems()):
2638 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2638 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2639 v.encode('string-escape')))
2639 v.encode('string-escape')))
2640
2640
2641 @command('debugpvec', [], _('A B'))
2641 @command('debugpvec', [], _('A B'))
2642 def debugpvec(ui, repo, a, b=None):
2642 def debugpvec(ui, repo, a, b=None):
2643 ca = scmutil.revsingle(repo, a)
2643 ca = scmutil.revsingle(repo, a)
2644 cb = scmutil.revsingle(repo, b)
2644 cb = scmutil.revsingle(repo, b)
2645 pa = pvec.ctxpvec(ca)
2645 pa = pvec.ctxpvec(ca)
2646 pb = pvec.ctxpvec(cb)
2646 pb = pvec.ctxpvec(cb)
2647 if pa == pb:
2647 if pa == pb:
2648 rel = "="
2648 rel = "="
2649 elif pa > pb:
2649 elif pa > pb:
2650 rel = ">"
2650 rel = ">"
2651 elif pa < pb:
2651 elif pa < pb:
2652 rel = "<"
2652 rel = "<"
2653 elif pa | pb:
2653 elif pa | pb:
2654 rel = "|"
2654 rel = "|"
2655 ui.write(_("a: %s\n") % pa)
2655 ui.write(_("a: %s\n") % pa)
2656 ui.write(_("b: %s\n") % pb)
2656 ui.write(_("b: %s\n") % pb)
2657 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2657 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2658 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2658 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2659 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2659 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2660 pa.distance(pb), rel))
2660 pa.distance(pb), rel))
2661
2661
2662 @command('debugrebuilddirstate|debugrebuildstate',
2662 @command('debugrebuilddirstate|debugrebuildstate',
2663 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2663 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2664 _('[-r REV]'))
2664 _('[-r REV]'))
2665 def debugrebuilddirstate(ui, repo, rev):
2665 def debugrebuilddirstate(ui, repo, rev):
2666 """rebuild the dirstate as it would look like for the given revision
2666 """rebuild the dirstate as it would look like for the given revision
2667
2667
2668 If no revision is specified the first current parent will be used.
2668 If no revision is specified the first current parent will be used.
2669
2669
2670 The dirstate will be set to the files of the given revision.
2670 The dirstate will be set to the files of the given revision.
2671 The actual working directory content or existing dirstate
2671 The actual working directory content or existing dirstate
2672 information such as adds or removes is not considered.
2672 information such as adds or removes is not considered.
2673
2673
2674 One use of this command is to make the next :hg:`status` invocation
2674 One use of this command is to make the next :hg:`status` invocation
2675 check the actual file content.
2675 check the actual file content.
2676 """
2676 """
2677 ctx = scmutil.revsingle(repo, rev)
2677 ctx = scmutil.revsingle(repo, rev)
2678 wlock = repo.wlock()
2678 wlock = repo.wlock()
2679 try:
2679 try:
2680 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2680 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2681 finally:
2681 finally:
2682 wlock.release()
2682 wlock.release()
2683
2683
2684 @command('debugrename',
2684 @command('debugrename',
2685 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2685 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2686 _('[-r REV] FILE'))
2686 _('[-r REV] FILE'))
2687 def debugrename(ui, repo, file1, *pats, **opts):
2687 def debugrename(ui, repo, file1, *pats, **opts):
2688 """dump rename information"""
2688 """dump rename information"""
2689
2689
2690 ctx = scmutil.revsingle(repo, opts.get('rev'))
2690 ctx = scmutil.revsingle(repo, opts.get('rev'))
2691 m = scmutil.match(ctx, (file1,) + pats, opts)
2691 m = scmutil.match(ctx, (file1,) + pats, opts)
2692 for abs in ctx.walk(m):
2692 for abs in ctx.walk(m):
2693 fctx = ctx[abs]
2693 fctx = ctx[abs]
2694 o = fctx.filelog().renamed(fctx.filenode())
2694 o = fctx.filelog().renamed(fctx.filenode())
2695 rel = m.rel(abs)
2695 rel = m.rel(abs)
2696 if o:
2696 if o:
2697 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2697 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2698 else:
2698 else:
2699 ui.write(_("%s not renamed\n") % rel)
2699 ui.write(_("%s not renamed\n") % rel)
2700
2700
2701 @command('debugrevlog',
2701 @command('debugrevlog',
2702 [('c', 'changelog', False, _('open changelog')),
2702 [('c', 'changelog', False, _('open changelog')),
2703 ('m', 'manifest', False, _('open manifest')),
2703 ('m', 'manifest', False, _('open manifest')),
2704 ('d', 'dump', False, _('dump index data'))],
2704 ('d', 'dump', False, _('dump index data'))],
2705 _('-c|-m|FILE'),
2705 _('-c|-m|FILE'),
2706 optionalrepo=True)
2706 optionalrepo=True)
2707 def debugrevlog(ui, repo, file_=None, **opts):
2707 def debugrevlog(ui, repo, file_=None, **opts):
2708 """show data and statistics about a revlog"""
2708 """show data and statistics about a revlog"""
2709 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2709 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2710
2710
2711 if opts.get("dump"):
2711 if opts.get("dump"):
2712 numrevs = len(r)
2712 numrevs = len(r)
2713 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2713 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2714 " rawsize totalsize compression heads chainlen\n")
2714 " rawsize totalsize compression heads chainlen\n")
2715 ts = 0
2715 ts = 0
2716 heads = set()
2716 heads = set()
2717
2717
2718 for rev in xrange(numrevs):
2718 for rev in xrange(numrevs):
2719 dbase = r.deltaparent(rev)
2719 dbase = r.deltaparent(rev)
2720 if dbase == -1:
2720 if dbase == -1:
2721 dbase = rev
2721 dbase = rev
2722 cbase = r.chainbase(rev)
2722 cbase = r.chainbase(rev)
2723 clen = r.chainlen(rev)
2723 clen = r.chainlen(rev)
2724 p1, p2 = r.parentrevs(rev)
2724 p1, p2 = r.parentrevs(rev)
2725 rs = r.rawsize(rev)
2725 rs = r.rawsize(rev)
2726 ts = ts + rs
2726 ts = ts + rs
2727 heads -= set(r.parentrevs(rev))
2727 heads -= set(r.parentrevs(rev))
2728 heads.add(rev)
2728 heads.add(rev)
2729 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2729 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2730 "%11d %5d %8d\n" %
2730 "%11d %5d %8d\n" %
2731 (rev, p1, p2, r.start(rev), r.end(rev),
2731 (rev, p1, p2, r.start(rev), r.end(rev),
2732 r.start(dbase), r.start(cbase),
2732 r.start(dbase), r.start(cbase),
2733 r.start(p1), r.start(p2),
2733 r.start(p1), r.start(p2),
2734 rs, ts, ts / r.end(rev), len(heads), clen))
2734 rs, ts, ts / r.end(rev), len(heads), clen))
2735 return 0
2735 return 0
2736
2736
2737 v = r.version
2737 v = r.version
2738 format = v & 0xFFFF
2738 format = v & 0xFFFF
2739 flags = []
2739 flags = []
2740 gdelta = False
2740 gdelta = False
2741 if v & revlog.REVLOGNGINLINEDATA:
2741 if v & revlog.REVLOGNGINLINEDATA:
2742 flags.append('inline')
2742 flags.append('inline')
2743 if v & revlog.REVLOGGENERALDELTA:
2743 if v & revlog.REVLOGGENERALDELTA:
2744 gdelta = True
2744 gdelta = True
2745 flags.append('generaldelta')
2745 flags.append('generaldelta')
2746 if not flags:
2746 if not flags:
2747 flags = ['(none)']
2747 flags = ['(none)']
2748
2748
2749 nummerges = 0
2749 nummerges = 0
2750 numfull = 0
2750 numfull = 0
2751 numprev = 0
2751 numprev = 0
2752 nump1 = 0
2752 nump1 = 0
2753 nump2 = 0
2753 nump2 = 0
2754 numother = 0
2754 numother = 0
2755 nump1prev = 0
2755 nump1prev = 0
2756 nump2prev = 0
2756 nump2prev = 0
2757 chainlengths = []
2757 chainlengths = []
2758
2758
2759 datasize = [None, 0, 0L]
2759 datasize = [None, 0, 0L]
2760 fullsize = [None, 0, 0L]
2760 fullsize = [None, 0, 0L]
2761 deltasize = [None, 0, 0L]
2761 deltasize = [None, 0, 0L]
2762
2762
2763 def addsize(size, l):
2763 def addsize(size, l):
2764 if l[0] is None or size < l[0]:
2764 if l[0] is None or size < l[0]:
2765 l[0] = size
2765 l[0] = size
2766 if size > l[1]:
2766 if size > l[1]:
2767 l[1] = size
2767 l[1] = size
2768 l[2] += size
2768 l[2] += size
2769
2769
2770 numrevs = len(r)
2770 numrevs = len(r)
2771 for rev in xrange(numrevs):
2771 for rev in xrange(numrevs):
2772 p1, p2 = r.parentrevs(rev)
2772 p1, p2 = r.parentrevs(rev)
2773 delta = r.deltaparent(rev)
2773 delta = r.deltaparent(rev)
2774 if format > 0:
2774 if format > 0:
2775 addsize(r.rawsize(rev), datasize)
2775 addsize(r.rawsize(rev), datasize)
2776 if p2 != nullrev:
2776 if p2 != nullrev:
2777 nummerges += 1
2777 nummerges += 1
2778 size = r.length(rev)
2778 size = r.length(rev)
2779 if delta == nullrev:
2779 if delta == nullrev:
2780 chainlengths.append(0)
2780 chainlengths.append(0)
2781 numfull += 1
2781 numfull += 1
2782 addsize(size, fullsize)
2782 addsize(size, fullsize)
2783 else:
2783 else:
2784 chainlengths.append(chainlengths[delta] + 1)
2784 chainlengths.append(chainlengths[delta] + 1)
2785 addsize(size, deltasize)
2785 addsize(size, deltasize)
2786 if delta == rev - 1:
2786 if delta == rev - 1:
2787 numprev += 1
2787 numprev += 1
2788 if delta == p1:
2788 if delta == p1:
2789 nump1prev += 1
2789 nump1prev += 1
2790 elif delta == p2:
2790 elif delta == p2:
2791 nump2prev += 1
2791 nump2prev += 1
2792 elif delta == p1:
2792 elif delta == p1:
2793 nump1 += 1
2793 nump1 += 1
2794 elif delta == p2:
2794 elif delta == p2:
2795 nump2 += 1
2795 nump2 += 1
2796 elif delta != nullrev:
2796 elif delta != nullrev:
2797 numother += 1
2797 numother += 1
2798
2798
2799 # Adjust size min value for empty cases
2799 # Adjust size min value for empty cases
2800 for size in (datasize, fullsize, deltasize):
2800 for size in (datasize, fullsize, deltasize):
2801 if size[0] is None:
2801 if size[0] is None:
2802 size[0] = 0
2802 size[0] = 0
2803
2803
2804 numdeltas = numrevs - numfull
2804 numdeltas = numrevs - numfull
2805 numoprev = numprev - nump1prev - nump2prev
2805 numoprev = numprev - nump1prev - nump2prev
2806 totalrawsize = datasize[2]
2806 totalrawsize = datasize[2]
2807 datasize[2] /= numrevs
2807 datasize[2] /= numrevs
2808 fulltotal = fullsize[2]
2808 fulltotal = fullsize[2]
2809 fullsize[2] /= numfull
2809 fullsize[2] /= numfull
2810 deltatotal = deltasize[2]
2810 deltatotal = deltasize[2]
2811 if numrevs - numfull > 0:
2811 if numrevs - numfull > 0:
2812 deltasize[2] /= numrevs - numfull
2812 deltasize[2] /= numrevs - numfull
2813 totalsize = fulltotal + deltatotal
2813 totalsize = fulltotal + deltatotal
2814 avgchainlen = sum(chainlengths) / numrevs
2814 avgchainlen = sum(chainlengths) / numrevs
2815 compratio = totalrawsize / totalsize
2815 compratio = totalrawsize / totalsize
2816
2816
2817 basedfmtstr = '%%%dd\n'
2817 basedfmtstr = '%%%dd\n'
2818 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2818 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2819
2819
2820 def dfmtstr(max):
2820 def dfmtstr(max):
2821 return basedfmtstr % len(str(max))
2821 return basedfmtstr % len(str(max))
2822 def pcfmtstr(max, padding=0):
2822 def pcfmtstr(max, padding=0):
2823 return basepcfmtstr % (len(str(max)), ' ' * padding)
2823 return basepcfmtstr % (len(str(max)), ' ' * padding)
2824
2824
2825 def pcfmt(value, total):
2825 def pcfmt(value, total):
2826 return (value, 100 * float(value) / total)
2826 return (value, 100 * float(value) / total)
2827
2827
2828 ui.write(('format : %d\n') % format)
2828 ui.write(('format : %d\n') % format)
2829 ui.write(('flags : %s\n') % ', '.join(flags))
2829 ui.write(('flags : %s\n') % ', '.join(flags))
2830
2830
2831 ui.write('\n')
2831 ui.write('\n')
2832 fmt = pcfmtstr(totalsize)
2832 fmt = pcfmtstr(totalsize)
2833 fmt2 = dfmtstr(totalsize)
2833 fmt2 = dfmtstr(totalsize)
2834 ui.write(('revisions : ') + fmt2 % numrevs)
2834 ui.write(('revisions : ') + fmt2 % numrevs)
2835 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2835 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2836 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2836 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2837 ui.write(('revisions : ') + fmt2 % numrevs)
2837 ui.write(('revisions : ') + fmt2 % numrevs)
2838 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2838 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2839 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2839 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2840 ui.write(('revision size : ') + fmt2 % totalsize)
2840 ui.write(('revision size : ') + fmt2 % totalsize)
2841 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2841 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2842 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2842 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2843
2843
2844 ui.write('\n')
2844 ui.write('\n')
2845 fmt = dfmtstr(max(avgchainlen, compratio))
2845 fmt = dfmtstr(max(avgchainlen, compratio))
2846 ui.write(('avg chain length : ') + fmt % avgchainlen)
2846 ui.write(('avg chain length : ') + fmt % avgchainlen)
2847 ui.write(('compression ratio : ') + fmt % compratio)
2847 ui.write(('compression ratio : ') + fmt % compratio)
2848
2848
2849 if format > 0:
2849 if format > 0:
2850 ui.write('\n')
2850 ui.write('\n')
2851 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2851 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2852 % tuple(datasize))
2852 % tuple(datasize))
2853 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2853 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2854 % tuple(fullsize))
2854 % tuple(fullsize))
2855 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2855 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2856 % tuple(deltasize))
2856 % tuple(deltasize))
2857
2857
2858 if numdeltas > 0:
2858 if numdeltas > 0:
2859 ui.write('\n')
2859 ui.write('\n')
2860 fmt = pcfmtstr(numdeltas)
2860 fmt = pcfmtstr(numdeltas)
2861 fmt2 = pcfmtstr(numdeltas, 4)
2861 fmt2 = pcfmtstr(numdeltas, 4)
2862 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2862 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2863 if numprev > 0:
2863 if numprev > 0:
2864 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2864 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2865 numprev))
2865 numprev))
2866 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2866 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2867 numprev))
2867 numprev))
2868 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2868 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2869 numprev))
2869 numprev))
2870 if gdelta:
2870 if gdelta:
2871 ui.write(('deltas against p1 : ')
2871 ui.write(('deltas against p1 : ')
2872 + fmt % pcfmt(nump1, numdeltas))
2872 + fmt % pcfmt(nump1, numdeltas))
2873 ui.write(('deltas against p2 : ')
2873 ui.write(('deltas against p2 : ')
2874 + fmt % pcfmt(nump2, numdeltas))
2874 + fmt % pcfmt(nump2, numdeltas))
2875 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2875 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2876 numdeltas))
2876 numdeltas))
2877
2877
2878 @command('debugrevspec',
2878 @command('debugrevspec',
2879 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2879 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2880 ('REVSPEC'))
2880 ('REVSPEC'))
2881 def debugrevspec(ui, repo, expr, **opts):
2881 def debugrevspec(ui, repo, expr, **opts):
2882 """parse and apply a revision specification
2882 """parse and apply a revision specification
2883
2883
2884 Use --verbose to print the parsed tree before and after aliases
2884 Use --verbose to print the parsed tree before and after aliases
2885 expansion.
2885 expansion.
2886 """
2886 """
2887 if ui.verbose:
2887 if ui.verbose:
2888 tree = revset.parse(expr)[0]
2888 tree = revset.parse(expr)[0]
2889 ui.note(revset.prettyformat(tree), "\n")
2889 ui.note(revset.prettyformat(tree), "\n")
2890 newtree = revset.findaliases(ui, tree)
2890 newtree = revset.findaliases(ui, tree)
2891 if newtree != tree:
2891 if newtree != tree:
2892 ui.note(revset.prettyformat(newtree), "\n")
2892 ui.note(revset.prettyformat(newtree), "\n")
2893 tree = newtree
2893 tree = newtree
2894 newtree = revset.foldconcat(tree)
2894 newtree = revset.foldconcat(tree)
2895 if newtree != tree:
2895 if newtree != tree:
2896 ui.note(revset.prettyformat(newtree), "\n")
2896 ui.note(revset.prettyformat(newtree), "\n")
2897 if opts["optimize"]:
2897 if opts["optimize"]:
2898 weight, optimizedtree = revset.optimize(newtree, True)
2898 weight, optimizedtree = revset.optimize(newtree, True)
2899 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2899 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2900 func = revset.match(ui, expr)
2900 func = revset.match(ui, expr)
2901 for c in func(repo):
2901 for c in func(repo):
2902 ui.write("%s\n" % c)
2902 ui.write("%s\n" % c)
2903
2903
2904 @command('debugsetparents', [], _('REV1 [REV2]'))
2904 @command('debugsetparents', [], _('REV1 [REV2]'))
2905 def debugsetparents(ui, repo, rev1, rev2=None):
2905 def debugsetparents(ui, repo, rev1, rev2=None):
2906 """manually set the parents of the current working directory
2906 """manually set the parents of the current working directory
2907
2907
2908 This is useful for writing repository conversion tools, but should
2908 This is useful for writing repository conversion tools, but should
2909 be used with care. For example, neither the working directory nor the
2909 be used with care. For example, neither the working directory nor the
2910 dirstate is updated, so file status may be incorrect after running this
2910 dirstate is updated, so file status may be incorrect after running this
2911 command.
2911 command.
2912
2912
2913 Returns 0 on success.
2913 Returns 0 on success.
2914 """
2914 """
2915
2915
2916 r1 = scmutil.revsingle(repo, rev1).node()
2916 r1 = scmutil.revsingle(repo, rev1).node()
2917 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2917 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2918
2918
2919 wlock = repo.wlock()
2919 wlock = repo.wlock()
2920 try:
2920 try:
2921 repo.dirstate.beginparentchange()
2921 repo.dirstate.beginparentchange()
2922 repo.setparents(r1, r2)
2922 repo.setparents(r1, r2)
2923 repo.dirstate.endparentchange()
2923 repo.dirstate.endparentchange()
2924 finally:
2924 finally:
2925 wlock.release()
2925 wlock.release()
2926
2926
2927 @command('debugdirstate|debugstate',
2927 @command('debugdirstate|debugstate',
2928 [('', 'nodates', None, _('do not display the saved mtime')),
2928 [('', 'nodates', None, _('do not display the saved mtime')),
2929 ('', 'datesort', None, _('sort by saved mtime'))],
2929 ('', 'datesort', None, _('sort by saved mtime'))],
2930 _('[OPTION]...'))
2930 _('[OPTION]...'))
2931 def debugstate(ui, repo, nodates=None, datesort=None):
2931 def debugstate(ui, repo, nodates=None, datesort=None):
2932 """show the contents of the current dirstate"""
2932 """show the contents of the current dirstate"""
2933 timestr = ""
2933 timestr = ""
2934 if datesort:
2934 if datesort:
2935 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2935 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2936 else:
2936 else:
2937 keyfunc = None # sort by filename
2937 keyfunc = None # sort by filename
2938 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2938 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2939 if ent[3] == -1:
2939 if ent[3] == -1:
2940 timestr = 'unset '
2940 timestr = 'unset '
2941 elif nodates:
2941 elif nodates:
2942 timestr = 'set '
2942 timestr = 'set '
2943 else:
2943 else:
2944 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2944 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2945 time.localtime(ent[3]))
2945 time.localtime(ent[3]))
2946 if ent[1] & 020000:
2946 if ent[1] & 020000:
2947 mode = 'lnk'
2947 mode = 'lnk'
2948 else:
2948 else:
2949 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2949 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2950 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2950 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2951 for f in repo.dirstate.copies():
2951 for f in repo.dirstate.copies():
2952 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2952 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2953
2953
2954 @command('debugsub',
2954 @command('debugsub',
2955 [('r', 'rev', '',
2955 [('r', 'rev', '',
2956 _('revision to check'), _('REV'))],
2956 _('revision to check'), _('REV'))],
2957 _('[-r REV] [REV]'))
2957 _('[-r REV] [REV]'))
2958 def debugsub(ui, repo, rev=None):
2958 def debugsub(ui, repo, rev=None):
2959 ctx = scmutil.revsingle(repo, rev, None)
2959 ctx = scmutil.revsingle(repo, rev, None)
2960 for k, v in sorted(ctx.substate.items()):
2960 for k, v in sorted(ctx.substate.items()):
2961 ui.write(('path %s\n') % k)
2961 ui.write(('path %s\n') % k)
2962 ui.write((' source %s\n') % v[0])
2962 ui.write((' source %s\n') % v[0])
2963 ui.write((' revision %s\n') % v[1])
2963 ui.write((' revision %s\n') % v[1])
2964
2964
2965 @command('debugsuccessorssets',
2965 @command('debugsuccessorssets',
2966 [],
2966 [],
2967 _('[REV]'))
2967 _('[REV]'))
2968 def debugsuccessorssets(ui, repo, *revs):
2968 def debugsuccessorssets(ui, repo, *revs):
2969 """show set of successors for revision
2969 """show set of successors for revision
2970
2970
2971 A successors set of changeset A is a consistent group of revisions that
2971 A successors set of changeset A is a consistent group of revisions that
2972 succeed A. It contains non-obsolete changesets only.
2972 succeed A. It contains non-obsolete changesets only.
2973
2973
2974 In most cases a changeset A has a single successors set containing a single
2974 In most cases a changeset A has a single successors set containing a single
2975 successor (changeset A replaced by A').
2975 successor (changeset A replaced by A').
2976
2976
2977 A changeset that is made obsolete with no successors are called "pruned".
2977 A changeset that is made obsolete with no successors are called "pruned".
2978 Such changesets have no successors sets at all.
2978 Such changesets have no successors sets at all.
2979
2979
2980 A changeset that has been "split" will have a successors set containing
2980 A changeset that has been "split" will have a successors set containing
2981 more than one successor.
2981 more than one successor.
2982
2982
2983 A changeset that has been rewritten in multiple different ways is called
2983 A changeset that has been rewritten in multiple different ways is called
2984 "divergent". Such changesets have multiple successor sets (each of which
2984 "divergent". Such changesets have multiple successor sets (each of which
2985 may also be split, i.e. have multiple successors).
2985 may also be split, i.e. have multiple successors).
2986
2986
2987 Results are displayed as follows::
2987 Results are displayed as follows::
2988
2988
2989 <rev1>
2989 <rev1>
2990 <successors-1A>
2990 <successors-1A>
2991 <rev2>
2991 <rev2>
2992 <successors-2A>
2992 <successors-2A>
2993 <successors-2B1> <successors-2B2> <successors-2B3>
2993 <successors-2B1> <successors-2B2> <successors-2B3>
2994
2994
2995 Here rev2 has two possible (i.e. divergent) successors sets. The first
2995 Here rev2 has two possible (i.e. divergent) successors sets. The first
2996 holds one element, whereas the second holds three (i.e. the changeset has
2996 holds one element, whereas the second holds three (i.e. the changeset has
2997 been split).
2997 been split).
2998 """
2998 """
2999 # passed to successorssets caching computation from one call to another
2999 # passed to successorssets caching computation from one call to another
3000 cache = {}
3000 cache = {}
3001 ctx2str = str
3001 ctx2str = str
3002 node2str = short
3002 node2str = short
3003 if ui.debug():
3003 if ui.debug():
3004 def ctx2str(ctx):
3004 def ctx2str(ctx):
3005 return ctx.hex()
3005 return ctx.hex()
3006 node2str = hex
3006 node2str = hex
3007 for rev in scmutil.revrange(repo, revs):
3007 for rev in scmutil.revrange(repo, revs):
3008 ctx = repo[rev]
3008 ctx = repo[rev]
3009 ui.write('%s\n'% ctx2str(ctx))
3009 ui.write('%s\n'% ctx2str(ctx))
3010 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3010 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3011 if succsset:
3011 if succsset:
3012 ui.write(' ')
3012 ui.write(' ')
3013 ui.write(node2str(succsset[0]))
3013 ui.write(node2str(succsset[0]))
3014 for node in succsset[1:]:
3014 for node in succsset[1:]:
3015 ui.write(' ')
3015 ui.write(' ')
3016 ui.write(node2str(node))
3016 ui.write(node2str(node))
3017 ui.write('\n')
3017 ui.write('\n')
3018
3018
3019 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3019 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3020 def debugwalk(ui, repo, *pats, **opts):
3020 def debugwalk(ui, repo, *pats, **opts):
3021 """show how files match on given patterns"""
3021 """show how files match on given patterns"""
3022 m = scmutil.match(repo[None], pats, opts)
3022 m = scmutil.match(repo[None], pats, opts)
3023 items = list(repo.walk(m))
3023 items = list(repo.walk(m))
3024 if not items:
3024 if not items:
3025 return
3025 return
3026 f = lambda fn: fn
3026 f = lambda fn: fn
3027 if ui.configbool('ui', 'slash') and os.sep != '/':
3027 if ui.configbool('ui', 'slash') and os.sep != '/':
3028 f = lambda fn: util.normpath(fn)
3028 f = lambda fn: util.normpath(fn)
3029 fmt = 'f %%-%ds %%-%ds %%s' % (
3029 fmt = 'f %%-%ds %%-%ds %%s' % (
3030 max([len(abs) for abs in items]),
3030 max([len(abs) for abs in items]),
3031 max([len(m.rel(abs)) for abs in items]))
3031 max([len(m.rel(abs)) for abs in items]))
3032 for abs in items:
3032 for abs in items:
3033 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3033 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3034 ui.write("%s\n" % line.rstrip())
3034 ui.write("%s\n" % line.rstrip())
3035
3035
3036 @command('debugwireargs',
3036 @command('debugwireargs',
3037 [('', 'three', '', 'three'),
3037 [('', 'three', '', 'three'),
3038 ('', 'four', '', 'four'),
3038 ('', 'four', '', 'four'),
3039 ('', 'five', '', 'five'),
3039 ('', 'five', '', 'five'),
3040 ] + remoteopts,
3040 ] + remoteopts,
3041 _('REPO [OPTIONS]... [ONE [TWO]]'),
3041 _('REPO [OPTIONS]... [ONE [TWO]]'),
3042 norepo=True)
3042 norepo=True)
3043 def debugwireargs(ui, repopath, *vals, **opts):
3043 def debugwireargs(ui, repopath, *vals, **opts):
3044 repo = hg.peer(ui, opts, repopath)
3044 repo = hg.peer(ui, opts, repopath)
3045 for opt in remoteopts:
3045 for opt in remoteopts:
3046 del opts[opt[1]]
3046 del opts[opt[1]]
3047 args = {}
3047 args = {}
3048 for k, v in opts.iteritems():
3048 for k, v in opts.iteritems():
3049 if v:
3049 if v:
3050 args[k] = v
3050 args[k] = v
3051 # run twice to check that we don't mess up the stream for the next command
3051 # run twice to check that we don't mess up the stream for the next command
3052 res1 = repo.debugwireargs(*vals, **args)
3052 res1 = repo.debugwireargs(*vals, **args)
3053 res2 = repo.debugwireargs(*vals, **args)
3053 res2 = repo.debugwireargs(*vals, **args)
3054 ui.write("%s\n" % res1)
3054 ui.write("%s\n" % res1)
3055 if res1 != res2:
3055 if res1 != res2:
3056 ui.warn("%s\n" % res2)
3056 ui.warn("%s\n" % res2)
3057
3057
3058 @command('^diff',
3058 @command('^diff',
3059 [('r', 'rev', [], _('revision'), _('REV')),
3059 [('r', 'rev', [], _('revision'), _('REV')),
3060 ('c', 'change', '', _('change made by revision'), _('REV'))
3060 ('c', 'change', '', _('change made by revision'), _('REV'))
3061 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3061 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3062 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3062 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3063 inferrepo=True)
3063 inferrepo=True)
3064 def diff(ui, repo, *pats, **opts):
3064 def diff(ui, repo, *pats, **opts):
3065 """diff repository (or selected files)
3065 """diff repository (or selected files)
3066
3066
3067 Show differences between revisions for the specified files.
3067 Show differences between revisions for the specified files.
3068
3068
3069 Differences between files are shown using the unified diff format.
3069 Differences between files are shown using the unified diff format.
3070
3070
3071 .. note::
3071 .. note::
3072
3072
3073 diff may generate unexpected results for merges, as it will
3073 diff may generate unexpected results for merges, as it will
3074 default to comparing against the working directory's first
3074 default to comparing against the working directory's first
3075 parent changeset if no revisions are specified.
3075 parent changeset if no revisions are specified.
3076
3076
3077 When two revision arguments are given, then changes are shown
3077 When two revision arguments are given, then changes are shown
3078 between those revisions. If only one revision is specified then
3078 between those revisions. If only one revision is specified then
3079 that revision is compared to the working directory, and, when no
3079 that revision is compared to the working directory, and, when no
3080 revisions are specified, the working directory files are compared
3080 revisions are specified, the working directory files are compared
3081 to its parent.
3081 to its parent.
3082
3082
3083 Alternatively you can specify -c/--change with a revision to see
3083 Alternatively you can specify -c/--change with a revision to see
3084 the changes in that changeset relative to its first parent.
3084 the changes in that changeset relative to its first parent.
3085
3085
3086 Without the -a/--text option, diff will avoid generating diffs of
3086 Without the -a/--text option, diff will avoid generating diffs of
3087 files it detects as binary. With -a, diff will generate a diff
3087 files it detects as binary. With -a, diff will generate a diff
3088 anyway, probably with undesirable results.
3088 anyway, probably with undesirable results.
3089
3089
3090 Use the -g/--git option to generate diffs in the git extended diff
3090 Use the -g/--git option to generate diffs in the git extended diff
3091 format. For more information, read :hg:`help diffs`.
3091 format. For more information, read :hg:`help diffs`.
3092
3092
3093 .. container:: verbose
3093 .. container:: verbose
3094
3094
3095 Examples:
3095 Examples:
3096
3096
3097 - compare a file in the current working directory to its parent::
3097 - compare a file in the current working directory to its parent::
3098
3098
3099 hg diff foo.c
3099 hg diff foo.c
3100
3100
3101 - compare two historical versions of a directory, with rename info::
3101 - compare two historical versions of a directory, with rename info::
3102
3102
3103 hg diff --git -r 1.0:1.2 lib/
3103 hg diff --git -r 1.0:1.2 lib/
3104
3104
3105 - get change stats relative to the last change on some date::
3105 - get change stats relative to the last change on some date::
3106
3106
3107 hg diff --stat -r "date('may 2')"
3107 hg diff --stat -r "date('may 2')"
3108
3108
3109 - diff all newly-added files that contain a keyword::
3109 - diff all newly-added files that contain a keyword::
3110
3110
3111 hg diff "set:added() and grep(GNU)"
3111 hg diff "set:added() and grep(GNU)"
3112
3112
3113 - compare a revision and its parents::
3113 - compare a revision and its parents::
3114
3114
3115 hg diff -c 9353 # compare against first parent
3115 hg diff -c 9353 # compare against first parent
3116 hg diff -r 9353^:9353 # same using revset syntax
3116 hg diff -r 9353^:9353 # same using revset syntax
3117 hg diff -r 9353^2:9353 # compare against the second parent
3117 hg diff -r 9353^2:9353 # compare against the second parent
3118
3118
3119 Returns 0 on success.
3119 Returns 0 on success.
3120 """
3120 """
3121
3121
3122 revs = opts.get('rev')
3122 revs = opts.get('rev')
3123 change = opts.get('change')
3123 change = opts.get('change')
3124 stat = opts.get('stat')
3124 stat = opts.get('stat')
3125 reverse = opts.get('reverse')
3125 reverse = opts.get('reverse')
3126
3126
3127 if revs and change:
3127 if revs and change:
3128 msg = _('cannot specify --rev and --change at the same time')
3128 msg = _('cannot specify --rev and --change at the same time')
3129 raise util.Abort(msg)
3129 raise util.Abort(msg)
3130 elif change:
3130 elif change:
3131 node2 = scmutil.revsingle(repo, change, None).node()
3131 node2 = scmutil.revsingle(repo, change, None).node()
3132 node1 = repo[node2].p1().node()
3132 node1 = repo[node2].p1().node()
3133 else:
3133 else:
3134 node1, node2 = scmutil.revpair(repo, revs)
3134 node1, node2 = scmutil.revpair(repo, revs)
3135
3135
3136 if reverse:
3136 if reverse:
3137 node1, node2 = node2, node1
3137 node1, node2 = node2, node1
3138
3138
3139 diffopts = patch.diffallopts(ui, opts)
3139 diffopts = patch.diffallopts(ui, opts)
3140 m = scmutil.match(repo[node2], pats, opts)
3140 m = scmutil.match(repo[node2], pats, opts)
3141 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3141 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3142 listsubrepos=opts.get('subrepos'))
3142 listsubrepos=opts.get('subrepos'))
3143
3143
3144 @command('^export',
3144 @command('^export',
3145 [('o', 'output', '',
3145 [('o', 'output', '',
3146 _('print output to file with formatted name'), _('FORMAT')),
3146 _('print output to file with formatted name'), _('FORMAT')),
3147 ('', 'switch-parent', None, _('diff against the second parent')),
3147 ('', 'switch-parent', None, _('diff against the second parent')),
3148 ('r', 'rev', [], _('revisions to export'), _('REV')),
3148 ('r', 'rev', [], _('revisions to export'), _('REV')),
3149 ] + diffopts,
3149 ] + diffopts,
3150 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3150 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3151 def export(ui, repo, *changesets, **opts):
3151 def export(ui, repo, *changesets, **opts):
3152 """dump the header and diffs for one or more changesets
3152 """dump the header and diffs for one or more changesets
3153
3153
3154 Print the changeset header and diffs for one or more revisions.
3154 Print the changeset header and diffs for one or more revisions.
3155 If no revision is given, the parent of the working directory is used.
3155 If no revision is given, the parent of the working directory is used.
3156
3156
3157 The information shown in the changeset header is: author, date,
3157 The information shown in the changeset header is: author, date,
3158 branch name (if non-default), changeset hash, parent(s) and commit
3158 branch name (if non-default), changeset hash, parent(s) and commit
3159 comment.
3159 comment.
3160
3160
3161 .. note::
3161 .. note::
3162
3162
3163 export may generate unexpected diff output for merge
3163 export may generate unexpected diff output for merge
3164 changesets, as it will compare the merge changeset against its
3164 changesets, as it will compare the merge changeset against its
3165 first parent only.
3165 first parent only.
3166
3166
3167 Output may be to a file, in which case the name of the file is
3167 Output may be to a file, in which case the name of the file is
3168 given using a format string. The formatting rules are as follows:
3168 given using a format string. The formatting rules are as follows:
3169
3169
3170 :``%%``: literal "%" character
3170 :``%%``: literal "%" character
3171 :``%H``: changeset hash (40 hexadecimal digits)
3171 :``%H``: changeset hash (40 hexadecimal digits)
3172 :``%N``: number of patches being generated
3172 :``%N``: number of patches being generated
3173 :``%R``: changeset revision number
3173 :``%R``: changeset revision number
3174 :``%b``: basename of the exporting repository
3174 :``%b``: basename of the exporting repository
3175 :``%h``: short-form changeset hash (12 hexadecimal digits)
3175 :``%h``: short-form changeset hash (12 hexadecimal digits)
3176 :``%m``: first line of the commit message (only alphanumeric characters)
3176 :``%m``: first line of the commit message (only alphanumeric characters)
3177 :``%n``: zero-padded sequence number, starting at 1
3177 :``%n``: zero-padded sequence number, starting at 1
3178 :``%r``: zero-padded changeset revision number
3178 :``%r``: zero-padded changeset revision number
3179
3179
3180 Without the -a/--text option, export will avoid generating diffs
3180 Without the -a/--text option, export will avoid generating diffs
3181 of files it detects as binary. With -a, export will generate a
3181 of files it detects as binary. With -a, export will generate a
3182 diff anyway, probably with undesirable results.
3182 diff anyway, probably with undesirable results.
3183
3183
3184 Use the -g/--git option to generate diffs in the git extended diff
3184 Use the -g/--git option to generate diffs in the git extended diff
3185 format. See :hg:`help diffs` for more information.
3185 format. See :hg:`help diffs` for more information.
3186
3186
3187 With the --switch-parent option, the diff will be against the
3187 With the --switch-parent option, the diff will be against the
3188 second parent. It can be useful to review a merge.
3188 second parent. It can be useful to review a merge.
3189
3189
3190 .. container:: verbose
3190 .. container:: verbose
3191
3191
3192 Examples:
3192 Examples:
3193
3193
3194 - use export and import to transplant a bugfix to the current
3194 - use export and import to transplant a bugfix to the current
3195 branch::
3195 branch::
3196
3196
3197 hg export -r 9353 | hg import -
3197 hg export -r 9353 | hg import -
3198
3198
3199 - export all the changesets between two revisions to a file with
3199 - export all the changesets between two revisions to a file with
3200 rename information::
3200 rename information::
3201
3201
3202 hg export --git -r 123:150 > changes.txt
3202 hg export --git -r 123:150 > changes.txt
3203
3203
3204 - split outgoing changes into a series of patches with
3204 - split outgoing changes into a series of patches with
3205 descriptive names::
3205 descriptive names::
3206
3206
3207 hg export -r "outgoing()" -o "%n-%m.patch"
3207 hg export -r "outgoing()" -o "%n-%m.patch"
3208
3208
3209 Returns 0 on success.
3209 Returns 0 on success.
3210 """
3210 """
3211 changesets += tuple(opts.get('rev', []))
3211 changesets += tuple(opts.get('rev', []))
3212 if not changesets:
3212 if not changesets:
3213 changesets = ['.']
3213 changesets = ['.']
3214 revs = scmutil.revrange(repo, changesets)
3214 revs = scmutil.revrange(repo, changesets)
3215 if not revs:
3215 if not revs:
3216 raise util.Abort(_("export requires at least one changeset"))
3216 raise util.Abort(_("export requires at least one changeset"))
3217 if len(revs) > 1:
3217 if len(revs) > 1:
3218 ui.note(_('exporting patches:\n'))
3218 ui.note(_('exporting patches:\n'))
3219 else:
3219 else:
3220 ui.note(_('exporting patch:\n'))
3220 ui.note(_('exporting patch:\n'))
3221 cmdutil.export(repo, revs, template=opts.get('output'),
3221 cmdutil.export(repo, revs, template=opts.get('output'),
3222 switch_parent=opts.get('switch_parent'),
3222 switch_parent=opts.get('switch_parent'),
3223 opts=patch.diffallopts(ui, opts))
3223 opts=patch.diffallopts(ui, opts))
3224
3224
3225 @command('files',
3225 @command('files',
3226 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3226 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3227 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3227 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3228 ] + walkopts + formatteropts,
3228 ] + walkopts + formatteropts,
3229 _('[OPTION]... [PATTERN]...'))
3229 _('[OPTION]... [PATTERN]...'))
3230 def files(ui, repo, *pats, **opts):
3230 def files(ui, repo, *pats, **opts):
3231 """list tracked files
3231 """list tracked files
3232
3232
3233 Print files under Mercurial control in the working directory or
3233 Print files under Mercurial control in the working directory or
3234 specified revision whose names match the given patterns (excluding
3234 specified revision whose names match the given patterns (excluding
3235 removed files).
3235 removed files).
3236
3236
3237 If no patterns are given to match, this command prints the names
3237 If no patterns are given to match, this command prints the names
3238 of all files under Mercurial control in the working directory.
3238 of all files under Mercurial control in the working directory.
3239
3239
3240 .. container:: verbose
3240 .. container:: verbose
3241
3241
3242 Examples:
3242 Examples:
3243
3243
3244 - list all files under the current directory::
3244 - list all files under the current directory::
3245
3245
3246 hg files .
3246 hg files .
3247
3247
3248 - shows sizes and flags for current revision::
3248 - shows sizes and flags for current revision::
3249
3249
3250 hg files -vr .
3250 hg files -vr .
3251
3251
3252 - list all files named README::
3252 - list all files named README::
3253
3253
3254 hg files -I "**/README"
3254 hg files -I "**/README"
3255
3255
3256 - list all binary files::
3256 - list all binary files::
3257
3257
3258 hg files "set:binary()"
3258 hg files "set:binary()"
3259
3259
3260 - find files containing a regular expression::
3260 - find files containing a regular expression::
3261
3261
3262 hg files "set:grep('bob')"
3262 hg files "set:grep('bob')"
3263
3263
3264 - search tracked file contents with xargs and grep::
3264 - search tracked file contents with xargs and grep::
3265
3265
3266 hg files -0 | xargs -0 grep foo
3266 hg files -0 | xargs -0 grep foo
3267
3267
3268 See :hg:`help patterns` and :hg:`help filesets` for more information
3268 See :hg:`help patterns` and :hg:`help filesets` for more information
3269 on specifying file patterns.
3269 on specifying file patterns.
3270
3270
3271 Returns 0 if a match is found, 1 otherwise.
3271 Returns 0 if a match is found, 1 otherwise.
3272
3272
3273 """
3273 """
3274 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3274 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3275
3275
3276 end = '\n'
3276 end = '\n'
3277 if opts.get('print0'):
3277 if opts.get('print0'):
3278 end = '\0'
3278 end = '\0'
3279 fm = ui.formatter('files', opts)
3279 fm = ui.formatter('files', opts)
3280 fmt = '%s' + end
3280 fmt = '%s' + end
3281
3281
3282 m = scmutil.match(ctx, pats, opts)
3282 m = scmutil.match(ctx, pats, opts)
3283 ret = cmdutil.files(ui, ctx, m, fm, fmt)
3283 ret = cmdutil.files(ui, ctx, m, fm, fmt)
3284
3284
3285 fm.end()
3285 fm.end()
3286
3286
3287 return ret
3287 return ret
3288
3288
3289 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3289 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3290 def forget(ui, repo, *pats, **opts):
3290 def forget(ui, repo, *pats, **opts):
3291 """forget the specified files on the next commit
3291 """forget the specified files on the next commit
3292
3292
3293 Mark the specified files so they will no longer be tracked
3293 Mark the specified files so they will no longer be tracked
3294 after the next commit.
3294 after the next commit.
3295
3295
3296 This only removes files from the current branch, not from the
3296 This only removes files from the current branch, not from the
3297 entire project history, and it does not delete them from the
3297 entire project history, and it does not delete them from the
3298 working directory.
3298 working directory.
3299
3299
3300 To undo a forget before the next commit, see :hg:`add`.
3300 To undo a forget before the next commit, see :hg:`add`.
3301
3301
3302 .. container:: verbose
3302 .. container:: verbose
3303
3303
3304 Examples:
3304 Examples:
3305
3305
3306 - forget newly-added binary files::
3306 - forget newly-added binary files::
3307
3307
3308 hg forget "set:added() and binary()"
3308 hg forget "set:added() and binary()"
3309
3309
3310 - forget files that would be excluded by .hgignore::
3310 - forget files that would be excluded by .hgignore::
3311
3311
3312 hg forget "set:hgignore()"
3312 hg forget "set:hgignore()"
3313
3313
3314 Returns 0 on success.
3314 Returns 0 on success.
3315 """
3315 """
3316
3316
3317 if not pats:
3317 if not pats:
3318 raise util.Abort(_('no files specified'))
3318 raise util.Abort(_('no files specified'))
3319
3319
3320 m = scmutil.match(repo[None], pats, opts)
3320 m = scmutil.match(repo[None], pats, opts)
3321 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3321 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3322 return rejected and 1 or 0
3322 return rejected and 1 or 0
3323
3323
3324 @command(
3324 @command(
3325 'graft',
3325 'graft',
3326 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3326 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3327 ('c', 'continue', False, _('resume interrupted graft')),
3327 ('c', 'continue', False, _('resume interrupted graft')),
3328 ('e', 'edit', False, _('invoke editor on commit messages')),
3328 ('e', 'edit', False, _('invoke editor on commit messages')),
3329 ('', 'log', None, _('append graft info to log message')),
3329 ('', 'log', None, _('append graft info to log message')),
3330 ('f', 'force', False, _('force graft')),
3330 ('f', 'force', False, _('force graft')),
3331 ('D', 'currentdate', False,
3331 ('D', 'currentdate', False,
3332 _('record the current date as commit date')),
3332 _('record the current date as commit date')),
3333 ('U', 'currentuser', False,
3333 ('U', 'currentuser', False,
3334 _('record the current user as committer'), _('DATE'))]
3334 _('record the current user as committer'), _('DATE'))]
3335 + commitopts2 + mergetoolopts + dryrunopts,
3335 + commitopts2 + mergetoolopts + dryrunopts,
3336 _('[OPTION]... [-r] REV...'))
3336 _('[OPTION]... [-r] REV...'))
3337 def graft(ui, repo, *revs, **opts):
3337 def graft(ui, repo, *revs, **opts):
3338 '''copy changes from other branches onto the current branch
3338 '''copy changes from other branches onto the current branch
3339
3339
3340 This command uses Mercurial's merge logic to copy individual
3340 This command uses Mercurial's merge logic to copy individual
3341 changes from other branches without merging branches in the
3341 changes from other branches without merging branches in the
3342 history graph. This is sometimes known as 'backporting' or
3342 history graph. This is sometimes known as 'backporting' or
3343 'cherry-picking'. By default, graft will copy user, date, and
3343 'cherry-picking'. By default, graft will copy user, date, and
3344 description from the source changesets.
3344 description from the source changesets.
3345
3345
3346 Changesets that are ancestors of the current revision, that have
3346 Changesets that are ancestors of the current revision, that have
3347 already been grafted, or that are merges will be skipped.
3347 already been grafted, or that are merges will be skipped.
3348
3348
3349 If --log is specified, log messages will have a comment appended
3349 If --log is specified, log messages will have a comment appended
3350 of the form::
3350 of the form::
3351
3351
3352 (grafted from CHANGESETHASH)
3352 (grafted from CHANGESETHASH)
3353
3353
3354 If --force is specified, revisions will be grafted even if they
3354 If --force is specified, revisions will be grafted even if they
3355 are already ancestors of or have been grafted to the destination.
3355 are already ancestors of or have been grafted to the destination.
3356 This is useful when the revisions have since been backed out.
3356 This is useful when the revisions have since been backed out.
3357
3357
3358 If a graft merge results in conflicts, the graft process is
3358 If a graft merge results in conflicts, the graft process is
3359 interrupted so that the current merge can be manually resolved.
3359 interrupted so that the current merge can be manually resolved.
3360 Once all conflicts are addressed, the graft process can be
3360 Once all conflicts are addressed, the graft process can be
3361 continued with the -c/--continue option.
3361 continued with the -c/--continue option.
3362
3362
3363 .. note::
3363 .. note::
3364
3364
3365 The -c/--continue option does not reapply earlier options, except
3365 The -c/--continue option does not reapply earlier options, except
3366 for --force.
3366 for --force.
3367
3367
3368 .. container:: verbose
3368 .. container:: verbose
3369
3369
3370 Examples:
3370 Examples:
3371
3371
3372 - copy a single change to the stable branch and edit its description::
3372 - copy a single change to the stable branch and edit its description::
3373
3373
3374 hg update stable
3374 hg update stable
3375 hg graft --edit 9393
3375 hg graft --edit 9393
3376
3376
3377 - graft a range of changesets with one exception, updating dates::
3377 - graft a range of changesets with one exception, updating dates::
3378
3378
3379 hg graft -D "2085::2093 and not 2091"
3379 hg graft -D "2085::2093 and not 2091"
3380
3380
3381 - continue a graft after resolving conflicts::
3381 - continue a graft after resolving conflicts::
3382
3382
3383 hg graft -c
3383 hg graft -c
3384
3384
3385 - show the source of a grafted changeset::
3385 - show the source of a grafted changeset::
3386
3386
3387 hg log --debug -r .
3387 hg log --debug -r .
3388
3388
3389 See :hg:`help revisions` and :hg:`help revsets` for more about
3389 See :hg:`help revisions` and :hg:`help revsets` for more about
3390 specifying revisions.
3390 specifying revisions.
3391
3391
3392 Returns 0 on successful completion.
3392 Returns 0 on successful completion.
3393 '''
3393 '''
3394
3394
3395 revs = list(revs)
3395 revs = list(revs)
3396 revs.extend(opts['rev'])
3396 revs.extend(opts['rev'])
3397
3397
3398 if not opts.get('user') and opts.get('currentuser'):
3398 if not opts.get('user') and opts.get('currentuser'):
3399 opts['user'] = ui.username()
3399 opts['user'] = ui.username()
3400 if not opts.get('date') and opts.get('currentdate'):
3400 if not opts.get('date') and opts.get('currentdate'):
3401 opts['date'] = "%d %d" % util.makedate()
3401 opts['date'] = "%d %d" % util.makedate()
3402
3402
3403 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3403 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3404
3404
3405 cont = False
3405 cont = False
3406 if opts['continue']:
3406 if opts['continue']:
3407 cont = True
3407 cont = True
3408 if revs:
3408 if revs:
3409 raise util.Abort(_("can't specify --continue and revisions"))
3409 raise util.Abort(_("can't specify --continue and revisions"))
3410 # read in unfinished revisions
3410 # read in unfinished revisions
3411 try:
3411 try:
3412 nodes = repo.vfs.read('graftstate').splitlines()
3412 nodes = repo.vfs.read('graftstate').splitlines()
3413 revs = [repo[node].rev() for node in nodes]
3413 revs = [repo[node].rev() for node in nodes]
3414 except IOError, inst:
3414 except IOError, inst:
3415 if inst.errno != errno.ENOENT:
3415 if inst.errno != errno.ENOENT:
3416 raise
3416 raise
3417 raise util.Abort(_("no graft state found, can't continue"))
3417 raise util.Abort(_("no graft state found, can't continue"))
3418 else:
3418 else:
3419 cmdutil.checkunfinished(repo)
3419 cmdutil.checkunfinished(repo)
3420 cmdutil.bailifchanged(repo)
3420 cmdutil.bailifchanged(repo)
3421 if not revs:
3421 if not revs:
3422 raise util.Abort(_('no revisions specified'))
3422 raise util.Abort(_('no revisions specified'))
3423 revs = scmutil.revrange(repo, revs)
3423 revs = scmutil.revrange(repo, revs)
3424
3424
3425 skipped = set()
3425 skipped = set()
3426 # check for merges
3426 # check for merges
3427 for rev in repo.revs('%ld and merge()', revs):
3427 for rev in repo.revs('%ld and merge()', revs):
3428 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3428 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3429 skipped.add(rev)
3429 skipped.add(rev)
3430 revs = [r for r in revs if r not in skipped]
3430 revs = [r for r in revs if r not in skipped]
3431 if not revs:
3431 if not revs:
3432 return -1
3432 return -1
3433
3433
3434 # Don't check in the --continue case, in effect retaining --force across
3434 # Don't check in the --continue case, in effect retaining --force across
3435 # --continues. That's because without --force, any revisions we decided to
3435 # --continues. That's because without --force, any revisions we decided to
3436 # skip would have been filtered out here, so they wouldn't have made their
3436 # skip would have been filtered out here, so they wouldn't have made their
3437 # way to the graftstate. With --force, any revisions we would have otherwise
3437 # way to the graftstate. With --force, any revisions we would have otherwise
3438 # skipped would not have been filtered out, and if they hadn't been applied
3438 # skipped would not have been filtered out, and if they hadn't been applied
3439 # already, they'd have been in the graftstate.
3439 # already, they'd have been in the graftstate.
3440 if not (cont or opts.get('force')):
3440 if not (cont or opts.get('force')):
3441 # check for ancestors of dest branch
3441 # check for ancestors of dest branch
3442 crev = repo['.'].rev()
3442 crev = repo['.'].rev()
3443 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3443 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3444 # Cannot use x.remove(y) on smart set, this has to be a list.
3444 # Cannot use x.remove(y) on smart set, this has to be a list.
3445 # XXX make this lazy in the future
3445 # XXX make this lazy in the future
3446 revs = list(revs)
3446 revs = list(revs)
3447 # don't mutate while iterating, create a copy
3447 # don't mutate while iterating, create a copy
3448 for rev in list(revs):
3448 for rev in list(revs):
3449 if rev in ancestors:
3449 if rev in ancestors:
3450 ui.warn(_('skipping ancestor revision %d:%s\n') %
3450 ui.warn(_('skipping ancestor revision %d:%s\n') %
3451 (rev, repo[rev]))
3451 (rev, repo[rev]))
3452 # XXX remove on list is slow
3452 # XXX remove on list is slow
3453 revs.remove(rev)
3453 revs.remove(rev)
3454 if not revs:
3454 if not revs:
3455 return -1
3455 return -1
3456
3456
3457 # analyze revs for earlier grafts
3457 # analyze revs for earlier grafts
3458 ids = {}
3458 ids = {}
3459 for ctx in repo.set("%ld", revs):
3459 for ctx in repo.set("%ld", revs):
3460 ids[ctx.hex()] = ctx.rev()
3460 ids[ctx.hex()] = ctx.rev()
3461 n = ctx.extra().get('source')
3461 n = ctx.extra().get('source')
3462 if n:
3462 if n:
3463 ids[n] = ctx.rev()
3463 ids[n] = ctx.rev()
3464
3464
3465 # check ancestors for earlier grafts
3465 # check ancestors for earlier grafts
3466 ui.debug('scanning for duplicate grafts\n')
3466 ui.debug('scanning for duplicate grafts\n')
3467
3467
3468 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3468 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3469 ctx = repo[rev]
3469 ctx = repo[rev]
3470 n = ctx.extra().get('source')
3470 n = ctx.extra().get('source')
3471 if n in ids:
3471 if n in ids:
3472 try:
3472 try:
3473 r = repo[n].rev()
3473 r = repo[n].rev()
3474 except error.RepoLookupError:
3474 except error.RepoLookupError:
3475 r = None
3475 r = None
3476 if r in revs:
3476 if r in revs:
3477 ui.warn(_('skipping revision %d:%s '
3477 ui.warn(_('skipping revision %d:%s '
3478 '(already grafted to %d:%s)\n')
3478 '(already grafted to %d:%s)\n')
3479 % (r, repo[r], rev, ctx))
3479 % (r, repo[r], rev, ctx))
3480 revs.remove(r)
3480 revs.remove(r)
3481 elif ids[n] in revs:
3481 elif ids[n] in revs:
3482 if r is None:
3482 if r is None:
3483 ui.warn(_('skipping already grafted revision %d:%s '
3483 ui.warn(_('skipping already grafted revision %d:%s '
3484 '(%d:%s also has unknown origin %s)\n')
3484 '(%d:%s also has unknown origin %s)\n')
3485 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3485 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3486 else:
3486 else:
3487 ui.warn(_('skipping already grafted revision %d:%s '
3487 ui.warn(_('skipping already grafted revision %d:%s '
3488 '(%d:%s also has origin %d:%s)\n')
3488 '(%d:%s also has origin %d:%s)\n')
3489 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3489 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3490 revs.remove(ids[n])
3490 revs.remove(ids[n])
3491 elif ctx.hex() in ids:
3491 elif ctx.hex() in ids:
3492 r = ids[ctx.hex()]
3492 r = ids[ctx.hex()]
3493 ui.warn(_('skipping already grafted revision %d:%s '
3493 ui.warn(_('skipping already grafted revision %d:%s '
3494 '(was grafted from %d:%s)\n') %
3494 '(was grafted from %d:%s)\n') %
3495 (r, repo[r], rev, ctx))
3495 (r, repo[r], rev, ctx))
3496 revs.remove(r)
3496 revs.remove(r)
3497 if not revs:
3497 if not revs:
3498 return -1
3498 return -1
3499
3499
3500 wlock = repo.wlock()
3500 wlock = repo.wlock()
3501 try:
3501 try:
3502 for pos, ctx in enumerate(repo.set("%ld", revs)):
3502 for pos, ctx in enumerate(repo.set("%ld", revs)):
3503 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3503 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3504 ctx.description().split('\n', 1)[0])
3504 ctx.description().split('\n', 1)[0])
3505 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3505 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3506 if names:
3506 if names:
3507 desc += ' (%s)' % ' '.join(names)
3507 desc += ' (%s)' % ' '.join(names)
3508 ui.status(_('grafting %s\n') % desc)
3508 ui.status(_('grafting %s\n') % desc)
3509 if opts.get('dry_run'):
3509 if opts.get('dry_run'):
3510 continue
3510 continue
3511
3511
3512 source = ctx.extra().get('source')
3512 source = ctx.extra().get('source')
3513 if not source:
3513 if not source:
3514 source = ctx.hex()
3514 source = ctx.hex()
3515 extra = {'source': source}
3515 extra = {'source': source}
3516 user = ctx.user()
3516 user = ctx.user()
3517 if opts.get('user'):
3517 if opts.get('user'):
3518 user = opts['user']
3518 user = opts['user']
3519 date = ctx.date()
3519 date = ctx.date()
3520 if opts.get('date'):
3520 if opts.get('date'):
3521 date = opts['date']
3521 date = opts['date']
3522 message = ctx.description()
3522 message = ctx.description()
3523 if opts.get('log'):
3523 if opts.get('log'):
3524 message += '\n(grafted from %s)' % ctx.hex()
3524 message += '\n(grafted from %s)' % ctx.hex()
3525
3525
3526 # we don't merge the first commit when continuing
3526 # we don't merge the first commit when continuing
3527 if not cont:
3527 if not cont:
3528 # perform the graft merge with p1(rev) as 'ancestor'
3528 # perform the graft merge with p1(rev) as 'ancestor'
3529 try:
3529 try:
3530 # ui.forcemerge is an internal variable, do not document
3530 # ui.forcemerge is an internal variable, do not document
3531 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3531 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3532 'graft')
3532 'graft')
3533 stats = mergemod.graft(repo, ctx, ctx.p1(),
3533 stats = mergemod.graft(repo, ctx, ctx.p1(),
3534 ['local', 'graft'])
3534 ['local', 'graft'])
3535 finally:
3535 finally:
3536 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3536 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3537 # report any conflicts
3537 # report any conflicts
3538 if stats and stats[3] > 0:
3538 if stats and stats[3] > 0:
3539 # write out state for --continue
3539 # write out state for --continue
3540 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3540 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3541 repo.vfs.write('graftstate', ''.join(nodelines))
3541 repo.vfs.write('graftstate', ''.join(nodelines))
3542 raise util.Abort(
3542 raise util.Abort(
3543 _("unresolved conflicts, can't continue"),
3543 _("unresolved conflicts, can't continue"),
3544 hint=_('use hg resolve and hg graft --continue'))
3544 hint=_('use hg resolve and hg graft --continue'))
3545 else:
3545 else:
3546 cont = False
3546 cont = False
3547
3547
3548 # commit
3548 # commit
3549 node = repo.commit(text=message, user=user,
3549 node = repo.commit(text=message, user=user,
3550 date=date, extra=extra, editor=editor)
3550 date=date, extra=extra, editor=editor)
3551 if node is None:
3551 if node is None:
3552 ui.warn(
3552 ui.warn(
3553 _('note: graft of %d:%s created no changes to commit\n') %
3553 _('note: graft of %d:%s created no changes to commit\n') %
3554 (ctx.rev(), ctx))
3554 (ctx.rev(), ctx))
3555 finally:
3555 finally:
3556 wlock.release()
3556 wlock.release()
3557
3557
3558 # remove state when we complete successfully
3558 # remove state when we complete successfully
3559 if not opts.get('dry_run'):
3559 if not opts.get('dry_run'):
3560 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3560 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3561
3561
3562 return 0
3562 return 0
3563
3563
3564 @command('grep',
3564 @command('grep',
3565 [('0', 'print0', None, _('end fields with NUL')),
3565 [('0', 'print0', None, _('end fields with NUL')),
3566 ('', 'all', None, _('print all revisions that match')),
3566 ('', 'all', None, _('print all revisions that match')),
3567 ('a', 'text', None, _('treat all files as text')),
3567 ('a', 'text', None, _('treat all files as text')),
3568 ('f', 'follow', None,
3568 ('f', 'follow', None,
3569 _('follow changeset history,'
3569 _('follow changeset history,'
3570 ' or file history across copies and renames')),
3570 ' or file history across copies and renames')),
3571 ('i', 'ignore-case', None, _('ignore case when matching')),
3571 ('i', 'ignore-case', None, _('ignore case when matching')),
3572 ('l', 'files-with-matches', None,
3572 ('l', 'files-with-matches', None,
3573 _('print only filenames and revisions that match')),
3573 _('print only filenames and revisions that match')),
3574 ('n', 'line-number', None, _('print matching line numbers')),
3574 ('n', 'line-number', None, _('print matching line numbers')),
3575 ('r', 'rev', [],
3575 ('r', 'rev', [],
3576 _('only search files changed within revision range'), _('REV')),
3576 _('only search files changed within revision range'), _('REV')),
3577 ('u', 'user', None, _('list the author (long with -v)')),
3577 ('u', 'user', None, _('list the author (long with -v)')),
3578 ('d', 'date', None, _('list the date (short with -q)')),
3578 ('d', 'date', None, _('list the date (short with -q)')),
3579 ] + walkopts,
3579 ] + walkopts,
3580 _('[OPTION]... PATTERN [FILE]...'),
3580 _('[OPTION]... PATTERN [FILE]...'),
3581 inferrepo=True)
3581 inferrepo=True)
3582 def grep(ui, repo, pattern, *pats, **opts):
3582 def grep(ui, repo, pattern, *pats, **opts):
3583 """search for a pattern in specified files and revisions
3583 """search for a pattern in specified files and revisions
3584
3584
3585 Search revisions of files for a regular expression.
3585 Search revisions of files for a regular expression.
3586
3586
3587 This command behaves differently than Unix grep. It only accepts
3587 This command behaves differently than Unix grep. It only accepts
3588 Python/Perl regexps. It searches repository history, not the
3588 Python/Perl regexps. It searches repository history, not the
3589 working directory. It always prints the revision number in which a
3589 working directory. It always prints the revision number in which a
3590 match appears.
3590 match appears.
3591
3591
3592 By default, grep only prints output for the first revision of a
3592 By default, grep only prints output for the first revision of a
3593 file in which it finds a match. To get it to print every revision
3593 file in which it finds a match. To get it to print every revision
3594 that contains a change in match status ("-" for a match that
3594 that contains a change in match status ("-" for a match that
3595 becomes a non-match, or "+" for a non-match that becomes a match),
3595 becomes a non-match, or "+" for a non-match that becomes a match),
3596 use the --all flag.
3596 use the --all flag.
3597
3597
3598 Returns 0 if a match is found, 1 otherwise.
3598 Returns 0 if a match is found, 1 otherwise.
3599 """
3599 """
3600 reflags = re.M
3600 reflags = re.M
3601 if opts.get('ignore_case'):
3601 if opts.get('ignore_case'):
3602 reflags |= re.I
3602 reflags |= re.I
3603 try:
3603 try:
3604 regexp = util.re.compile(pattern, reflags)
3604 regexp = util.re.compile(pattern, reflags)
3605 except re.error, inst:
3605 except re.error, inst:
3606 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3606 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3607 return 1
3607 return 1
3608 sep, eol = ':', '\n'
3608 sep, eol = ':', '\n'
3609 if opts.get('print0'):
3609 if opts.get('print0'):
3610 sep = eol = '\0'
3610 sep = eol = '\0'
3611
3611
3612 getfile = util.lrucachefunc(repo.file)
3612 getfile = util.lrucachefunc(repo.file)
3613
3613
3614 def matchlines(body):
3614 def matchlines(body):
3615 begin = 0
3615 begin = 0
3616 linenum = 0
3616 linenum = 0
3617 while begin < len(body):
3617 while begin < len(body):
3618 match = regexp.search(body, begin)
3618 match = regexp.search(body, begin)
3619 if not match:
3619 if not match:
3620 break
3620 break
3621 mstart, mend = match.span()
3621 mstart, mend = match.span()
3622 linenum += body.count('\n', begin, mstart) + 1
3622 linenum += body.count('\n', begin, mstart) + 1
3623 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3623 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3624 begin = body.find('\n', mend) + 1 or len(body) + 1
3624 begin = body.find('\n', mend) + 1 or len(body) + 1
3625 lend = begin - 1
3625 lend = begin - 1
3626 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3626 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3627
3627
3628 class linestate(object):
3628 class linestate(object):
3629 def __init__(self, line, linenum, colstart, colend):
3629 def __init__(self, line, linenum, colstart, colend):
3630 self.line = line
3630 self.line = line
3631 self.linenum = linenum
3631 self.linenum = linenum
3632 self.colstart = colstart
3632 self.colstart = colstart
3633 self.colend = colend
3633 self.colend = colend
3634
3634
3635 def __hash__(self):
3635 def __hash__(self):
3636 return hash((self.linenum, self.line))
3636 return hash((self.linenum, self.line))
3637
3637
3638 def __eq__(self, other):
3638 def __eq__(self, other):
3639 return self.line == other.line
3639 return self.line == other.line
3640
3640
3641 def __iter__(self):
3641 def __iter__(self):
3642 yield (self.line[:self.colstart], '')
3642 yield (self.line[:self.colstart], '')
3643 yield (self.line[self.colstart:self.colend], 'grep.match')
3643 yield (self.line[self.colstart:self.colend], 'grep.match')
3644 rest = self.line[self.colend:]
3644 rest = self.line[self.colend:]
3645 while rest != '':
3645 while rest != '':
3646 match = regexp.search(rest)
3646 match = regexp.search(rest)
3647 if not match:
3647 if not match:
3648 yield (rest, '')
3648 yield (rest, '')
3649 break
3649 break
3650 mstart, mend = match.span()
3650 mstart, mend = match.span()
3651 yield (rest[:mstart], '')
3651 yield (rest[:mstart], '')
3652 yield (rest[mstart:mend], 'grep.match')
3652 yield (rest[mstart:mend], 'grep.match')
3653 rest = rest[mend:]
3653 rest = rest[mend:]
3654
3654
3655 matches = {}
3655 matches = {}
3656 copies = {}
3656 copies = {}
3657 def grepbody(fn, rev, body):
3657 def grepbody(fn, rev, body):
3658 matches[rev].setdefault(fn, [])
3658 matches[rev].setdefault(fn, [])
3659 m = matches[rev][fn]
3659 m = matches[rev][fn]
3660 for lnum, cstart, cend, line in matchlines(body):
3660 for lnum, cstart, cend, line in matchlines(body):
3661 s = linestate(line, lnum, cstart, cend)
3661 s = linestate(line, lnum, cstart, cend)
3662 m.append(s)
3662 m.append(s)
3663
3663
3664 def difflinestates(a, b):
3664 def difflinestates(a, b):
3665 sm = difflib.SequenceMatcher(None, a, b)
3665 sm = difflib.SequenceMatcher(None, a, b)
3666 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3666 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3667 if tag == 'insert':
3667 if tag == 'insert':
3668 for i in xrange(blo, bhi):
3668 for i in xrange(blo, bhi):
3669 yield ('+', b[i])
3669 yield ('+', b[i])
3670 elif tag == 'delete':
3670 elif tag == 'delete':
3671 for i in xrange(alo, ahi):
3671 for i in xrange(alo, ahi):
3672 yield ('-', a[i])
3672 yield ('-', a[i])
3673 elif tag == 'replace':
3673 elif tag == 'replace':
3674 for i in xrange(alo, ahi):
3674 for i in xrange(alo, ahi):
3675 yield ('-', a[i])
3675 yield ('-', a[i])
3676 for i in xrange(blo, bhi):
3676 for i in xrange(blo, bhi):
3677 yield ('+', b[i])
3677 yield ('+', b[i])
3678
3678
3679 def display(fn, ctx, pstates, states):
3679 def display(fn, ctx, pstates, states):
3680 rev = ctx.rev()
3680 rev = ctx.rev()
3681 if ui.quiet:
3681 if ui.quiet:
3682 datefunc = util.shortdate
3682 datefunc = util.shortdate
3683 else:
3683 else:
3684 datefunc = util.datestr
3684 datefunc = util.datestr
3685 found = False
3685 found = False
3686 @util.cachefunc
3686 @util.cachefunc
3687 def binary():
3687 def binary():
3688 flog = getfile(fn)
3688 flog = getfile(fn)
3689 return util.binary(flog.read(ctx.filenode(fn)))
3689 return util.binary(flog.read(ctx.filenode(fn)))
3690
3690
3691 if opts.get('all'):
3691 if opts.get('all'):
3692 iter = difflinestates(pstates, states)
3692 iter = difflinestates(pstates, states)
3693 else:
3693 else:
3694 iter = [('', l) for l in states]
3694 iter = [('', l) for l in states]
3695 for change, l in iter:
3695 for change, l in iter:
3696 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3696 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3697
3697
3698 if opts.get('line_number'):
3698 if opts.get('line_number'):
3699 cols.append((str(l.linenum), 'grep.linenumber'))
3699 cols.append((str(l.linenum), 'grep.linenumber'))
3700 if opts.get('all'):
3700 if opts.get('all'):
3701 cols.append((change, 'grep.change'))
3701 cols.append((change, 'grep.change'))
3702 if opts.get('user'):
3702 if opts.get('user'):
3703 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3703 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3704 if opts.get('date'):
3704 if opts.get('date'):
3705 cols.append((datefunc(ctx.date()), 'grep.date'))
3705 cols.append((datefunc(ctx.date()), 'grep.date'))
3706 for col, label in cols[:-1]:
3706 for col, label in cols[:-1]:
3707 ui.write(col, label=label)
3707 ui.write(col, label=label)
3708 ui.write(sep, label='grep.sep')
3708 ui.write(sep, label='grep.sep')
3709 ui.write(cols[-1][0], label=cols[-1][1])
3709 ui.write(cols[-1][0], label=cols[-1][1])
3710 if not opts.get('files_with_matches'):
3710 if not opts.get('files_with_matches'):
3711 ui.write(sep, label='grep.sep')
3711 ui.write(sep, label='grep.sep')
3712 if not opts.get('text') and binary():
3712 if not opts.get('text') and binary():
3713 ui.write(" Binary file matches")
3713 ui.write(" Binary file matches")
3714 else:
3714 else:
3715 for s, label in l:
3715 for s, label in l:
3716 ui.write(s, label=label)
3716 ui.write(s, label=label)
3717 ui.write(eol)
3717 ui.write(eol)
3718 found = True
3718 found = True
3719 if opts.get('files_with_matches'):
3719 if opts.get('files_with_matches'):
3720 break
3720 break
3721 return found
3721 return found
3722
3722
3723 skip = {}
3723 skip = {}
3724 revfiles = {}
3724 revfiles = {}
3725 matchfn = scmutil.match(repo[None], pats, opts)
3725 matchfn = scmutil.match(repo[None], pats, opts)
3726 found = False
3726 found = False
3727 follow = opts.get('follow')
3727 follow = opts.get('follow')
3728
3728
3729 def prep(ctx, fns):
3729 def prep(ctx, fns):
3730 rev = ctx.rev()
3730 rev = ctx.rev()
3731 pctx = ctx.p1()
3731 pctx = ctx.p1()
3732 parent = pctx.rev()
3732 parent = pctx.rev()
3733 matches.setdefault(rev, {})
3733 matches.setdefault(rev, {})
3734 matches.setdefault(parent, {})
3734 matches.setdefault(parent, {})
3735 files = revfiles.setdefault(rev, [])
3735 files = revfiles.setdefault(rev, [])
3736 for fn in fns:
3736 for fn in fns:
3737 flog = getfile(fn)
3737 flog = getfile(fn)
3738 try:
3738 try:
3739 fnode = ctx.filenode(fn)
3739 fnode = ctx.filenode(fn)
3740 except error.LookupError:
3740 except error.LookupError:
3741 continue
3741 continue
3742
3742
3743 copied = flog.renamed(fnode)
3743 copied = flog.renamed(fnode)
3744 copy = follow and copied and copied[0]
3744 copy = follow and copied and copied[0]
3745 if copy:
3745 if copy:
3746 copies.setdefault(rev, {})[fn] = copy
3746 copies.setdefault(rev, {})[fn] = copy
3747 if fn in skip:
3747 if fn in skip:
3748 if copy:
3748 if copy:
3749 skip[copy] = True
3749 skip[copy] = True
3750 continue
3750 continue
3751 files.append(fn)
3751 files.append(fn)
3752
3752
3753 if fn not in matches[rev]:
3753 if fn not in matches[rev]:
3754 grepbody(fn, rev, flog.read(fnode))
3754 grepbody(fn, rev, flog.read(fnode))
3755
3755
3756 pfn = copy or fn
3756 pfn = copy or fn
3757 if pfn not in matches[parent]:
3757 if pfn not in matches[parent]:
3758 try:
3758 try:
3759 fnode = pctx.filenode(pfn)
3759 fnode = pctx.filenode(pfn)
3760 grepbody(pfn, parent, flog.read(fnode))
3760 grepbody(pfn, parent, flog.read(fnode))
3761 except error.LookupError:
3761 except error.LookupError:
3762 pass
3762 pass
3763
3763
3764 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3764 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3765 rev = ctx.rev()
3765 rev = ctx.rev()
3766 parent = ctx.p1().rev()
3766 parent = ctx.p1().rev()
3767 for fn in sorted(revfiles.get(rev, [])):
3767 for fn in sorted(revfiles.get(rev, [])):
3768 states = matches[rev][fn]
3768 states = matches[rev][fn]
3769 copy = copies.get(rev, {}).get(fn)
3769 copy = copies.get(rev, {}).get(fn)
3770 if fn in skip:
3770 if fn in skip:
3771 if copy:
3771 if copy:
3772 skip[copy] = True
3772 skip[copy] = True
3773 continue
3773 continue
3774 pstates = matches.get(parent, {}).get(copy or fn, [])
3774 pstates = matches.get(parent, {}).get(copy or fn, [])
3775 if pstates or states:
3775 if pstates or states:
3776 r = display(fn, ctx, pstates, states)
3776 r = display(fn, ctx, pstates, states)
3777 found = found or r
3777 found = found or r
3778 if r and not opts.get('all'):
3778 if r and not opts.get('all'):
3779 skip[fn] = True
3779 skip[fn] = True
3780 if copy:
3780 if copy:
3781 skip[copy] = True
3781 skip[copy] = True
3782 del matches[rev]
3782 del matches[rev]
3783 del revfiles[rev]
3783 del revfiles[rev]
3784
3784
3785 return not found
3785 return not found
3786
3786
3787 @command('heads',
3787 @command('heads',
3788 [('r', 'rev', '',
3788 [('r', 'rev', '',
3789 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3789 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3790 ('t', 'topo', False, _('show topological heads only')),
3790 ('t', 'topo', False, _('show topological heads only')),
3791 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3791 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3792 ('c', 'closed', False, _('show normal and closed branch heads')),
3792 ('c', 'closed', False, _('show normal and closed branch heads')),
3793 ] + templateopts,
3793 ] + templateopts,
3794 _('[-ct] [-r STARTREV] [REV]...'))
3794 _('[-ct] [-r STARTREV] [REV]...'))
3795 def heads(ui, repo, *branchrevs, **opts):
3795 def heads(ui, repo, *branchrevs, **opts):
3796 """show branch heads
3796 """show branch heads
3797
3797
3798 With no arguments, show all open branch heads in the repository.
3798 With no arguments, show all open branch heads in the repository.
3799 Branch heads are changesets that have no descendants on the
3799 Branch heads are changesets that have no descendants on the
3800 same branch. They are where development generally takes place and
3800 same branch. They are where development generally takes place and
3801 are the usual targets for update and merge operations.
3801 are the usual targets for update and merge operations.
3802
3802
3803 If one or more REVs are given, only open branch heads on the
3803 If one or more REVs are given, only open branch heads on the
3804 branches associated with the specified changesets are shown. This
3804 branches associated with the specified changesets are shown. This
3805 means that you can use :hg:`heads .` to see the heads on the
3805 means that you can use :hg:`heads .` to see the heads on the
3806 currently checked-out branch.
3806 currently checked-out branch.
3807
3807
3808 If -c/--closed is specified, also show branch heads marked closed
3808 If -c/--closed is specified, also show branch heads marked closed
3809 (see :hg:`commit --close-branch`).
3809 (see :hg:`commit --close-branch`).
3810
3810
3811 If STARTREV is specified, only those heads that are descendants of
3811 If STARTREV is specified, only those heads that are descendants of
3812 STARTREV will be displayed.
3812 STARTREV will be displayed.
3813
3813
3814 If -t/--topo is specified, named branch mechanics will be ignored and only
3814 If -t/--topo is specified, named branch mechanics will be ignored and only
3815 topological heads (changesets with no children) will be shown.
3815 topological heads (changesets with no children) will be shown.
3816
3816
3817 Returns 0 if matching heads are found, 1 if not.
3817 Returns 0 if matching heads are found, 1 if not.
3818 """
3818 """
3819
3819
3820 start = None
3820 start = None
3821 if 'rev' in opts:
3821 if 'rev' in opts:
3822 start = scmutil.revsingle(repo, opts['rev'], None).node()
3822 start = scmutil.revsingle(repo, opts['rev'], None).node()
3823
3823
3824 if opts.get('topo'):
3824 if opts.get('topo'):
3825 heads = [repo[h] for h in repo.heads(start)]
3825 heads = [repo[h] for h in repo.heads(start)]
3826 else:
3826 else:
3827 heads = []
3827 heads = []
3828 for branch in repo.branchmap():
3828 for branch in repo.branchmap():
3829 heads += repo.branchheads(branch, start, opts.get('closed'))
3829 heads += repo.branchheads(branch, start, opts.get('closed'))
3830 heads = [repo[h] for h in heads]
3830 heads = [repo[h] for h in heads]
3831
3831
3832 if branchrevs:
3832 if branchrevs:
3833 branches = set(repo[br].branch() for br in branchrevs)
3833 branches = set(repo[br].branch() for br in branchrevs)
3834 heads = [h for h in heads if h.branch() in branches]
3834 heads = [h for h in heads if h.branch() in branches]
3835
3835
3836 if opts.get('active') and branchrevs:
3836 if opts.get('active') and branchrevs:
3837 dagheads = repo.heads(start)
3837 dagheads = repo.heads(start)
3838 heads = [h for h in heads if h.node() in dagheads]
3838 heads = [h for h in heads if h.node() in dagheads]
3839
3839
3840 if branchrevs:
3840 if branchrevs:
3841 haveheads = set(h.branch() for h in heads)
3841 haveheads = set(h.branch() for h in heads)
3842 if branches - haveheads:
3842 if branches - haveheads:
3843 headless = ', '.join(b for b in branches - haveheads)
3843 headless = ', '.join(b for b in branches - haveheads)
3844 msg = _('no open branch heads found on branches %s')
3844 msg = _('no open branch heads found on branches %s')
3845 if opts.get('rev'):
3845 if opts.get('rev'):
3846 msg += _(' (started at %s)') % opts['rev']
3846 msg += _(' (started at %s)') % opts['rev']
3847 ui.warn((msg + '\n') % headless)
3847 ui.warn((msg + '\n') % headless)
3848
3848
3849 if not heads:
3849 if not heads:
3850 return 1
3850 return 1
3851
3851
3852 heads = sorted(heads, key=lambda x: -x.rev())
3852 heads = sorted(heads, key=lambda x: -x.rev())
3853 displayer = cmdutil.show_changeset(ui, repo, opts)
3853 displayer = cmdutil.show_changeset(ui, repo, opts)
3854 for ctx in heads:
3854 for ctx in heads:
3855 displayer.show(ctx)
3855 displayer.show(ctx)
3856 displayer.close()
3856 displayer.close()
3857
3857
3858 @command('help',
3858 @command('help',
3859 [('e', 'extension', None, _('show only help for extensions')),
3859 [('e', 'extension', None, _('show only help for extensions')),
3860 ('c', 'command', None, _('show only help for commands')),
3860 ('c', 'command', None, _('show only help for commands')),
3861 ('k', 'keyword', '', _('show topics matching keyword')),
3861 ('k', 'keyword', '', _('show topics matching keyword')),
3862 ],
3862 ],
3863 _('[-ec] [TOPIC]'),
3863 _('[-ec] [TOPIC]'),
3864 norepo=True)
3864 norepo=True)
3865 def help_(ui, name=None, **opts):
3865 def help_(ui, name=None, **opts):
3866 """show help for a given topic or a help overview
3866 """show help for a given topic or a help overview
3867
3867
3868 With no arguments, print a list of commands with short help messages.
3868 With no arguments, print a list of commands with short help messages.
3869
3869
3870 Given a topic, extension, or command name, print help for that
3870 Given a topic, extension, or command name, print help for that
3871 topic.
3871 topic.
3872
3872
3873 Returns 0 if successful.
3873 Returns 0 if successful.
3874 """
3874 """
3875
3875
3876 textwidth = min(ui.termwidth(), 80) - 2
3876 textwidth = min(ui.termwidth(), 80) - 2
3877
3877
3878 keep = []
3878 keep = []
3879 if ui.verbose:
3879 if ui.verbose:
3880 keep.append('verbose')
3880 keep.append('verbose')
3881 if sys.platform.startswith('win'):
3881 if sys.platform.startswith('win'):
3882 keep.append('windows')
3882 keep.append('windows')
3883 elif sys.platform == 'OpenVMS':
3883 elif sys.platform == 'OpenVMS':
3884 keep.append('vms')
3884 keep.append('vms')
3885 elif sys.platform == 'plan9':
3885 elif sys.platform == 'plan9':
3886 keep.append('plan9')
3886 keep.append('plan9')
3887 else:
3887 else:
3888 keep.append('unix')
3888 keep.append('unix')
3889 keep.append(sys.platform.lower())
3889 keep.append(sys.platform.lower())
3890
3890
3891 section = None
3891 section = None
3892 if name and '.' in name:
3892 if name and '.' in name:
3893 name, section = name.split('.', 1)
3893 name, section = name.split('.', 1)
3894
3894
3895 text = help.help_(ui, name, **opts)
3895 text = help.help_(ui, name, **opts)
3896
3896
3897 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3897 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3898 section=section)
3898 section=section)
3899 if section and not formatted:
3899 if section and not formatted:
3900 raise util.Abort(_("help section not found"))
3900 raise util.Abort(_("help section not found"))
3901
3901
3902 if 'verbose' in pruned:
3902 if 'verbose' in pruned:
3903 keep.append('omitted')
3903 keep.append('omitted')
3904 else:
3904 else:
3905 keep.append('notomitted')
3905 keep.append('notomitted')
3906 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3906 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3907 section=section)
3907 section=section)
3908 ui.write(formatted)
3908 ui.write(formatted)
3909
3909
3910
3910
3911 @command('identify|id',
3911 @command('identify|id',
3912 [('r', 'rev', '',
3912 [('r', 'rev', '',
3913 _('identify the specified revision'), _('REV')),
3913 _('identify the specified revision'), _('REV')),
3914 ('n', 'num', None, _('show local revision number')),
3914 ('n', 'num', None, _('show local revision number')),
3915 ('i', 'id', None, _('show global revision id')),
3915 ('i', 'id', None, _('show global revision id')),
3916 ('b', 'branch', None, _('show branch')),
3916 ('b', 'branch', None, _('show branch')),
3917 ('t', 'tags', None, _('show tags')),
3917 ('t', 'tags', None, _('show tags')),
3918 ('B', 'bookmarks', None, _('show bookmarks')),
3918 ('B', 'bookmarks', None, _('show bookmarks')),
3919 ] + remoteopts,
3919 ] + remoteopts,
3920 _('[-nibtB] [-r REV] [SOURCE]'),
3920 _('[-nibtB] [-r REV] [SOURCE]'),
3921 optionalrepo=True)
3921 optionalrepo=True)
3922 def identify(ui, repo, source=None, rev=None,
3922 def identify(ui, repo, source=None, rev=None,
3923 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3923 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3924 """identify the working directory or specified revision
3924 """identify the working directory or specified revision
3925
3925
3926 Print a summary identifying the repository state at REV using one or
3926 Print a summary identifying the repository state at REV using one or
3927 two parent hash identifiers, followed by a "+" if the working
3927 two parent hash identifiers, followed by a "+" if the working
3928 directory has uncommitted changes, the branch name (if not default),
3928 directory has uncommitted changes, the branch name (if not default),
3929 a list of tags, and a list of bookmarks.
3929 a list of tags, and a list of bookmarks.
3930
3930
3931 When REV is not given, print a summary of the current state of the
3931 When REV is not given, print a summary of the current state of the
3932 repository.
3932 repository.
3933
3933
3934 Specifying a path to a repository root or Mercurial bundle will
3934 Specifying a path to a repository root or Mercurial bundle will
3935 cause lookup to operate on that repository/bundle.
3935 cause lookup to operate on that repository/bundle.
3936
3936
3937 .. container:: verbose
3937 .. container:: verbose
3938
3938
3939 Examples:
3939 Examples:
3940
3940
3941 - generate a build identifier for the working directory::
3941 - generate a build identifier for the working directory::
3942
3942
3943 hg id --id > build-id.dat
3943 hg id --id > build-id.dat
3944
3944
3945 - find the revision corresponding to a tag::
3945 - find the revision corresponding to a tag::
3946
3946
3947 hg id -n -r 1.3
3947 hg id -n -r 1.3
3948
3948
3949 - check the most recent revision of a remote repository::
3949 - check the most recent revision of a remote repository::
3950
3950
3951 hg id -r tip http://selenic.com/hg/
3951 hg id -r tip http://selenic.com/hg/
3952
3952
3953 Returns 0 if successful.
3953 Returns 0 if successful.
3954 """
3954 """
3955
3955
3956 if not repo and not source:
3956 if not repo and not source:
3957 raise util.Abort(_("there is no Mercurial repository here "
3957 raise util.Abort(_("there is no Mercurial repository here "
3958 "(.hg not found)"))
3958 "(.hg not found)"))
3959
3959
3960 if ui.debugflag:
3960 if ui.debugflag:
3961 hexfunc = hex
3961 hexfunc = hex
3962 else:
3962 else:
3963 hexfunc = short
3963 hexfunc = short
3964 default = not (num or id or branch or tags or bookmarks)
3964 default = not (num or id or branch or tags or bookmarks)
3965 output = []
3965 output = []
3966 revs = []
3966 revs = []
3967
3967
3968 if source:
3968 if source:
3969 source, branches = hg.parseurl(ui.expandpath(source))
3969 source, branches = hg.parseurl(ui.expandpath(source))
3970 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3970 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3971 repo = peer.local()
3971 repo = peer.local()
3972 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3972 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3973
3973
3974 if not repo:
3974 if not repo:
3975 if num or branch or tags:
3975 if num or branch or tags:
3976 raise util.Abort(
3976 raise util.Abort(
3977 _("can't query remote revision number, branch, or tags"))
3977 _("can't query remote revision number, branch, or tags"))
3978 if not rev and revs:
3978 if not rev and revs:
3979 rev = revs[0]
3979 rev = revs[0]
3980 if not rev:
3980 if not rev:
3981 rev = "tip"
3981 rev = "tip"
3982
3982
3983 remoterev = peer.lookup(rev)
3983 remoterev = peer.lookup(rev)
3984 if default or id:
3984 if default or id:
3985 output = [hexfunc(remoterev)]
3985 output = [hexfunc(remoterev)]
3986
3986
3987 def getbms():
3987 def getbms():
3988 bms = []
3988 bms = []
3989
3989
3990 if 'bookmarks' in peer.listkeys('namespaces'):
3990 if 'bookmarks' in peer.listkeys('namespaces'):
3991 hexremoterev = hex(remoterev)
3991 hexremoterev = hex(remoterev)
3992 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3992 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3993 if bmr == hexremoterev]
3993 if bmr == hexremoterev]
3994
3994
3995 return sorted(bms)
3995 return sorted(bms)
3996
3996
3997 if bookmarks:
3997 if bookmarks:
3998 output.extend(getbms())
3998 output.extend(getbms())
3999 elif default and not ui.quiet:
3999 elif default and not ui.quiet:
4000 # multiple bookmarks for a single parent separated by '/'
4000 # multiple bookmarks for a single parent separated by '/'
4001 bm = '/'.join(getbms())
4001 bm = '/'.join(getbms())
4002 if bm:
4002 if bm:
4003 output.append(bm)
4003 output.append(bm)
4004 else:
4004 else:
4005 if not rev:
4005 if not rev:
4006 ctx = repo[None]
4006 ctx = repo[None]
4007 parents = ctx.parents()
4007 parents = ctx.parents()
4008 changed = ""
4008 changed = ""
4009 if default or id or num:
4009 if default or id or num:
4010 if (util.any(repo.status())
4010 if (util.any(repo.status())
4011 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
4011 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
4012 changed = '+'
4012 changed = '+'
4013 if default or id:
4013 if default or id:
4014 output = ["%s%s" %
4014 output = ["%s%s" %
4015 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4015 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4016 if num:
4016 if num:
4017 output.append("%s%s" %
4017 output.append("%s%s" %
4018 ('+'.join([str(p.rev()) for p in parents]), changed))
4018 ('+'.join([str(p.rev()) for p in parents]), changed))
4019 else:
4019 else:
4020 ctx = scmutil.revsingle(repo, rev)
4020 ctx = scmutil.revsingle(repo, rev)
4021 if default or id:
4021 if default or id:
4022 output = [hexfunc(ctx.node())]
4022 output = [hexfunc(ctx.node())]
4023 if num:
4023 if num:
4024 output.append(str(ctx.rev()))
4024 output.append(str(ctx.rev()))
4025
4025
4026 if default and not ui.quiet:
4026 if default and not ui.quiet:
4027 b = ctx.branch()
4027 b = ctx.branch()
4028 if b != 'default':
4028 if b != 'default':
4029 output.append("(%s)" % b)
4029 output.append("(%s)" % b)
4030
4030
4031 # multiple tags for a single parent separated by '/'
4031 # multiple tags for a single parent separated by '/'
4032 t = '/'.join(ctx.tags())
4032 t = '/'.join(ctx.tags())
4033 if t:
4033 if t:
4034 output.append(t)
4034 output.append(t)
4035
4035
4036 # multiple bookmarks for a single parent separated by '/'
4036 # multiple bookmarks for a single parent separated by '/'
4037 bm = '/'.join(ctx.bookmarks())
4037 bm = '/'.join(ctx.bookmarks())
4038 if bm:
4038 if bm:
4039 output.append(bm)
4039 output.append(bm)
4040 else:
4040 else:
4041 if branch:
4041 if branch:
4042 output.append(ctx.branch())
4042 output.append(ctx.branch())
4043
4043
4044 if tags:
4044 if tags:
4045 output.extend(ctx.tags())
4045 output.extend(ctx.tags())
4046
4046
4047 if bookmarks:
4047 if bookmarks:
4048 output.extend(ctx.bookmarks())
4048 output.extend(ctx.bookmarks())
4049
4049
4050 ui.write("%s\n" % ' '.join(output))
4050 ui.write("%s\n" % ' '.join(output))
4051
4051
4052 @command('import|patch',
4052 @command('import|patch',
4053 [('p', 'strip', 1,
4053 [('p', 'strip', 1,
4054 _('directory strip option for patch. This has the same '
4054 _('directory strip option for patch. This has the same '
4055 'meaning as the corresponding patch option'), _('NUM')),
4055 'meaning as the corresponding patch option'), _('NUM')),
4056 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4056 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4057 ('e', 'edit', False, _('invoke editor on commit messages')),
4057 ('e', 'edit', False, _('invoke editor on commit messages')),
4058 ('f', 'force', None,
4058 ('f', 'force', None,
4059 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4059 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4060 ('', 'no-commit', None,
4060 ('', 'no-commit', None,
4061 _("don't commit, just update the working directory")),
4061 _("don't commit, just update the working directory")),
4062 ('', 'bypass', None,
4062 ('', 'bypass', None,
4063 _("apply patch without touching the working directory")),
4063 _("apply patch without touching the working directory")),
4064 ('', 'partial', None,
4064 ('', 'partial', None,
4065 _('commit even if some hunks fail')),
4065 _('commit even if some hunks fail')),
4066 ('', 'exact', None,
4066 ('', 'exact', None,
4067 _('apply patch to the nodes from which it was generated')),
4067 _('apply patch to the nodes from which it was generated')),
4068 ('', 'prefix', '',
4068 ('', 'prefix', '',
4069 _('apply patch to directory relative to the root'), _('DIR')),
4069 _('apply patch to directory relative to the root'), _('DIR')),
4070 ('', 'import-branch', None,
4070 ('', 'import-branch', None,
4071 _('use any branch information in patch (implied by --exact)'))] +
4071 _('use any branch information in patch (implied by --exact)'))] +
4072 commitopts + commitopts2 + similarityopts,
4072 commitopts + commitopts2 + similarityopts,
4073 _('[OPTION]... PATCH...'))
4073 _('[OPTION]... PATCH...'))
4074 def import_(ui, repo, patch1=None, *patches, **opts):
4074 def import_(ui, repo, patch1=None, *patches, **opts):
4075 """import an ordered set of patches
4075 """import an ordered set of patches
4076
4076
4077 Import a list of patches and commit them individually (unless
4077 Import a list of patches and commit them individually (unless
4078 --no-commit is specified).
4078 --no-commit is specified).
4079
4079
4080 Because import first applies changes to the working directory,
4080 Because import first applies changes to the working directory,
4081 import will abort if there are outstanding changes.
4081 import will abort if there are outstanding changes.
4082
4082
4083 You can import a patch straight from a mail message. Even patches
4083 You can import a patch straight from a mail message. Even patches
4084 as attachments work (to use the body part, it must have type
4084 as attachments work (to use the body part, it must have type
4085 text/plain or text/x-patch). From and Subject headers of email
4085 text/plain or text/x-patch). From and Subject headers of email
4086 message are used as default committer and commit message. All
4086 message are used as default committer and commit message. All
4087 text/plain body parts before first diff are added to commit
4087 text/plain body parts before first diff are added to commit
4088 message.
4088 message.
4089
4089
4090 If the imported patch was generated by :hg:`export`, user and
4090 If the imported patch was generated by :hg:`export`, user and
4091 description from patch override values from message headers and
4091 description from patch override values from message headers and
4092 body. Values given on command line with -m/--message and -u/--user
4092 body. Values given on command line with -m/--message and -u/--user
4093 override these.
4093 override these.
4094
4094
4095 If --exact is specified, import will set the working directory to
4095 If --exact is specified, import will set the working directory to
4096 the parent of each patch before applying it, and will abort if the
4096 the parent of each patch before applying it, and will abort if the
4097 resulting changeset has a different ID than the one recorded in
4097 resulting changeset has a different ID than the one recorded in
4098 the patch. This may happen due to character set problems or other
4098 the patch. This may happen due to character set problems or other
4099 deficiencies in the text patch format.
4099 deficiencies in the text patch format.
4100
4100
4101 Use --bypass to apply and commit patches directly to the
4101 Use --bypass to apply and commit patches directly to the
4102 repository, not touching the working directory. Without --exact,
4102 repository, not touching the working directory. Without --exact,
4103 patches will be applied on top of the working directory parent
4103 patches will be applied on top of the working directory parent
4104 revision.
4104 revision.
4105
4105
4106 With -s/--similarity, hg will attempt to discover renames and
4106 With -s/--similarity, hg will attempt to discover renames and
4107 copies in the patch in the same way as :hg:`addremove`.
4107 copies in the patch in the same way as :hg:`addremove`.
4108
4108
4109 Use --partial to ensure a changeset will be created from the patch
4109 Use --partial to ensure a changeset will be created from the patch
4110 even if some hunks fail to apply. Hunks that fail to apply will be
4110 even if some hunks fail to apply. Hunks that fail to apply will be
4111 written to a <target-file>.rej file. Conflicts can then be resolved
4111 written to a <target-file>.rej file. Conflicts can then be resolved
4112 by hand before :hg:`commit --amend` is run to update the created
4112 by hand before :hg:`commit --amend` is run to update the created
4113 changeset. This flag exists to let people import patches that
4113 changeset. This flag exists to let people import patches that
4114 partially apply without losing the associated metadata (author,
4114 partially apply without losing the associated metadata (author,
4115 date, description, ...). Note that when none of the hunk applies
4115 date, description, ...). Note that when none of the hunk applies
4116 cleanly, :hg:`import --partial` will create an empty changeset,
4116 cleanly, :hg:`import --partial` will create an empty changeset,
4117 importing only the patch metadata.
4117 importing only the patch metadata.
4118
4118
4119 To read a patch from standard input, use "-" as the patch name. If
4119 To read a patch from standard input, use "-" as the patch name. If
4120 a URL is specified, the patch will be downloaded from it.
4120 a URL is specified, the patch will be downloaded from it.
4121 See :hg:`help dates` for a list of formats valid for -d/--date.
4121 See :hg:`help dates` for a list of formats valid for -d/--date.
4122
4122
4123 .. container:: verbose
4123 .. container:: verbose
4124
4124
4125 Examples:
4125 Examples:
4126
4126
4127 - import a traditional patch from a website and detect renames::
4127 - import a traditional patch from a website and detect renames::
4128
4128
4129 hg import -s 80 http://example.com/bugfix.patch
4129 hg import -s 80 http://example.com/bugfix.patch
4130
4130
4131 - import a changeset from an hgweb server::
4131 - import a changeset from an hgweb server::
4132
4132
4133 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4133 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4134
4134
4135 - import all the patches in an Unix-style mbox::
4135 - import all the patches in an Unix-style mbox::
4136
4136
4137 hg import incoming-patches.mbox
4137 hg import incoming-patches.mbox
4138
4138
4139 - attempt to exactly restore an exported changeset (not always
4139 - attempt to exactly restore an exported changeset (not always
4140 possible)::
4140 possible)::
4141
4141
4142 hg import --exact proposed-fix.patch
4142 hg import --exact proposed-fix.patch
4143
4143
4144 Returns 0 on success, 1 on partial success (see --partial).
4144 Returns 0 on success, 1 on partial success (see --partial).
4145 """
4145 """
4146
4146
4147 if not patch1:
4147 if not patch1:
4148 raise util.Abort(_('need at least one patch to import'))
4148 raise util.Abort(_('need at least one patch to import'))
4149
4149
4150 patches = (patch1,) + patches
4150 patches = (patch1,) + patches
4151
4151
4152 date = opts.get('date')
4152 date = opts.get('date')
4153 if date:
4153 if date:
4154 opts['date'] = util.parsedate(date)
4154 opts['date'] = util.parsedate(date)
4155
4155
4156 update = not opts.get('bypass')
4156 update = not opts.get('bypass')
4157 if not update and opts.get('no_commit'):
4157 if not update and opts.get('no_commit'):
4158 raise util.Abort(_('cannot use --no-commit with --bypass'))
4158 raise util.Abort(_('cannot use --no-commit with --bypass'))
4159 try:
4159 try:
4160 sim = float(opts.get('similarity') or 0)
4160 sim = float(opts.get('similarity') or 0)
4161 except ValueError:
4161 except ValueError:
4162 raise util.Abort(_('similarity must be a number'))
4162 raise util.Abort(_('similarity must be a number'))
4163 if sim < 0 or sim > 100:
4163 if sim < 0 or sim > 100:
4164 raise util.Abort(_('similarity must be between 0 and 100'))
4164 raise util.Abort(_('similarity must be between 0 and 100'))
4165 if sim and not update:
4165 if sim and not update:
4166 raise util.Abort(_('cannot use --similarity with --bypass'))
4166 raise util.Abort(_('cannot use --similarity with --bypass'))
4167 if opts.get('exact') and opts.get('edit'):
4167 if opts.get('exact') and opts.get('edit'):
4168 raise util.Abort(_('cannot use --exact with --edit'))
4168 raise util.Abort(_('cannot use --exact with --edit'))
4169 if opts.get('exact') and opts.get('prefix'):
4169 if opts.get('exact') and opts.get('prefix'):
4170 raise util.Abort(_('cannot use --exact with --prefix'))
4170 raise util.Abort(_('cannot use --exact with --prefix'))
4171
4171
4172 if update:
4172 if update:
4173 cmdutil.checkunfinished(repo)
4173 cmdutil.checkunfinished(repo)
4174 if (opts.get('exact') or not opts.get('force')) and update:
4174 if (opts.get('exact') or not opts.get('force')) and update:
4175 cmdutil.bailifchanged(repo)
4175 cmdutil.bailifchanged(repo)
4176
4176
4177 base = opts["base"]
4177 base = opts["base"]
4178 wlock = lock = tr = None
4178 wlock = lock = tr = None
4179 msgs = []
4179 msgs = []
4180 ret = 0
4180 ret = 0
4181
4181
4182
4182
4183 try:
4183 try:
4184 try:
4184 try:
4185 wlock = repo.wlock()
4185 wlock = repo.wlock()
4186 repo.dirstate.beginparentchange()
4186 repo.dirstate.beginparentchange()
4187 if not opts.get('no_commit'):
4187 if not opts.get('no_commit'):
4188 lock = repo.lock()
4188 lock = repo.lock()
4189 tr = repo.transaction('import')
4189 tr = repo.transaction('import')
4190 parents = repo.parents()
4190 parents = repo.parents()
4191 for patchurl in patches:
4191 for patchurl in patches:
4192 if patchurl == '-':
4192 if patchurl == '-':
4193 ui.status(_('applying patch from stdin\n'))
4193 ui.status(_('applying patch from stdin\n'))
4194 patchfile = ui.fin
4194 patchfile = ui.fin
4195 patchurl = 'stdin' # for error message
4195 patchurl = 'stdin' # for error message
4196 else:
4196 else:
4197 patchurl = os.path.join(base, patchurl)
4197 patchurl = os.path.join(base, patchurl)
4198 ui.status(_('applying %s\n') % patchurl)
4198 ui.status(_('applying %s\n') % patchurl)
4199 patchfile = hg.openpath(ui, patchurl)
4199 patchfile = hg.openpath(ui, patchurl)
4200
4200
4201 haspatch = False
4201 haspatch = False
4202 for hunk in patch.split(patchfile):
4202 for hunk in patch.split(patchfile):
4203 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4203 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4204 parents, opts,
4204 parents, opts,
4205 msgs, hg.clean)
4205 msgs, hg.clean)
4206 if msg:
4206 if msg:
4207 haspatch = True
4207 haspatch = True
4208 ui.note(msg + '\n')
4208 ui.note(msg + '\n')
4209 if update or opts.get('exact'):
4209 if update or opts.get('exact'):
4210 parents = repo.parents()
4210 parents = repo.parents()
4211 else:
4211 else:
4212 parents = [repo[node]]
4212 parents = [repo[node]]
4213 if rej:
4213 if rej:
4214 ui.write_err(_("patch applied partially\n"))
4214 ui.write_err(_("patch applied partially\n"))
4215 ui.write_err(_("(fix the .rej files and run "
4215 ui.write_err(_("(fix the .rej files and run "
4216 "`hg commit --amend`)\n"))
4216 "`hg commit --amend`)\n"))
4217 ret = 1
4217 ret = 1
4218 break
4218 break
4219
4219
4220 if not haspatch:
4220 if not haspatch:
4221 raise util.Abort(_('%s: no diffs found') % patchurl)
4221 raise util.Abort(_('%s: no diffs found') % patchurl)
4222
4222
4223 if tr:
4223 if tr:
4224 tr.close()
4224 tr.close()
4225 if msgs:
4225 if msgs:
4226 repo.savecommitmessage('\n* * *\n'.join(msgs))
4226 repo.savecommitmessage('\n* * *\n'.join(msgs))
4227 repo.dirstate.endparentchange()
4227 repo.dirstate.endparentchange()
4228 return ret
4228 return ret
4229 except: # re-raises
4229 except: # re-raises
4230 # wlock.release() indirectly calls dirstate.write(): since
4230 # wlock.release() indirectly calls dirstate.write(): since
4231 # we're crashing, we do not want to change the working dir
4231 # we're crashing, we do not want to change the working dir
4232 # parent after all, so make sure it writes nothing
4232 # parent after all, so make sure it writes nothing
4233 repo.dirstate.invalidate()
4233 repo.dirstate.invalidate()
4234 raise
4234 raise
4235 finally:
4235 finally:
4236 if tr:
4236 if tr:
4237 tr.release()
4237 tr.release()
4238 release(lock, wlock)
4238 release(lock, wlock)
4239
4239
4240 @command('incoming|in',
4240 @command('incoming|in',
4241 [('f', 'force', None,
4241 [('f', 'force', None,
4242 _('run even if remote repository is unrelated')),
4242 _('run even if remote repository is unrelated')),
4243 ('n', 'newest-first', None, _('show newest record first')),
4243 ('n', 'newest-first', None, _('show newest record first')),
4244 ('', 'bundle', '',
4244 ('', 'bundle', '',
4245 _('file to store the bundles into'), _('FILE')),
4245 _('file to store the bundles into'), _('FILE')),
4246 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4246 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4247 ('B', 'bookmarks', False, _("compare bookmarks")),
4247 ('B', 'bookmarks', False, _("compare bookmarks")),
4248 ('b', 'branch', [],
4248 ('b', 'branch', [],
4249 _('a specific branch you would like to pull'), _('BRANCH')),
4249 _('a specific branch you would like to pull'), _('BRANCH')),
4250 ] + logopts + remoteopts + subrepoopts,
4250 ] + logopts + remoteopts + subrepoopts,
4251 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4251 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4252 def incoming(ui, repo, source="default", **opts):
4252 def incoming(ui, repo, source="default", **opts):
4253 """show new changesets found in source
4253 """show new changesets found in source
4254
4254
4255 Show new changesets found in the specified path/URL or the default
4255 Show new changesets found in the specified path/URL or the default
4256 pull location. These are the changesets that would have been pulled
4256 pull location. These are the changesets that would have been pulled
4257 if a pull at the time you issued this command.
4257 if a pull at the time you issued this command.
4258
4258
4259 See pull for valid source format details.
4259 See pull for valid source format details.
4260
4260
4261 .. container:: verbose
4261 .. container:: verbose
4262
4262
4263 For remote repository, using --bundle avoids downloading the
4263 For remote repository, using --bundle avoids downloading the
4264 changesets twice if the incoming is followed by a pull.
4264 changesets twice if the incoming is followed by a pull.
4265
4265
4266 Examples:
4266 Examples:
4267
4267
4268 - show incoming changes with patches and full description::
4268 - show incoming changes with patches and full description::
4269
4269
4270 hg incoming -vp
4270 hg incoming -vp
4271
4271
4272 - show incoming changes excluding merges, store a bundle::
4272 - show incoming changes excluding merges, store a bundle::
4273
4273
4274 hg in -vpM --bundle incoming.hg
4274 hg in -vpM --bundle incoming.hg
4275 hg pull incoming.hg
4275 hg pull incoming.hg
4276
4276
4277 - briefly list changes inside a bundle::
4277 - briefly list changes inside a bundle::
4278
4278
4279 hg in changes.hg -T "{desc|firstline}\\n"
4279 hg in changes.hg -T "{desc|firstline}\\n"
4280
4280
4281 Returns 0 if there are incoming changes, 1 otherwise.
4281 Returns 0 if there are incoming changes, 1 otherwise.
4282 """
4282 """
4283 if opts.get('graph'):
4283 if opts.get('graph'):
4284 cmdutil.checkunsupportedgraphflags([], opts)
4284 cmdutil.checkunsupportedgraphflags([], opts)
4285 def display(other, chlist, displayer):
4285 def display(other, chlist, displayer):
4286 revdag = cmdutil.graphrevs(other, chlist, opts)
4286 revdag = cmdutil.graphrevs(other, chlist, opts)
4287 showparents = [ctx.node() for ctx in repo[None].parents()]
4287 showparents = [ctx.node() for ctx in repo[None].parents()]
4288 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4288 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4289 graphmod.asciiedges)
4289 graphmod.asciiedges)
4290
4290
4291 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4291 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4292 return 0
4292 return 0
4293
4293
4294 if opts.get('bundle') and opts.get('subrepos'):
4294 if opts.get('bundle') and opts.get('subrepos'):
4295 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4295 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4296
4296
4297 if opts.get('bookmarks'):
4297 if opts.get('bookmarks'):
4298 source, branches = hg.parseurl(ui.expandpath(source),
4298 source, branches = hg.parseurl(ui.expandpath(source),
4299 opts.get('branch'))
4299 opts.get('branch'))
4300 other = hg.peer(repo, opts, source)
4300 other = hg.peer(repo, opts, source)
4301 if 'bookmarks' not in other.listkeys('namespaces'):
4301 if 'bookmarks' not in other.listkeys('namespaces'):
4302 ui.warn(_("remote doesn't support bookmarks\n"))
4302 ui.warn(_("remote doesn't support bookmarks\n"))
4303 return 0
4303 return 0
4304 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4304 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4305 return bookmarks.diff(ui, repo, other)
4305 return bookmarks.diff(ui, repo, other)
4306
4306
4307 repo._subtoppath = ui.expandpath(source)
4307 repo._subtoppath = ui.expandpath(source)
4308 try:
4308 try:
4309 return hg.incoming(ui, repo, source, opts)
4309 return hg.incoming(ui, repo, source, opts)
4310 finally:
4310 finally:
4311 del repo._subtoppath
4311 del repo._subtoppath
4312
4312
4313
4313
4314 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4314 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4315 norepo=True)
4315 norepo=True)
4316 def init(ui, dest=".", **opts):
4316 def init(ui, dest=".", **opts):
4317 """create a new repository in the given directory
4317 """create a new repository in the given directory
4318
4318
4319 Initialize a new repository in the given directory. If the given
4319 Initialize a new repository in the given directory. If the given
4320 directory does not exist, it will be created.
4320 directory does not exist, it will be created.
4321
4321
4322 If no directory is given, the current directory is used.
4322 If no directory is given, the current directory is used.
4323
4323
4324 It is possible to specify an ``ssh://`` URL as the destination.
4324 It is possible to specify an ``ssh://`` URL as the destination.
4325 See :hg:`help urls` for more information.
4325 See :hg:`help urls` for more information.
4326
4326
4327 Returns 0 on success.
4327 Returns 0 on success.
4328 """
4328 """
4329 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4329 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4330
4330
4331 @command('locate',
4331 @command('locate',
4332 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4332 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4333 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4333 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4334 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4334 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4335 ] + walkopts,
4335 ] + walkopts,
4336 _('[OPTION]... [PATTERN]...'))
4336 _('[OPTION]... [PATTERN]...'))
4337 def locate(ui, repo, *pats, **opts):
4337 def locate(ui, repo, *pats, **opts):
4338 """locate files matching specific patterns (DEPRECATED)
4338 """locate files matching specific patterns (DEPRECATED)
4339
4339
4340 Print files under Mercurial control in the working directory whose
4340 Print files under Mercurial control in the working directory whose
4341 names match the given patterns.
4341 names match the given patterns.
4342
4342
4343 By default, this command searches all directories in the working
4343 By default, this command searches all directories in the working
4344 directory. To search just the current directory and its
4344 directory. To search just the current directory and its
4345 subdirectories, use "--include .".
4345 subdirectories, use "--include .".
4346
4346
4347 If no patterns are given to match, this command prints the names
4347 If no patterns are given to match, this command prints the names
4348 of all files under Mercurial control in the working directory.
4348 of all files under Mercurial control in the working directory.
4349
4349
4350 If you want to feed the output of this command into the "xargs"
4350 If you want to feed the output of this command into the "xargs"
4351 command, use the -0 option to both this command and "xargs". This
4351 command, use the -0 option to both this command and "xargs". This
4352 will avoid the problem of "xargs" treating single filenames that
4352 will avoid the problem of "xargs" treating single filenames that
4353 contain whitespace as multiple filenames.
4353 contain whitespace as multiple filenames.
4354
4354
4355 See :hg:`help files` for a more versatile command.
4355 See :hg:`help files` for a more versatile command.
4356
4356
4357 Returns 0 if a match is found, 1 otherwise.
4357 Returns 0 if a match is found, 1 otherwise.
4358 """
4358 """
4359 if opts.get('print0'):
4359 if opts.get('print0'):
4360 end = '\0'
4360 end = '\0'
4361 else:
4361 else:
4362 end = '\n'
4362 end = '\n'
4363 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4363 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4364
4364
4365 ret = 1
4365 ret = 1
4366 ctx = repo[rev]
4366 ctx = repo[rev]
4367 m = scmutil.match(ctx, pats, opts, default='relglob')
4367 m = scmutil.match(ctx, pats, opts, default='relglob')
4368 m.bad = lambda x, y: False
4368 m.bad = lambda x, y: False
4369
4369
4370 for abs in ctx.matches(m):
4370 for abs in ctx.matches(m):
4371 if opts.get('fullpath'):
4371 if opts.get('fullpath'):
4372 ui.write(repo.wjoin(abs), end)
4372 ui.write(repo.wjoin(abs), end)
4373 else:
4373 else:
4374 ui.write(((pats and m.rel(abs)) or abs), end)
4374 ui.write(((pats and m.rel(abs)) or abs), end)
4375 ret = 0
4375 ret = 0
4376
4376
4377 return ret
4377 return ret
4378
4378
4379 @command('^log|history',
4379 @command('^log|history',
4380 [('f', 'follow', None,
4380 [('f', 'follow', None,
4381 _('follow changeset history, or file history across copies and renames')),
4381 _('follow changeset history, or file history across copies and renames')),
4382 ('', 'follow-first', None,
4382 ('', 'follow-first', None,
4383 _('only follow the first parent of merge changesets (DEPRECATED)')),
4383 _('only follow the first parent of merge changesets (DEPRECATED)')),
4384 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4384 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4385 ('C', 'copies', None, _('show copied files')),
4385 ('C', 'copies', None, _('show copied files')),
4386 ('k', 'keyword', [],
4386 ('k', 'keyword', [],
4387 _('do case-insensitive search for a given text'), _('TEXT')),
4387 _('do case-insensitive search for a given text'), _('TEXT')),
4388 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4388 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4389 ('', 'removed', None, _('include revisions where files were removed')),
4389 ('', 'removed', None, _('include revisions where files were removed')),
4390 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4390 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4391 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4391 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4392 ('', 'only-branch', [],
4392 ('', 'only-branch', [],
4393 _('show only changesets within the given named branch (DEPRECATED)'),
4393 _('show only changesets within the given named branch (DEPRECATED)'),
4394 _('BRANCH')),
4394 _('BRANCH')),
4395 ('b', 'branch', [],
4395 ('b', 'branch', [],
4396 _('show changesets within the given named branch'), _('BRANCH')),
4396 _('show changesets within the given named branch'), _('BRANCH')),
4397 ('P', 'prune', [],
4397 ('P', 'prune', [],
4398 _('do not display revision or any of its ancestors'), _('REV')),
4398 _('do not display revision or any of its ancestors'), _('REV')),
4399 ] + logopts + walkopts,
4399 ] + logopts + walkopts,
4400 _('[OPTION]... [FILE]'),
4400 _('[OPTION]... [FILE]'),
4401 inferrepo=True)
4401 inferrepo=True)
4402 def log(ui, repo, *pats, **opts):
4402 def log(ui, repo, *pats, **opts):
4403 """show revision history of entire repository or files
4403 """show revision history of entire repository or files
4404
4404
4405 Print the revision history of the specified files or the entire
4405 Print the revision history of the specified files or the entire
4406 project.
4406 project.
4407
4407
4408 If no revision range is specified, the default is ``tip:0`` unless
4408 If no revision range is specified, the default is ``tip:0`` unless
4409 --follow is set, in which case the working directory parent is
4409 --follow is set, in which case the working directory parent is
4410 used as the starting revision.
4410 used as the starting revision.
4411
4411
4412 File history is shown without following rename or copy history of
4412 File history is shown without following rename or copy history of
4413 files. Use -f/--follow with a filename to follow history across
4413 files. Use -f/--follow with a filename to follow history across
4414 renames and copies. --follow without a filename will only show
4414 renames and copies. --follow without a filename will only show
4415 ancestors or descendants of the starting revision.
4415 ancestors or descendants of the starting revision.
4416
4416
4417 By default this command prints revision number and changeset id,
4417 By default this command prints revision number and changeset id,
4418 tags, non-trivial parents, user, date and time, and a summary for
4418 tags, non-trivial parents, user, date and time, and a summary for
4419 each commit. When the -v/--verbose switch is used, the list of
4419 each commit. When the -v/--verbose switch is used, the list of
4420 changed files and full commit message are shown.
4420 changed files and full commit message are shown.
4421
4421
4422 With --graph the revisions are shown as an ASCII art DAG with the most
4422 With --graph the revisions are shown as an ASCII art DAG with the most
4423 recent changeset at the top.
4423 recent changeset at the top.
4424 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4424 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4425 and '+' represents a fork where the changeset from the lines below is a
4425 and '+' represents a fork where the changeset from the lines below is a
4426 parent of the 'o' merge on the same line.
4426 parent of the 'o' merge on the same line.
4427
4427
4428 .. note::
4428 .. note::
4429
4429
4430 log -p/--patch may generate unexpected diff output for merge
4430 log -p/--patch may generate unexpected diff output for merge
4431 changesets, as it will only compare the merge changeset against
4431 changesets, as it will only compare the merge changeset against
4432 its first parent. Also, only files different from BOTH parents
4432 its first parent. Also, only files different from BOTH parents
4433 will appear in files:.
4433 will appear in files:.
4434
4434
4435 .. note::
4435 .. note::
4436
4436
4437 for performance reasons, log FILE may omit duplicate changes
4437 for performance reasons, log FILE may omit duplicate changes
4438 made on branches and will not show removals or mode changes. To
4438 made on branches and will not show removals or mode changes. To
4439 see all such changes, use the --removed switch.
4439 see all such changes, use the --removed switch.
4440
4440
4441 .. container:: verbose
4441 .. container:: verbose
4442
4442
4443 Some examples:
4443 Some examples:
4444
4444
4445 - changesets with full descriptions and file lists::
4445 - changesets with full descriptions and file lists::
4446
4446
4447 hg log -v
4447 hg log -v
4448
4448
4449 - changesets ancestral to the working directory::
4449 - changesets ancestral to the working directory::
4450
4450
4451 hg log -f
4451 hg log -f
4452
4452
4453 - last 10 commits on the current branch::
4453 - last 10 commits on the current branch::
4454
4454
4455 hg log -l 10 -b .
4455 hg log -l 10 -b .
4456
4456
4457 - changesets showing all modifications of a file, including removals::
4457 - changesets showing all modifications of a file, including removals::
4458
4458
4459 hg log --removed file.c
4459 hg log --removed file.c
4460
4460
4461 - all changesets that touch a directory, with diffs, excluding merges::
4461 - all changesets that touch a directory, with diffs, excluding merges::
4462
4462
4463 hg log -Mp lib/
4463 hg log -Mp lib/
4464
4464
4465 - all revision numbers that match a keyword::
4465 - all revision numbers that match a keyword::
4466
4466
4467 hg log -k bug --template "{rev}\\n"
4467 hg log -k bug --template "{rev}\\n"
4468
4468
4469 - list available log templates::
4469 - list available log templates::
4470
4470
4471 hg log -T list
4471 hg log -T list
4472
4472
4473 - check if a given changeset is included in a tagged release::
4473 - check if a given changeset is included in a tagged release::
4474
4474
4475 hg log -r "a21ccf and ancestor(1.9)"
4475 hg log -r "a21ccf and ancestor(1.9)"
4476
4476
4477 - find all changesets by some user in a date range::
4477 - find all changesets by some user in a date range::
4478
4478
4479 hg log -k alice -d "may 2008 to jul 2008"
4479 hg log -k alice -d "may 2008 to jul 2008"
4480
4480
4481 - summary of all changesets after the last tag::
4481 - summary of all changesets after the last tag::
4482
4482
4483 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4483 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4484
4484
4485 See :hg:`help dates` for a list of formats valid for -d/--date.
4485 See :hg:`help dates` for a list of formats valid for -d/--date.
4486
4486
4487 See :hg:`help revisions` and :hg:`help revsets` for more about
4487 See :hg:`help revisions` and :hg:`help revsets` for more about
4488 specifying revisions.
4488 specifying revisions.
4489
4489
4490 See :hg:`help templates` for more about pre-packaged styles and
4490 See :hg:`help templates` for more about pre-packaged styles and
4491 specifying custom templates.
4491 specifying custom templates.
4492
4492
4493 Returns 0 on success.
4493 Returns 0 on success.
4494
4494
4495 """
4495 """
4496 if opts.get('follow') and opts.get('rev'):
4496 if opts.get('follow') and opts.get('rev'):
4497 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4497 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4498 del opts['follow']
4498 del opts['follow']
4499
4499
4500 if opts.get('graph'):
4500 if opts.get('graph'):
4501 return cmdutil.graphlog(ui, repo, *pats, **opts)
4501 return cmdutil.graphlog(ui, repo, *pats, **opts)
4502
4502
4503 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4503 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4504 limit = cmdutil.loglimit(opts)
4504 limit = cmdutil.loglimit(opts)
4505 count = 0
4505 count = 0
4506
4506
4507 getrenamed = None
4507 getrenamed = None
4508 if opts.get('copies'):
4508 if opts.get('copies'):
4509 endrev = None
4509 endrev = None
4510 if opts.get('rev'):
4510 if opts.get('rev'):
4511 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4511 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4512 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4512 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4513
4513
4514 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4514 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4515 for rev in revs:
4515 for rev in revs:
4516 if count == limit:
4516 if count == limit:
4517 break
4517 break
4518 ctx = repo[rev]
4518 ctx = repo[rev]
4519 copies = None
4519 copies = None
4520 if getrenamed is not None and rev:
4520 if getrenamed is not None and rev:
4521 copies = []
4521 copies = []
4522 for fn in ctx.files():
4522 for fn in ctx.files():
4523 rename = getrenamed(fn, rev)
4523 rename = getrenamed(fn, rev)
4524 if rename:
4524 if rename:
4525 copies.append((fn, rename[0]))
4525 copies.append((fn, rename[0]))
4526 if filematcher:
4526 if filematcher:
4527 revmatchfn = filematcher(ctx.rev())
4527 revmatchfn = filematcher(ctx.rev())
4528 else:
4528 else:
4529 revmatchfn = None
4529 revmatchfn = None
4530 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4530 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4531 if displayer.flush(rev):
4531 if displayer.flush(rev):
4532 count += 1
4532 count += 1
4533
4533
4534 displayer.close()
4534 displayer.close()
4535
4535
4536 @command('manifest',
4536 @command('manifest',
4537 [('r', 'rev', '', _('revision to display'), _('REV')),
4537 [('r', 'rev', '', _('revision to display'), _('REV')),
4538 ('', 'all', False, _("list files from all revisions"))]
4538 ('', 'all', False, _("list files from all revisions"))]
4539 + formatteropts,
4539 + formatteropts,
4540 _('[-r REV]'))
4540 _('[-r REV]'))
4541 def manifest(ui, repo, node=None, rev=None, **opts):
4541 def manifest(ui, repo, node=None, rev=None, **opts):
4542 """output the current or given revision of the project manifest
4542 """output the current or given revision of the project manifest
4543
4543
4544 Print a list of version controlled files for the given revision.
4544 Print a list of version controlled files for the given revision.
4545 If no revision is given, the first parent of the working directory
4545 If no revision is given, the first parent of the working directory
4546 is used, or the null revision if no revision is checked out.
4546 is used, or the null revision if no revision is checked out.
4547
4547
4548 With -v, print file permissions, symlink and executable bits.
4548 With -v, print file permissions, symlink and executable bits.
4549 With --debug, print file revision hashes.
4549 With --debug, print file revision hashes.
4550
4550
4551 If option --all is specified, the list of all files from all revisions
4551 If option --all is specified, the list of all files from all revisions
4552 is printed. This includes deleted and renamed files.
4552 is printed. This includes deleted and renamed files.
4553
4553
4554 Returns 0 on success.
4554 Returns 0 on success.
4555 """
4555 """
4556
4556
4557 fm = ui.formatter('manifest', opts)
4557 fm = ui.formatter('manifest', opts)
4558
4558
4559 if opts.get('all'):
4559 if opts.get('all'):
4560 if rev or node:
4560 if rev or node:
4561 raise util.Abort(_("can't specify a revision with --all"))
4561 raise util.Abort(_("can't specify a revision with --all"))
4562
4562
4563 res = []
4563 res = []
4564 prefix = "data/"
4564 prefix = "data/"
4565 suffix = ".i"
4565 suffix = ".i"
4566 plen = len(prefix)
4566 plen = len(prefix)
4567 slen = len(suffix)
4567 slen = len(suffix)
4568 lock = repo.lock()
4568 lock = repo.lock()
4569 try:
4569 try:
4570 for fn, b, size in repo.store.datafiles():
4570 for fn, b, size in repo.store.datafiles():
4571 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4571 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4572 res.append(fn[plen:-slen])
4572 res.append(fn[plen:-slen])
4573 finally:
4573 finally:
4574 lock.release()
4574 lock.release()
4575 for f in res:
4575 for f in res:
4576 fm.startitem()
4576 fm.startitem()
4577 fm.write("path", '%s\n', f)
4577 fm.write("path", '%s\n', f)
4578 fm.end()
4578 fm.end()
4579 return
4579 return
4580
4580
4581 if rev and node:
4581 if rev and node:
4582 raise util.Abort(_("please specify just one revision"))
4582 raise util.Abort(_("please specify just one revision"))
4583
4583
4584 if not node:
4584 if not node:
4585 node = rev
4585 node = rev
4586
4586
4587 char = {'l': '@', 'x': '*', '': ''}
4587 char = {'l': '@', 'x': '*', '': ''}
4588 mode = {'l': '644', 'x': '755', '': '644'}
4588 mode = {'l': '644', 'x': '755', '': '644'}
4589 ctx = scmutil.revsingle(repo, node)
4589 ctx = scmutil.revsingle(repo, node)
4590 mf = ctx.manifest()
4590 mf = ctx.manifest()
4591 for f in ctx:
4591 for f in ctx:
4592 fm.startitem()
4592 fm.startitem()
4593 fl = ctx[f].flags()
4593 fl = ctx[f].flags()
4594 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4594 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4595 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4595 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4596 fm.write('path', '%s\n', f)
4596 fm.write('path', '%s\n', f)
4597 fm.end()
4597 fm.end()
4598
4598
4599 @command('^merge',
4599 @command('^merge',
4600 [('f', 'force', None,
4600 [('f', 'force', None,
4601 _('force a merge including outstanding changes (DEPRECATED)')),
4601 _('force a merge including outstanding changes (DEPRECATED)')),
4602 ('r', 'rev', '', _('revision to merge'), _('REV')),
4602 ('r', 'rev', '', _('revision to merge'), _('REV')),
4603 ('P', 'preview', None,
4603 ('P', 'preview', None,
4604 _('review revisions to merge (no merge is performed)'))
4604 _('review revisions to merge (no merge is performed)'))
4605 ] + mergetoolopts,
4605 ] + mergetoolopts,
4606 _('[-P] [-f] [[-r] REV]'))
4606 _('[-P] [-f] [[-r] REV]'))
4607 def merge(ui, repo, node=None, **opts):
4607 def merge(ui, repo, node=None, **opts):
4608 """merge another revision into working directory
4608 """merge another revision into working directory
4609
4609
4610 The current working directory is updated with all changes made in
4610 The current working directory is updated with all changes made in
4611 the requested revision since the last common predecessor revision.
4611 the requested revision since the last common predecessor revision.
4612
4612
4613 Files that changed between either parent are marked as changed for
4613 Files that changed between either parent are marked as changed for
4614 the next commit and a commit must be performed before any further
4614 the next commit and a commit must be performed before any further
4615 updates to the repository are allowed. The next commit will have
4615 updates to the repository are allowed. The next commit will have
4616 two parents.
4616 two parents.
4617
4617
4618 ``--tool`` can be used to specify the merge tool used for file
4618 ``--tool`` can be used to specify the merge tool used for file
4619 merges. It overrides the HGMERGE environment variable and your
4619 merges. It overrides the HGMERGE environment variable and your
4620 configuration files. See :hg:`help merge-tools` for options.
4620 configuration files. See :hg:`help merge-tools` for options.
4621
4621
4622 If no revision is specified, the working directory's parent is a
4622 If no revision is specified, the working directory's parent is a
4623 head revision, and the current branch contains exactly one other
4623 head revision, and the current branch contains exactly one other
4624 head, the other head is merged with by default. Otherwise, an
4624 head, the other head is merged with by default. Otherwise, an
4625 explicit revision with which to merge with must be provided.
4625 explicit revision with which to merge with must be provided.
4626
4626
4627 :hg:`resolve` must be used to resolve unresolved files.
4627 :hg:`resolve` must be used to resolve unresolved files.
4628
4628
4629 To undo an uncommitted merge, use :hg:`update --clean .` which
4629 To undo an uncommitted merge, use :hg:`update --clean .` which
4630 will check out a clean copy of the original merge parent, losing
4630 will check out a clean copy of the original merge parent, losing
4631 all changes.
4631 all changes.
4632
4632
4633 Returns 0 on success, 1 if there are unresolved files.
4633 Returns 0 on success, 1 if there are unresolved files.
4634 """
4634 """
4635
4635
4636 if opts.get('rev') and node:
4636 if opts.get('rev') and node:
4637 raise util.Abort(_("please specify just one revision"))
4637 raise util.Abort(_("please specify just one revision"))
4638 if not node:
4638 if not node:
4639 node = opts.get('rev')
4639 node = opts.get('rev')
4640
4640
4641 if node:
4641 if node:
4642 node = scmutil.revsingle(repo, node).node()
4642 node = scmutil.revsingle(repo, node).node()
4643
4643
4644 if not node and repo._bookmarkcurrent:
4644 if not node and repo._bookmarkcurrent:
4645 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4645 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4646 curhead = repo[repo._bookmarkcurrent].node()
4646 curhead = repo[repo._bookmarkcurrent].node()
4647 if len(bmheads) == 2:
4647 if len(bmheads) == 2:
4648 if curhead == bmheads[0]:
4648 if curhead == bmheads[0]:
4649 node = bmheads[1]
4649 node = bmheads[1]
4650 else:
4650 else:
4651 node = bmheads[0]
4651 node = bmheads[0]
4652 elif len(bmheads) > 2:
4652 elif len(bmheads) > 2:
4653 raise util.Abort(_("multiple matching bookmarks to merge - "
4653 raise util.Abort(_("multiple matching bookmarks to merge - "
4654 "please merge with an explicit rev or bookmark"),
4654 "please merge with an explicit rev or bookmark"),
4655 hint=_("run 'hg heads' to see all heads"))
4655 hint=_("run 'hg heads' to see all heads"))
4656 elif len(bmheads) <= 1:
4656 elif len(bmheads) <= 1:
4657 raise util.Abort(_("no matching bookmark to merge - "
4657 raise util.Abort(_("no matching bookmark to merge - "
4658 "please merge with an explicit rev or bookmark"),
4658 "please merge with an explicit rev or bookmark"),
4659 hint=_("run 'hg heads' to see all heads"))
4659 hint=_("run 'hg heads' to see all heads"))
4660
4660
4661 if not node and not repo._bookmarkcurrent:
4661 if not node and not repo._bookmarkcurrent:
4662 branch = repo[None].branch()
4662 branch = repo[None].branch()
4663 bheads = repo.branchheads(branch)
4663 bheads = repo.branchheads(branch)
4664 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4664 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4665
4665
4666 if len(nbhs) > 2:
4666 if len(nbhs) > 2:
4667 raise util.Abort(_("branch '%s' has %d heads - "
4667 raise util.Abort(_("branch '%s' has %d heads - "
4668 "please merge with an explicit rev")
4668 "please merge with an explicit rev")
4669 % (branch, len(bheads)),
4669 % (branch, len(bheads)),
4670 hint=_("run 'hg heads .' to see heads"))
4670 hint=_("run 'hg heads .' to see heads"))
4671
4671
4672 parent = repo.dirstate.p1()
4672 parent = repo.dirstate.p1()
4673 if len(nbhs) <= 1:
4673 if len(nbhs) <= 1:
4674 if len(bheads) > 1:
4674 if len(bheads) > 1:
4675 raise util.Abort(_("heads are bookmarked - "
4675 raise util.Abort(_("heads are bookmarked - "
4676 "please merge with an explicit rev"),
4676 "please merge with an explicit rev"),
4677 hint=_("run 'hg heads' to see all heads"))
4677 hint=_("run 'hg heads' to see all heads"))
4678 if len(repo.heads()) > 1:
4678 if len(repo.heads()) > 1:
4679 raise util.Abort(_("branch '%s' has one head - "
4679 raise util.Abort(_("branch '%s' has one head - "
4680 "please merge with an explicit rev")
4680 "please merge with an explicit rev")
4681 % branch,
4681 % branch,
4682 hint=_("run 'hg heads' to see all heads"))
4682 hint=_("run 'hg heads' to see all heads"))
4683 msg, hint = _('nothing to merge'), None
4683 msg, hint = _('nothing to merge'), None
4684 if parent != repo.lookup(branch):
4684 if parent != repo.lookup(branch):
4685 hint = _("use 'hg update' instead")
4685 hint = _("use 'hg update' instead")
4686 raise util.Abort(msg, hint=hint)
4686 raise util.Abort(msg, hint=hint)
4687
4687
4688 if parent not in bheads:
4688 if parent not in bheads:
4689 raise util.Abort(_('working directory not at a head revision'),
4689 raise util.Abort(_('working directory not at a head revision'),
4690 hint=_("use 'hg update' or merge with an "
4690 hint=_("use 'hg update' or merge with an "
4691 "explicit revision"))
4691 "explicit revision"))
4692 if parent == nbhs[0]:
4692 if parent == nbhs[0]:
4693 node = nbhs[-1]
4693 node = nbhs[-1]
4694 else:
4694 else:
4695 node = nbhs[0]
4695 node = nbhs[0]
4696
4696
4697 if opts.get('preview'):
4697 if opts.get('preview'):
4698 # find nodes that are ancestors of p2 but not of p1
4698 # find nodes that are ancestors of p2 but not of p1
4699 p1 = repo.lookup('.')
4699 p1 = repo.lookup('.')
4700 p2 = repo.lookup(node)
4700 p2 = repo.lookup(node)
4701 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4701 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4702
4702
4703 displayer = cmdutil.show_changeset(ui, repo, opts)
4703 displayer = cmdutil.show_changeset(ui, repo, opts)
4704 for node in nodes:
4704 for node in nodes:
4705 displayer.show(repo[node])
4705 displayer.show(repo[node])
4706 displayer.close()
4706 displayer.close()
4707 return 0
4707 return 0
4708
4708
4709 try:
4709 try:
4710 # ui.forcemerge is an internal variable, do not document
4710 # ui.forcemerge is an internal variable, do not document
4711 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4711 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4712 return hg.merge(repo, node, force=opts.get('force'))
4712 return hg.merge(repo, node, force=opts.get('force'))
4713 finally:
4713 finally:
4714 ui.setconfig('ui', 'forcemerge', '', 'merge')
4714 ui.setconfig('ui', 'forcemerge', '', 'merge')
4715
4715
4716 @command('outgoing|out',
4716 @command('outgoing|out',
4717 [('f', 'force', None, _('run even when the destination is unrelated')),
4717 [('f', 'force', None, _('run even when the destination is unrelated')),
4718 ('r', 'rev', [],
4718 ('r', 'rev', [],
4719 _('a changeset intended to be included in the destination'), _('REV')),
4719 _('a changeset intended to be included in the destination'), _('REV')),
4720 ('n', 'newest-first', None, _('show newest record first')),
4720 ('n', 'newest-first', None, _('show newest record first')),
4721 ('B', 'bookmarks', False, _('compare bookmarks')),
4721 ('B', 'bookmarks', False, _('compare bookmarks')),
4722 ('b', 'branch', [], _('a specific branch you would like to push'),
4722 ('b', 'branch', [], _('a specific branch you would like to push'),
4723 _('BRANCH')),
4723 _('BRANCH')),
4724 ] + logopts + remoteopts + subrepoopts,
4724 ] + logopts + remoteopts + subrepoopts,
4725 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4725 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4726 def outgoing(ui, repo, dest=None, **opts):
4726 def outgoing(ui, repo, dest=None, **opts):
4727 """show changesets not found in the destination
4727 """show changesets not found in the destination
4728
4728
4729 Show changesets not found in the specified destination repository
4729 Show changesets not found in the specified destination repository
4730 or the default push location. These are the changesets that would
4730 or the default push location. These are the changesets that would
4731 be pushed if a push was requested.
4731 be pushed if a push was requested.
4732
4732
4733 See pull for details of valid destination formats.
4733 See pull for details of valid destination formats.
4734
4734
4735 Returns 0 if there are outgoing changes, 1 otherwise.
4735 Returns 0 if there are outgoing changes, 1 otherwise.
4736 """
4736 """
4737 if opts.get('graph'):
4737 if opts.get('graph'):
4738 cmdutil.checkunsupportedgraphflags([], opts)
4738 cmdutil.checkunsupportedgraphflags([], opts)
4739 o, other = hg._outgoing(ui, repo, dest, opts)
4739 o, other = hg._outgoing(ui, repo, dest, opts)
4740 if not o:
4740 if not o:
4741 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4741 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4742 return
4742 return
4743
4743
4744 revdag = cmdutil.graphrevs(repo, o, opts)
4744 revdag = cmdutil.graphrevs(repo, o, opts)
4745 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4745 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4746 showparents = [ctx.node() for ctx in repo[None].parents()]
4746 showparents = [ctx.node() for ctx in repo[None].parents()]
4747 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4747 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4748 graphmod.asciiedges)
4748 graphmod.asciiedges)
4749 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4749 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4750 return 0
4750 return 0
4751
4751
4752 if opts.get('bookmarks'):
4752 if opts.get('bookmarks'):
4753 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4753 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4754 dest, branches = hg.parseurl(dest, opts.get('branch'))
4754 dest, branches = hg.parseurl(dest, opts.get('branch'))
4755 other = hg.peer(repo, opts, dest)
4755 other = hg.peer(repo, opts, dest)
4756 if 'bookmarks' not in other.listkeys('namespaces'):
4756 if 'bookmarks' not in other.listkeys('namespaces'):
4757 ui.warn(_("remote doesn't support bookmarks\n"))
4757 ui.warn(_("remote doesn't support bookmarks\n"))
4758 return 0
4758 return 0
4759 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4759 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4760 return bookmarks.diff(ui, other, repo)
4760 return bookmarks.diff(ui, other, repo)
4761
4761
4762 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4762 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4763 try:
4763 try:
4764 return hg.outgoing(ui, repo, dest, opts)
4764 return hg.outgoing(ui, repo, dest, opts)
4765 finally:
4765 finally:
4766 del repo._subtoppath
4766 del repo._subtoppath
4767
4767
4768 @command('parents',
4768 @command('parents',
4769 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4769 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4770 ] + templateopts,
4770 ] + templateopts,
4771 _('[-r REV] [FILE]'),
4771 _('[-r REV] [FILE]'),
4772 inferrepo=True)
4772 inferrepo=True)
4773 def parents(ui, repo, file_=None, **opts):
4773 def parents(ui, repo, file_=None, **opts):
4774 """show the parents of the working directory or revision (DEPRECATED)
4774 """show the parents of the working directory or revision (DEPRECATED)
4775
4775
4776 Print the working directory's parent revisions. If a revision is
4776 Print the working directory's parent revisions. If a revision is
4777 given via -r/--rev, the parent of that revision will be printed.
4777 given via -r/--rev, the parent of that revision will be printed.
4778 If a file argument is given, the revision in which the file was
4778 If a file argument is given, the revision in which the file was
4779 last changed (before the working directory revision or the
4779 last changed (before the working directory revision or the
4780 argument to --rev if given) is printed.
4780 argument to --rev if given) is printed.
4781
4781
4782 See :hg:`summary` and :hg:`help revsets` for related information.
4782 See :hg:`summary` and :hg:`help revsets` for related information.
4783
4783
4784 Returns 0 on success.
4784 Returns 0 on success.
4785 """
4785 """
4786
4786
4787 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4787 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4788
4788
4789 if file_:
4789 if file_:
4790 m = scmutil.match(ctx, (file_,), opts)
4790 m = scmutil.match(ctx, (file_,), opts)
4791 if m.anypats() or len(m.files()) != 1:
4791 if m.anypats() or len(m.files()) != 1:
4792 raise util.Abort(_('can only specify an explicit filename'))
4792 raise util.Abort(_('can only specify an explicit filename'))
4793 file_ = m.files()[0]
4793 file_ = m.files()[0]
4794 filenodes = []
4794 filenodes = []
4795 for cp in ctx.parents():
4795 for cp in ctx.parents():
4796 if not cp:
4796 if not cp:
4797 continue
4797 continue
4798 try:
4798 try:
4799 filenodes.append(cp.filenode(file_))
4799 filenodes.append(cp.filenode(file_))
4800 except error.LookupError:
4800 except error.LookupError:
4801 pass
4801 pass
4802 if not filenodes:
4802 if not filenodes:
4803 raise util.Abort(_("'%s' not found in manifest!") % file_)
4803 raise util.Abort(_("'%s' not found in manifest!") % file_)
4804 p = []
4804 p = []
4805 for fn in filenodes:
4805 for fn in filenodes:
4806 fctx = repo.filectx(file_, fileid=fn)
4806 fctx = repo.filectx(file_, fileid=fn)
4807 p.append(fctx.node())
4807 p.append(fctx.node())
4808 else:
4808 else:
4809 p = [cp.node() for cp in ctx.parents()]
4809 p = [cp.node() for cp in ctx.parents()]
4810
4810
4811 displayer = cmdutil.show_changeset(ui, repo, opts)
4811 displayer = cmdutil.show_changeset(ui, repo, opts)
4812 for n in p:
4812 for n in p:
4813 if n != nullid:
4813 if n != nullid:
4814 displayer.show(repo[n])
4814 displayer.show(repo[n])
4815 displayer.close()
4815 displayer.close()
4816
4816
4817 @command('paths', [], _('[NAME]'), optionalrepo=True)
4817 @command('paths', [], _('[NAME]'), optionalrepo=True)
4818 def paths(ui, repo, search=None):
4818 def paths(ui, repo, search=None):
4819 """show aliases for remote repositories
4819 """show aliases for remote repositories
4820
4820
4821 Show definition of symbolic path name NAME. If no name is given,
4821 Show definition of symbolic path name NAME. If no name is given,
4822 show definition of all available names.
4822 show definition of all available names.
4823
4823
4824 Option -q/--quiet suppresses all output when searching for NAME
4824 Option -q/--quiet suppresses all output when searching for NAME
4825 and shows only the path names when listing all definitions.
4825 and shows only the path names when listing all definitions.
4826
4826
4827 Path names are defined in the [paths] section of your
4827 Path names are defined in the [paths] section of your
4828 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4828 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4829 repository, ``.hg/hgrc`` is used, too.
4829 repository, ``.hg/hgrc`` is used, too.
4830
4830
4831 The path names ``default`` and ``default-push`` have a special
4831 The path names ``default`` and ``default-push`` have a special
4832 meaning. When performing a push or pull operation, they are used
4832 meaning. When performing a push or pull operation, they are used
4833 as fallbacks if no location is specified on the command-line.
4833 as fallbacks if no location is specified on the command-line.
4834 When ``default-push`` is set, it will be used for push and
4834 When ``default-push`` is set, it will be used for push and
4835 ``default`` will be used for pull; otherwise ``default`` is used
4835 ``default`` will be used for pull; otherwise ``default`` is used
4836 as the fallback for both. When cloning a repository, the clone
4836 as the fallback for both. When cloning a repository, the clone
4837 source is written as ``default`` in ``.hg/hgrc``. Note that
4837 source is written as ``default`` in ``.hg/hgrc``. Note that
4838 ``default`` and ``default-push`` apply to all inbound (e.g.
4838 ``default`` and ``default-push`` apply to all inbound (e.g.
4839 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4839 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4840 :hg:`bundle`) operations.
4840 :hg:`bundle`) operations.
4841
4841
4842 See :hg:`help urls` for more information.
4842 See :hg:`help urls` for more information.
4843
4843
4844 Returns 0 on success.
4844 Returns 0 on success.
4845 """
4845 """
4846 if search:
4846 if search:
4847 for name, path in sorted(ui.paths.iteritems()):
4847 for name, path in sorted(ui.paths.iteritems()):
4848 if name == search:
4848 if name == search:
4849 ui.status("%s\n" % util.hidepassword(path.loc))
4849 ui.status("%s\n" % util.hidepassword(path.loc))
4850 return
4850 return
4851 if not ui.quiet:
4851 if not ui.quiet:
4852 ui.warn(_("not found!\n"))
4852 ui.warn(_("not found!\n"))
4853 return 1
4853 return 1
4854 else:
4854 else:
4855 for name, path in sorted(ui.paths.iteritems()):
4855 for name, path in sorted(ui.paths.iteritems()):
4856 if ui.quiet:
4856 if ui.quiet:
4857 ui.write("%s\n" % name)
4857 ui.write("%s\n" % name)
4858 else:
4858 else:
4859 ui.write("%s = %s\n" % (name,
4859 ui.write("%s = %s\n" % (name,
4860 util.hidepassword(path.loc)))
4860 util.hidepassword(path.loc)))
4861
4861
4862 @command('phase',
4862 @command('phase',
4863 [('p', 'public', False, _('set changeset phase to public')),
4863 [('p', 'public', False, _('set changeset phase to public')),
4864 ('d', 'draft', False, _('set changeset phase to draft')),
4864 ('d', 'draft', False, _('set changeset phase to draft')),
4865 ('s', 'secret', False, _('set changeset phase to secret')),
4865 ('s', 'secret', False, _('set changeset phase to secret')),
4866 ('f', 'force', False, _('allow to move boundary backward')),
4866 ('f', 'force', False, _('allow to move boundary backward')),
4867 ('r', 'rev', [], _('target revision'), _('REV')),
4867 ('r', 'rev', [], _('target revision'), _('REV')),
4868 ],
4868 ],
4869 _('[-p|-d|-s] [-f] [-r] REV...'))
4869 _('[-p|-d|-s] [-f] [-r] REV...'))
4870 def phase(ui, repo, *revs, **opts):
4870 def phase(ui, repo, *revs, **opts):
4871 """set or show the current phase name
4871 """set or show the current phase name
4872
4872
4873 With no argument, show the phase name of specified revisions.
4873 With no argument, show the phase name of specified revisions.
4874
4874
4875 With one of -p/--public, -d/--draft or -s/--secret, change the
4875 With one of -p/--public, -d/--draft or -s/--secret, change the
4876 phase value of the specified revisions.
4876 phase value of the specified revisions.
4877
4877
4878 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4878 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4879 lower phase to an higher phase. Phases are ordered as follows::
4879 lower phase to an higher phase. Phases are ordered as follows::
4880
4880
4881 public < draft < secret
4881 public < draft < secret
4882
4882
4883 Returns 0 on success, 1 if no phases were changed or some could not
4883 Returns 0 on success, 1 if no phases were changed or some could not
4884 be changed.
4884 be changed.
4885 """
4885 """
4886 # search for a unique phase argument
4886 # search for a unique phase argument
4887 targetphase = None
4887 targetphase = None
4888 for idx, name in enumerate(phases.phasenames):
4888 for idx, name in enumerate(phases.phasenames):
4889 if opts[name]:
4889 if opts[name]:
4890 if targetphase is not None:
4890 if targetphase is not None:
4891 raise util.Abort(_('only one phase can be specified'))
4891 raise util.Abort(_('only one phase can be specified'))
4892 targetphase = idx
4892 targetphase = idx
4893
4893
4894 # look for specified revision
4894 # look for specified revision
4895 revs = list(revs)
4895 revs = list(revs)
4896 revs.extend(opts['rev'])
4896 revs.extend(opts['rev'])
4897 if not revs:
4897 if not revs:
4898 raise util.Abort(_('no revisions specified'))
4898 raise util.Abort(_('no revisions specified'))
4899
4899
4900 revs = scmutil.revrange(repo, revs)
4900 revs = scmutil.revrange(repo, revs)
4901
4901
4902 lock = None
4902 lock = None
4903 ret = 0
4903 ret = 0
4904 if targetphase is None:
4904 if targetphase is None:
4905 # display
4905 # display
4906 for r in revs:
4906 for r in revs:
4907 ctx = repo[r]
4907 ctx = repo[r]
4908 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4908 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4909 else:
4909 else:
4910 tr = None
4910 tr = None
4911 lock = repo.lock()
4911 lock = repo.lock()
4912 try:
4912 try:
4913 tr = repo.transaction("phase")
4913 tr = repo.transaction("phase")
4914 # set phase
4914 # set phase
4915 if not revs:
4915 if not revs:
4916 raise util.Abort(_('empty revision set'))
4916 raise util.Abort(_('empty revision set'))
4917 nodes = [repo[r].node() for r in revs]
4917 nodes = [repo[r].node() for r in revs]
4918 # moving revision from public to draft may hide them
4918 # moving revision from public to draft may hide them
4919 # We have to check result on an unfiltered repository
4919 # We have to check result on an unfiltered repository
4920 unfi = repo.unfiltered()
4920 unfi = repo.unfiltered()
4921 getphase = unfi._phasecache.phase
4921 getphase = unfi._phasecache.phase
4922 olddata = [getphase(unfi, r) for r in unfi]
4922 olddata = [getphase(unfi, r) for r in unfi]
4923 phases.advanceboundary(repo, tr, targetphase, nodes)
4923 phases.advanceboundary(repo, tr, targetphase, nodes)
4924 if opts['force']:
4924 if opts['force']:
4925 phases.retractboundary(repo, tr, targetphase, nodes)
4925 phases.retractboundary(repo, tr, targetphase, nodes)
4926 tr.close()
4926 tr.close()
4927 finally:
4927 finally:
4928 if tr is not None:
4928 if tr is not None:
4929 tr.release()
4929 tr.release()
4930 lock.release()
4930 lock.release()
4931 getphase = unfi._phasecache.phase
4931 getphase = unfi._phasecache.phase
4932 newdata = [getphase(unfi, r) for r in unfi]
4932 newdata = [getphase(unfi, r) for r in unfi]
4933 changes = sum(newdata[r] != olddata[r] for r in unfi)
4933 changes = sum(newdata[r] != olddata[r] for r in unfi)
4934 cl = unfi.changelog
4934 cl = unfi.changelog
4935 rejected = [n for n in nodes
4935 rejected = [n for n in nodes
4936 if newdata[cl.rev(n)] < targetphase]
4936 if newdata[cl.rev(n)] < targetphase]
4937 if rejected:
4937 if rejected:
4938 ui.warn(_('cannot move %i changesets to a higher '
4938 ui.warn(_('cannot move %i changesets to a higher '
4939 'phase, use --force\n') % len(rejected))
4939 'phase, use --force\n') % len(rejected))
4940 ret = 1
4940 ret = 1
4941 if changes:
4941 if changes:
4942 msg = _('phase changed for %i changesets\n') % changes
4942 msg = _('phase changed for %i changesets\n') % changes
4943 if ret:
4943 if ret:
4944 ui.status(msg)
4944 ui.status(msg)
4945 else:
4945 else:
4946 ui.note(msg)
4946 ui.note(msg)
4947 else:
4947 else:
4948 ui.warn(_('no phases changed\n'))
4948 ui.warn(_('no phases changed\n'))
4949 ret = 1
4949 ret = 1
4950 return ret
4950 return ret
4951
4951
4952 def postincoming(ui, repo, modheads, optupdate, checkout):
4952 def postincoming(ui, repo, modheads, optupdate, checkout):
4953 if modheads == 0:
4953 if modheads == 0:
4954 return
4954 return
4955 if optupdate:
4955 if optupdate:
4956 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4956 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4957 try:
4957 try:
4958 ret = hg.update(repo, checkout)
4958 ret = hg.update(repo, checkout)
4959 except util.Abort, inst:
4959 except util.Abort, inst:
4960 ui.warn(_("not updating: %s\n") % str(inst))
4960 ui.warn(_("not updating: %s\n") % str(inst))
4961 if inst.hint:
4961 if inst.hint:
4962 ui.warn(_("(%s)\n") % inst.hint)
4962 ui.warn(_("(%s)\n") % inst.hint)
4963 return 0
4963 return 0
4964 if not ret and not checkout:
4964 if not ret and not checkout:
4965 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4965 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4966 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4966 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4967 return ret
4967 return ret
4968 if modheads > 1:
4968 if modheads > 1:
4969 currentbranchheads = len(repo.branchheads())
4969 currentbranchheads = len(repo.branchheads())
4970 if currentbranchheads == modheads:
4970 if currentbranchheads == modheads:
4971 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4971 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4972 elif currentbranchheads > 1:
4972 elif currentbranchheads > 1:
4973 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4973 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4974 "merge)\n"))
4974 "merge)\n"))
4975 else:
4975 else:
4976 ui.status(_("(run 'hg heads' to see heads)\n"))
4976 ui.status(_("(run 'hg heads' to see heads)\n"))
4977 else:
4977 else:
4978 ui.status(_("(run 'hg update' to get a working copy)\n"))
4978 ui.status(_("(run 'hg update' to get a working copy)\n"))
4979
4979
4980 @command('^pull',
4980 @command('^pull',
4981 [('u', 'update', None,
4981 [('u', 'update', None,
4982 _('update to new branch head if changesets were pulled')),
4982 _('update to new branch head if changesets were pulled')),
4983 ('f', 'force', None, _('run even when remote repository is unrelated')),
4983 ('f', 'force', None, _('run even when remote repository is unrelated')),
4984 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4984 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4985 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4985 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4986 ('b', 'branch', [], _('a specific branch you would like to pull'),
4986 ('b', 'branch', [], _('a specific branch you would like to pull'),
4987 _('BRANCH')),
4987 _('BRANCH')),
4988 ] + remoteopts,
4988 ] + remoteopts,
4989 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4989 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4990 def pull(ui, repo, source="default", **opts):
4990 def pull(ui, repo, source="default", **opts):
4991 """pull changes from the specified source
4991 """pull changes from the specified source
4992
4992
4993 Pull changes from a remote repository to a local one.
4993 Pull changes from a remote repository to a local one.
4994
4994
4995 This finds all changes from the repository at the specified path
4995 This finds all changes from the repository at the specified path
4996 or URL and adds them to a local repository (the current one unless
4996 or URL and adds them to a local repository (the current one unless
4997 -R is specified). By default, this does not update the copy of the
4997 -R is specified). By default, this does not update the copy of the
4998 project in the working directory.
4998 project in the working directory.
4999
4999
5000 Use :hg:`incoming` if you want to see what would have been added
5000 Use :hg:`incoming` if you want to see what would have been added
5001 by a pull at the time you issued this command. If you then decide
5001 by a pull at the time you issued this command. If you then decide
5002 to add those changes to the repository, you should use :hg:`pull
5002 to add those changes to the repository, you should use :hg:`pull
5003 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5003 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5004
5004
5005 If SOURCE is omitted, the 'default' path will be used.
5005 If SOURCE is omitted, the 'default' path will be used.
5006 See :hg:`help urls` for more information.
5006 See :hg:`help urls` for more information.
5007
5007
5008 Returns 0 on success, 1 if an update had unresolved files.
5008 Returns 0 on success, 1 if an update had unresolved files.
5009 """
5009 """
5010 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5010 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5011 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5011 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5012 other = hg.peer(repo, opts, source)
5012 other = hg.peer(repo, opts, source)
5013 try:
5013 try:
5014 revs, checkout = hg.addbranchrevs(repo, other, branches,
5014 revs, checkout = hg.addbranchrevs(repo, other, branches,
5015 opts.get('rev'))
5015 opts.get('rev'))
5016
5016
5017 remotebookmarks = other.listkeys('bookmarks')
5017 remotebookmarks = other.listkeys('bookmarks')
5018
5018
5019 if opts.get('bookmark'):
5019 if opts.get('bookmark'):
5020 if not revs:
5020 if not revs:
5021 revs = []
5021 revs = []
5022 for b in opts['bookmark']:
5022 for b in opts['bookmark']:
5023 if b not in remotebookmarks:
5023 if b not in remotebookmarks:
5024 raise util.Abort(_('remote bookmark %s not found!') % b)
5024 raise util.Abort(_('remote bookmark %s not found!') % b)
5025 revs.append(remotebookmarks[b])
5025 revs.append(remotebookmarks[b])
5026
5026
5027 if revs:
5027 if revs:
5028 try:
5028 try:
5029 revs = [other.lookup(rev) for rev in revs]
5029 revs = [other.lookup(rev) for rev in revs]
5030 except error.CapabilityError:
5030 except error.CapabilityError:
5031 err = _("other repository doesn't support revision lookup, "
5031 err = _("other repository doesn't support revision lookup, "
5032 "so a rev cannot be specified.")
5032 "so a rev cannot be specified.")
5033 raise util.Abort(err)
5033 raise util.Abort(err)
5034
5034
5035 modheads = exchange.pull(repo, other, heads=revs,
5035 modheads = exchange.pull(repo, other, heads=revs,
5036 force=opts.get('force'),
5036 force=opts.get('force'),
5037 bookmarks=opts.get('bookmark', ())).cgresult
5037 bookmarks=opts.get('bookmark', ())).cgresult
5038 if checkout:
5038 if checkout:
5039 checkout = str(repo.changelog.rev(other.lookup(checkout)))
5039 checkout = str(repo.changelog.rev(other.lookup(checkout)))
5040 repo._subtoppath = source
5040 repo._subtoppath = source
5041 try:
5041 try:
5042 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5042 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5043
5043
5044 finally:
5044 finally:
5045 del repo._subtoppath
5045 del repo._subtoppath
5046
5046
5047 finally:
5047 finally:
5048 other.close()
5048 other.close()
5049 return ret
5049 return ret
5050
5050
5051 @command('^push',
5051 @command('^push',
5052 [('f', 'force', None, _('force push')),
5052 [('f', 'force', None, _('force push')),
5053 ('r', 'rev', [],
5053 ('r', 'rev', [],
5054 _('a changeset intended to be included in the destination'),
5054 _('a changeset intended to be included in the destination'),
5055 _('REV')),
5055 _('REV')),
5056 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5056 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5057 ('b', 'branch', [],
5057 ('b', 'branch', [],
5058 _('a specific branch you would like to push'), _('BRANCH')),
5058 _('a specific branch you would like to push'), _('BRANCH')),
5059 ('', 'new-branch', False, _('allow pushing a new branch')),
5059 ('', 'new-branch', False, _('allow pushing a new branch')),
5060 ] + remoteopts,
5060 ] + remoteopts,
5061 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5061 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5062 def push(ui, repo, dest=None, **opts):
5062 def push(ui, repo, dest=None, **opts):
5063 """push changes to the specified destination
5063 """push changes to the specified destination
5064
5064
5065 Push changesets from the local repository to the specified
5065 Push changesets from the local repository to the specified
5066 destination.
5066 destination.
5067
5067
5068 This operation is symmetrical to pull: it is identical to a pull
5068 This operation is symmetrical to pull: it is identical to a pull
5069 in the destination repository from the current one.
5069 in the destination repository from the current one.
5070
5070
5071 By default, push will not allow creation of new heads at the
5071 By default, push will not allow creation of new heads at the
5072 destination, since multiple heads would make it unclear which head
5072 destination, since multiple heads would make it unclear which head
5073 to use. In this situation, it is recommended to pull and merge
5073 to use. In this situation, it is recommended to pull and merge
5074 before pushing.
5074 before pushing.
5075
5075
5076 Use --new-branch if you want to allow push to create a new named
5076 Use --new-branch if you want to allow push to create a new named
5077 branch that is not present at the destination. This allows you to
5077 branch that is not present at the destination. This allows you to
5078 only create a new branch without forcing other changes.
5078 only create a new branch without forcing other changes.
5079
5079
5080 .. note::
5080 .. note::
5081
5081
5082 Extra care should be taken with the -f/--force option,
5082 Extra care should be taken with the -f/--force option,
5083 which will push all new heads on all branches, an action which will
5083 which will push all new heads on all branches, an action which will
5084 almost always cause confusion for collaborators.
5084 almost always cause confusion for collaborators.
5085
5085
5086 If -r/--rev is used, the specified revision and all its ancestors
5086 If -r/--rev is used, the specified revision and all its ancestors
5087 will be pushed to the remote repository.
5087 will be pushed to the remote repository.
5088
5088
5089 If -B/--bookmark is used, the specified bookmarked revision, its
5089 If -B/--bookmark is used, the specified bookmarked revision, its
5090 ancestors, and the bookmark will be pushed to the remote
5090 ancestors, and the bookmark will be pushed to the remote
5091 repository.
5091 repository.
5092
5092
5093 Please see :hg:`help urls` for important details about ``ssh://``
5093 Please see :hg:`help urls` for important details about ``ssh://``
5094 URLs. If DESTINATION is omitted, a default path will be used.
5094 URLs. If DESTINATION is omitted, a default path will be used.
5095
5095
5096 Returns 0 if push was successful, 1 if nothing to push.
5096 Returns 0 if push was successful, 1 if nothing to push.
5097 """
5097 """
5098
5098
5099 if opts.get('bookmark'):
5099 if opts.get('bookmark'):
5100 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5100 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5101 for b in opts['bookmark']:
5101 for b in opts['bookmark']:
5102 # translate -B options to -r so changesets get pushed
5102 # translate -B options to -r so changesets get pushed
5103 if b in repo._bookmarks:
5103 if b in repo._bookmarks:
5104 opts.setdefault('rev', []).append(b)
5104 opts.setdefault('rev', []).append(b)
5105 else:
5105 else:
5106 # if we try to push a deleted bookmark, translate it to null
5106 # if we try to push a deleted bookmark, translate it to null
5107 # this lets simultaneous -r, -b options continue working
5107 # this lets simultaneous -r, -b options continue working
5108 opts.setdefault('rev', []).append("null")
5108 opts.setdefault('rev', []).append("null")
5109
5109
5110 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5110 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5111 dest, branches = hg.parseurl(dest, opts.get('branch'))
5111 dest, branches = hg.parseurl(dest, opts.get('branch'))
5112 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5112 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5113 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5113 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5114 try:
5114 try:
5115 other = hg.peer(repo, opts, dest)
5115 other = hg.peer(repo, opts, dest)
5116 except error.RepoError:
5116 except error.RepoError:
5117 if dest == "default-push":
5117 if dest == "default-push":
5118 raise util.Abort(_("default repository not configured!"),
5118 raise util.Abort(_("default repository not configured!"),
5119 hint=_('see the "path" section in "hg help config"'))
5119 hint=_('see the "path" section in "hg help config"'))
5120 else:
5120 else:
5121 raise
5121 raise
5122
5122
5123 if revs:
5123 if revs:
5124 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5124 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5125
5125
5126 repo._subtoppath = dest
5126 repo._subtoppath = dest
5127 try:
5127 try:
5128 # push subrepos depth-first for coherent ordering
5128 # push subrepos depth-first for coherent ordering
5129 c = repo['']
5129 c = repo['']
5130 subs = c.substate # only repos that are committed
5130 subs = c.substate # only repos that are committed
5131 for s in sorted(subs):
5131 for s in sorted(subs):
5132 result = c.sub(s).push(opts)
5132 result = c.sub(s).push(opts)
5133 if result == 0:
5133 if result == 0:
5134 return not result
5134 return not result
5135 finally:
5135 finally:
5136 del repo._subtoppath
5136 del repo._subtoppath
5137 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5137 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5138 newbranch=opts.get('new_branch'),
5138 newbranch=opts.get('new_branch'),
5139 bookmarks=opts.get('bookmark', ()))
5139 bookmarks=opts.get('bookmark', ()))
5140
5140
5141 result = not pushop.cgresult
5141 result = not pushop.cgresult
5142
5142
5143 if pushop.bkresult is not None:
5143 if pushop.bkresult is not None:
5144 if pushop.bkresult == 2:
5144 if pushop.bkresult == 2:
5145 result = 2
5145 result = 2
5146 elif not result and pushop.bkresult:
5146 elif not result and pushop.bkresult:
5147 result = 2
5147 result = 2
5148
5148
5149 return result
5149 return result
5150
5150
5151 @command('recover', [])
5151 @command('recover', [])
5152 def recover(ui, repo):
5152 def recover(ui, repo):
5153 """roll back an interrupted transaction
5153 """roll back an interrupted transaction
5154
5154
5155 Recover from an interrupted commit or pull.
5155 Recover from an interrupted commit or pull.
5156
5156
5157 This command tries to fix the repository status after an
5157 This command tries to fix the repository status after an
5158 interrupted operation. It should only be necessary when Mercurial
5158 interrupted operation. It should only be necessary when Mercurial
5159 suggests it.
5159 suggests it.
5160
5160
5161 Returns 0 if successful, 1 if nothing to recover or verify fails.
5161 Returns 0 if successful, 1 if nothing to recover or verify fails.
5162 """
5162 """
5163 if repo.recover():
5163 if repo.recover():
5164 return hg.verify(repo)
5164 return hg.verify(repo)
5165 return 1
5165 return 1
5166
5166
5167 @command('^remove|rm',
5167 @command('^remove|rm',
5168 [('A', 'after', None, _('record delete for missing files')),
5168 [('A', 'after', None, _('record delete for missing files')),
5169 ('f', 'force', None,
5169 ('f', 'force', None,
5170 _('remove (and delete) file even if added or modified')),
5170 _('remove (and delete) file even if added or modified')),
5171 ] + subrepoopts + walkopts,
5171 ] + subrepoopts + walkopts,
5172 _('[OPTION]... FILE...'),
5172 _('[OPTION]... FILE...'),
5173 inferrepo=True)
5173 inferrepo=True)
5174 def remove(ui, repo, *pats, **opts):
5174 def remove(ui, repo, *pats, **opts):
5175 """remove the specified files on the next commit
5175 """remove the specified files on the next commit
5176
5176
5177 Schedule the indicated files for removal from the current branch.
5177 Schedule the indicated files for removal from the current branch.
5178
5178
5179 This command schedules the files to be removed at the next commit.
5179 This command schedules the files to be removed at the next commit.
5180 To undo a remove before that, see :hg:`revert`. To undo added
5180 To undo a remove before that, see :hg:`revert`. To undo added
5181 files, see :hg:`forget`.
5181 files, see :hg:`forget`.
5182
5182
5183 .. container:: verbose
5183 .. container:: verbose
5184
5184
5185 -A/--after can be used to remove only files that have already
5185 -A/--after can be used to remove only files that have already
5186 been deleted, -f/--force can be used to force deletion, and -Af
5186 been deleted, -f/--force can be used to force deletion, and -Af
5187 can be used to remove files from the next revision without
5187 can be used to remove files from the next revision without
5188 deleting them from the working directory.
5188 deleting them from the working directory.
5189
5189
5190 The following table details the behavior of remove for different
5190 The following table details the behavior of remove for different
5191 file states (columns) and option combinations (rows). The file
5191 file states (columns) and option combinations (rows). The file
5192 states are Added [A], Clean [C], Modified [M] and Missing [!]
5192 states are Added [A], Clean [C], Modified [M] and Missing [!]
5193 (as reported by :hg:`status`). The actions are Warn, Remove
5193 (as reported by :hg:`status`). The actions are Warn, Remove
5194 (from branch) and Delete (from disk):
5194 (from branch) and Delete (from disk):
5195
5195
5196 ========= == == == ==
5196 ========= == == == ==
5197 opt/state A C M !
5197 opt/state A C M !
5198 ========= == == == ==
5198 ========= == == == ==
5199 none W RD W R
5199 none W RD W R
5200 -f R RD RD R
5200 -f R RD RD R
5201 -A W W W R
5201 -A W W W R
5202 -Af R R R R
5202 -Af R R R R
5203 ========= == == == ==
5203 ========= == == == ==
5204
5204
5205 Note that remove never deletes files in Added [A] state from the
5205 Note that remove never deletes files in Added [A] state from the
5206 working directory, not even if option --force is specified.
5206 working directory, not even if option --force is specified.
5207
5207
5208 Returns 0 on success, 1 if any warnings encountered.
5208 Returns 0 on success, 1 if any warnings encountered.
5209 """
5209 """
5210
5210
5211 after, force = opts.get('after'), opts.get('force')
5211 after, force = opts.get('after'), opts.get('force')
5212 if not pats and not after:
5212 if not pats and not after:
5213 raise util.Abort(_('no files specified'))
5213 raise util.Abort(_('no files specified'))
5214
5214
5215 m = scmutil.match(repo[None], pats, opts)
5215 m = scmutil.match(repo[None], pats, opts)
5216 subrepos = opts.get('subrepos')
5216 subrepos = opts.get('subrepos')
5217 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5217 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5218
5218
5219 @command('rename|move|mv',
5219 @command('rename|move|mv',
5220 [('A', 'after', None, _('record a rename that has already occurred')),
5220 [('A', 'after', None, _('record a rename that has already occurred')),
5221 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5221 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5222 ] + walkopts + dryrunopts,
5222 ] + walkopts + dryrunopts,
5223 _('[OPTION]... SOURCE... DEST'))
5223 _('[OPTION]... SOURCE... DEST'))
5224 def rename(ui, repo, *pats, **opts):
5224 def rename(ui, repo, *pats, **opts):
5225 """rename files; equivalent of copy + remove
5225 """rename files; equivalent of copy + remove
5226
5226
5227 Mark dest as copies of sources; mark sources for deletion. If dest
5227 Mark dest as copies of sources; mark sources for deletion. If dest
5228 is a directory, copies are put in that directory. If dest is a
5228 is a directory, copies are put in that directory. If dest is a
5229 file, there can only be one source.
5229 file, there can only be one source.
5230
5230
5231 By default, this command copies the contents of files as they
5231 By default, this command copies the contents of files as they
5232 exist in the working directory. If invoked with -A/--after, the
5232 exist in the working directory. If invoked with -A/--after, the
5233 operation is recorded, but no copying is performed.
5233 operation is recorded, but no copying is performed.
5234
5234
5235 This command takes effect at the next commit. To undo a rename
5235 This command takes effect at the next commit. To undo a rename
5236 before that, see :hg:`revert`.
5236 before that, see :hg:`revert`.
5237
5237
5238 Returns 0 on success, 1 if errors are encountered.
5238 Returns 0 on success, 1 if errors are encountered.
5239 """
5239 """
5240 wlock = repo.wlock(False)
5240 wlock = repo.wlock(False)
5241 try:
5241 try:
5242 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5242 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5243 finally:
5243 finally:
5244 wlock.release()
5244 wlock.release()
5245
5245
5246 @command('resolve',
5246 @command('resolve',
5247 [('a', 'all', None, _('select all unresolved files')),
5247 [('a', 'all', None, _('select all unresolved files')),
5248 ('l', 'list', None, _('list state of files needing merge')),
5248 ('l', 'list', None, _('list state of files needing merge')),
5249 ('m', 'mark', None, _('mark files as resolved')),
5249 ('m', 'mark', None, _('mark files as resolved')),
5250 ('u', 'unmark', None, _('mark files as unresolved')),
5250 ('u', 'unmark', None, _('mark files as unresolved')),
5251 ('n', 'no-status', None, _('hide status prefix'))]
5251 ('n', 'no-status', None, _('hide status prefix'))]
5252 + mergetoolopts + walkopts + formatteropts,
5252 + mergetoolopts + walkopts + formatteropts,
5253 _('[OPTION]... [FILE]...'),
5253 _('[OPTION]... [FILE]...'),
5254 inferrepo=True)
5254 inferrepo=True)
5255 def resolve(ui, repo, *pats, **opts):
5255 def resolve(ui, repo, *pats, **opts):
5256 """redo merges or set/view the merge status of files
5256 """redo merges or set/view the merge status of files
5257
5257
5258 Merges with unresolved conflicts are often the result of
5258 Merges with unresolved conflicts are often the result of
5259 non-interactive merging using the ``internal:merge`` configuration
5259 non-interactive merging using the ``internal:merge`` configuration
5260 setting, or a command-line merge tool like ``diff3``. The resolve
5260 setting, or a command-line merge tool like ``diff3``. The resolve
5261 command is used to manage the files involved in a merge, after
5261 command is used to manage the files involved in a merge, after
5262 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5262 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5263 working directory must have two parents). See :hg:`help
5263 working directory must have two parents). See :hg:`help
5264 merge-tools` for information on configuring merge tools.
5264 merge-tools` for information on configuring merge tools.
5265
5265
5266 The resolve command can be used in the following ways:
5266 The resolve command can be used in the following ways:
5267
5267
5268 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5268 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5269 files, discarding any previous merge attempts. Re-merging is not
5269 files, discarding any previous merge attempts. Re-merging is not
5270 performed for files already marked as resolved. Use ``--all/-a``
5270 performed for files already marked as resolved. Use ``--all/-a``
5271 to select all unresolved files. ``--tool`` can be used to specify
5271 to select all unresolved files. ``--tool`` can be used to specify
5272 the merge tool used for the given files. It overrides the HGMERGE
5272 the merge tool used for the given files. It overrides the HGMERGE
5273 environment variable and your configuration files. Previous file
5273 environment variable and your configuration files. Previous file
5274 contents are saved with a ``.orig`` suffix.
5274 contents are saved with a ``.orig`` suffix.
5275
5275
5276 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5276 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5277 (e.g. after having manually fixed-up the files). The default is
5277 (e.g. after having manually fixed-up the files). The default is
5278 to mark all unresolved files.
5278 to mark all unresolved files.
5279
5279
5280 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5280 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5281 default is to mark all resolved files.
5281 default is to mark all resolved files.
5282
5282
5283 - :hg:`resolve -l`: list files which had or still have conflicts.
5283 - :hg:`resolve -l`: list files which had or still have conflicts.
5284 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5284 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5285
5285
5286 Note that Mercurial will not let you commit files with unresolved
5286 Note that Mercurial will not let you commit files with unresolved
5287 merge conflicts. You must use :hg:`resolve -m ...` before you can
5287 merge conflicts. You must use :hg:`resolve -m ...` before you can
5288 commit after a conflicting merge.
5288 commit after a conflicting merge.
5289
5289
5290 Returns 0 on success, 1 if any files fail a resolve attempt.
5290 Returns 0 on success, 1 if any files fail a resolve attempt.
5291 """
5291 """
5292
5292
5293 all, mark, unmark, show, nostatus = \
5293 all, mark, unmark, show, nostatus = \
5294 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5294 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5295
5295
5296 if (show and (mark or unmark)) or (mark and unmark):
5296 if (show and (mark or unmark)) or (mark and unmark):
5297 raise util.Abort(_("too many options specified"))
5297 raise util.Abort(_("too many options specified"))
5298 if pats and all:
5298 if pats and all:
5299 raise util.Abort(_("can't specify --all and patterns"))
5299 raise util.Abort(_("can't specify --all and patterns"))
5300 if not (all or pats or show or mark or unmark):
5300 if not (all or pats or show or mark or unmark):
5301 raise util.Abort(_('no files or directories specified'),
5301 raise util.Abort(_('no files or directories specified'),
5302 hint=('use --all to remerge all files'))
5302 hint=('use --all to remerge all files'))
5303
5303
5304 if show:
5304 if show:
5305 fm = ui.formatter('resolve', opts)
5305 fm = ui.formatter('resolve', opts)
5306 ms = mergemod.mergestate(repo)
5306 ms = mergemod.mergestate(repo)
5307 m = scmutil.match(repo[None], pats, opts)
5307 m = scmutil.match(repo[None], pats, opts)
5308 for f in ms:
5308 for f in ms:
5309 if not m(f):
5309 if not m(f):
5310 continue
5310 continue
5311 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved'}[ms[f]]
5311 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved'}[ms[f]]
5312 fm.startitem()
5312 fm.startitem()
5313 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5313 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5314 fm.write('path', '%s\n', f, label=l)
5314 fm.write('path', '%s\n', f, label=l)
5315 fm.end()
5315 fm.end()
5316 return 0
5316 return 0
5317
5317
5318 wlock = repo.wlock()
5318 wlock = repo.wlock()
5319 try:
5319 try:
5320 ms = mergemod.mergestate(repo)
5320 ms = mergemod.mergestate(repo)
5321
5321
5322 if not (ms.active() or repo.dirstate.p2() != nullid):
5322 if not (ms.active() or repo.dirstate.p2() != nullid):
5323 raise util.Abort(
5323 raise util.Abort(
5324 _('resolve command not applicable when not merging'))
5324 _('resolve command not applicable when not merging'))
5325
5325
5326 m = scmutil.match(repo[None], pats, opts)
5326 m = scmutil.match(repo[None], pats, opts)
5327 ret = 0
5327 ret = 0
5328 didwork = False
5328 didwork = False
5329
5329
5330 for f in ms:
5330 for f in ms:
5331 if not m(f):
5331 if not m(f):
5332 continue
5332 continue
5333
5333
5334 didwork = True
5334 didwork = True
5335
5335
5336 if mark:
5336 if mark:
5337 ms.mark(f, "r")
5337 ms.mark(f, "r")
5338 elif unmark:
5338 elif unmark:
5339 ms.mark(f, "u")
5339 ms.mark(f, "u")
5340 else:
5340 else:
5341 wctx = repo[None]
5341 wctx = repo[None]
5342
5342
5343 # backup pre-resolve (merge uses .orig for its own purposes)
5343 # backup pre-resolve (merge uses .orig for its own purposes)
5344 a = repo.wjoin(f)
5344 a = repo.wjoin(f)
5345 util.copyfile(a, a + ".resolve")
5345 util.copyfile(a, a + ".resolve")
5346
5346
5347 try:
5347 try:
5348 # resolve file
5348 # resolve file
5349 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5349 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5350 'resolve')
5350 'resolve')
5351 if ms.resolve(f, wctx):
5351 if ms.resolve(f, wctx):
5352 ret = 1
5352 ret = 1
5353 finally:
5353 finally:
5354 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5354 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5355 ms.commit()
5355 ms.commit()
5356
5356
5357 # replace filemerge's .orig file with our resolve file
5357 # replace filemerge's .orig file with our resolve file
5358 util.rename(a + ".resolve", a + ".orig")
5358 util.rename(a + ".resolve", a + ".orig")
5359
5359
5360 ms.commit()
5360 ms.commit()
5361
5361
5362 if not didwork and pats:
5362 if not didwork and pats:
5363 ui.warn(_("arguments do not match paths that need resolving\n"))
5363 ui.warn(_("arguments do not match paths that need resolving\n"))
5364
5364
5365 finally:
5365 finally:
5366 wlock.release()
5366 wlock.release()
5367
5367
5368 # Nudge users into finishing an unfinished operation
5368 # Nudge users into finishing an unfinished operation
5369 if not list(ms.unresolved()):
5369 if not list(ms.unresolved()):
5370 ui.status(_('(no more unresolved files)\n'))
5370 ui.status(_('(no more unresolved files)\n'))
5371
5371
5372 return ret
5372 return ret
5373
5373
5374 @command('revert',
5374 @command('revert',
5375 [('a', 'all', None, _('revert all changes when no arguments given')),
5375 [('a', 'all', None, _('revert all changes when no arguments given')),
5376 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5376 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5377 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5377 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5378 ('C', 'no-backup', None, _('do not save backup copies of files')),
5378 ('C', 'no-backup', None, _('do not save backup copies of files')),
5379 ('i', 'interactive', None, _('interactively select the changes')),
5379 ('i', 'interactive', None, _('interactively select the changes')),
5380 ] + walkopts + dryrunopts,
5380 ] + walkopts + dryrunopts,
5381 _('[OPTION]... [-r REV] [NAME]...'))
5381 _('[OPTION]... [-r REV] [NAME]...'))
5382 def revert(ui, repo, *pats, **opts):
5382 def revert(ui, repo, *pats, **opts):
5383 """restore files to their checkout state
5383 """restore files to their checkout state
5384
5384
5385 .. note::
5385 .. note::
5386
5386
5387 To check out earlier revisions, you should use :hg:`update REV`.
5387 To check out earlier revisions, you should use :hg:`update REV`.
5388 To cancel an uncommitted merge (and lose your changes),
5388 To cancel an uncommitted merge (and lose your changes),
5389 use :hg:`update --clean .`.
5389 use :hg:`update --clean .`.
5390
5390
5391 With no revision specified, revert the specified files or directories
5391 With no revision specified, revert the specified files or directories
5392 to the contents they had in the parent of the working directory.
5392 to the contents they had in the parent of the working directory.
5393 This restores the contents of files to an unmodified
5393 This restores the contents of files to an unmodified
5394 state and unschedules adds, removes, copies, and renames. If the
5394 state and unschedules adds, removes, copies, and renames. If the
5395 working directory has two parents, you must explicitly specify a
5395 working directory has two parents, you must explicitly specify a
5396 revision.
5396 revision.
5397
5397
5398 Using the -r/--rev or -d/--date options, revert the given files or
5398 Using the -r/--rev or -d/--date options, revert the given files or
5399 directories to their states as of a specific revision. Because
5399 directories to their states as of a specific revision. Because
5400 revert does not change the working directory parents, this will
5400 revert does not change the working directory parents, this will
5401 cause these files to appear modified. This can be helpful to "back
5401 cause these files to appear modified. This can be helpful to "back
5402 out" some or all of an earlier change. See :hg:`backout` for a
5402 out" some or all of an earlier change. See :hg:`backout` for a
5403 related method.
5403 related method.
5404
5404
5405 Modified files are saved with a .orig suffix before reverting.
5405 Modified files are saved with a .orig suffix before reverting.
5406 To disable these backups, use --no-backup.
5406 To disable these backups, use --no-backup.
5407
5407
5408 See :hg:`help dates` for a list of formats valid for -d/--date.
5408 See :hg:`help dates` for a list of formats valid for -d/--date.
5409
5409
5410 Returns 0 on success.
5410 Returns 0 on success.
5411 """
5411 """
5412
5412
5413 if opts.get("date"):
5413 if opts.get("date"):
5414 if opts.get("rev"):
5414 if opts.get("rev"):
5415 raise util.Abort(_("you can't specify a revision and a date"))
5415 raise util.Abort(_("you can't specify a revision and a date"))
5416 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5416 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5417
5417
5418 parent, p2 = repo.dirstate.parents()
5418 parent, p2 = repo.dirstate.parents()
5419 if not opts.get('rev') and p2 != nullid:
5419 if not opts.get('rev') and p2 != nullid:
5420 # revert after merge is a trap for new users (issue2915)
5420 # revert after merge is a trap for new users (issue2915)
5421 raise util.Abort(_('uncommitted merge with no revision specified'),
5421 raise util.Abort(_('uncommitted merge with no revision specified'),
5422 hint=_('use "hg update" or see "hg help revert"'))
5422 hint=_('use "hg update" or see "hg help revert"'))
5423
5423
5424 ctx = scmutil.revsingle(repo, opts.get('rev'))
5424 ctx = scmutil.revsingle(repo, opts.get('rev'))
5425
5425
5426 if not pats and not opts.get('all'):
5426 if not pats and not opts.get('all'):
5427 msg = _("no files or directories specified")
5427 msg = _("no files or directories specified")
5428 if p2 != nullid:
5428 if p2 != nullid:
5429 hint = _("uncommitted merge, use --all to discard all changes,"
5429 hint = _("uncommitted merge, use --all to discard all changes,"
5430 " or 'hg update -C .' to abort the merge")
5430 " or 'hg update -C .' to abort the merge")
5431 raise util.Abort(msg, hint=hint)
5431 raise util.Abort(msg, hint=hint)
5432 dirty = util.any(repo.status())
5432 dirty = util.any(repo.status())
5433 node = ctx.node()
5433 node = ctx.node()
5434 if node != parent:
5434 if node != parent:
5435 if dirty:
5435 if dirty:
5436 hint = _("uncommitted changes, use --all to discard all"
5436 hint = _("uncommitted changes, use --all to discard all"
5437 " changes, or 'hg update %s' to update") % ctx.rev()
5437 " changes, or 'hg update %s' to update") % ctx.rev()
5438 else:
5438 else:
5439 hint = _("use --all to revert all files,"
5439 hint = _("use --all to revert all files,"
5440 " or 'hg update %s' to update") % ctx.rev()
5440 " or 'hg update %s' to update") % ctx.rev()
5441 elif dirty:
5441 elif dirty:
5442 hint = _("uncommitted changes, use --all to discard all changes")
5442 hint = _("uncommitted changes, use --all to discard all changes")
5443 else:
5443 else:
5444 hint = _("use --all to revert all files")
5444 hint = _("use --all to revert all files")
5445 raise util.Abort(msg, hint=hint)
5445 raise util.Abort(msg, hint=hint)
5446
5446
5447 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5447 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5448
5448
5449 @command('rollback', dryrunopts +
5449 @command('rollback', dryrunopts +
5450 [('f', 'force', False, _('ignore safety measures'))])
5450 [('f', 'force', False, _('ignore safety measures'))])
5451 def rollback(ui, repo, **opts):
5451 def rollback(ui, repo, **opts):
5452 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5452 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5453
5453
5454 Please use :hg:`commit --amend` instead of rollback to correct
5454 Please use :hg:`commit --amend` instead of rollback to correct
5455 mistakes in the last commit.
5455 mistakes in the last commit.
5456
5456
5457 This command should be used with care. There is only one level of
5457 This command should be used with care. There is only one level of
5458 rollback, and there is no way to undo a rollback. It will also
5458 rollback, and there is no way to undo a rollback. It will also
5459 restore the dirstate at the time of the last transaction, losing
5459 restore the dirstate at the time of the last transaction, losing
5460 any dirstate changes since that time. This command does not alter
5460 any dirstate changes since that time. This command does not alter
5461 the working directory.
5461 the working directory.
5462
5462
5463 Transactions are used to encapsulate the effects of all commands
5463 Transactions are used to encapsulate the effects of all commands
5464 that create new changesets or propagate existing changesets into a
5464 that create new changesets or propagate existing changesets into a
5465 repository.
5465 repository.
5466
5466
5467 .. container:: verbose
5467 .. container:: verbose
5468
5468
5469 For example, the following commands are transactional, and their
5469 For example, the following commands are transactional, and their
5470 effects can be rolled back:
5470 effects can be rolled back:
5471
5471
5472 - commit
5472 - commit
5473 - import
5473 - import
5474 - pull
5474 - pull
5475 - push (with this repository as the destination)
5475 - push (with this repository as the destination)
5476 - unbundle
5476 - unbundle
5477
5477
5478 To avoid permanent data loss, rollback will refuse to rollback a
5478 To avoid permanent data loss, rollback will refuse to rollback a
5479 commit transaction if it isn't checked out. Use --force to
5479 commit transaction if it isn't checked out. Use --force to
5480 override this protection.
5480 override this protection.
5481
5481
5482 This command is not intended for use on public repositories. Once
5482 This command is not intended for use on public repositories. Once
5483 changes are visible for pull by other users, rolling a transaction
5483 changes are visible for pull by other users, rolling a transaction
5484 back locally is ineffective (someone else may already have pulled
5484 back locally is ineffective (someone else may already have pulled
5485 the changes). Furthermore, a race is possible with readers of the
5485 the changes). Furthermore, a race is possible with readers of the
5486 repository; for example an in-progress pull from the repository
5486 repository; for example an in-progress pull from the repository
5487 may fail if a rollback is performed.
5487 may fail if a rollback is performed.
5488
5488
5489 Returns 0 on success, 1 if no rollback data is available.
5489 Returns 0 on success, 1 if no rollback data is available.
5490 """
5490 """
5491 return repo.rollback(dryrun=opts.get('dry_run'),
5491 return repo.rollback(dryrun=opts.get('dry_run'),
5492 force=opts.get('force'))
5492 force=opts.get('force'))
5493
5493
5494 @command('root', [])
5494 @command('root', [])
5495 def root(ui, repo):
5495 def root(ui, repo):
5496 """print the root (top) of the current working directory
5496 """print the root (top) of the current working directory
5497
5497
5498 Print the root directory of the current repository.
5498 Print the root directory of the current repository.
5499
5499
5500 Returns 0 on success.
5500 Returns 0 on success.
5501 """
5501 """
5502 ui.write(repo.root + "\n")
5502 ui.write(repo.root + "\n")
5503
5503
5504 @command('^serve',
5504 @command('^serve',
5505 [('A', 'accesslog', '', _('name of access log file to write to'),
5505 [('A', 'accesslog', '', _('name of access log file to write to'),
5506 _('FILE')),
5506 _('FILE')),
5507 ('d', 'daemon', None, _('run server in background')),
5507 ('d', 'daemon', None, _('run server in background')),
5508 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5508 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5509 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5509 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5510 # use string type, then we can check if something was passed
5510 # use string type, then we can check if something was passed
5511 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5511 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5512 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5512 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5513 _('ADDR')),
5513 _('ADDR')),
5514 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5514 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5515 _('PREFIX')),
5515 _('PREFIX')),
5516 ('n', 'name', '',
5516 ('n', 'name', '',
5517 _('name to show in web pages (default: working directory)'), _('NAME')),
5517 _('name to show in web pages (default: working directory)'), _('NAME')),
5518 ('', 'web-conf', '',
5518 ('', 'web-conf', '',
5519 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5519 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5520 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5520 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5521 _('FILE')),
5521 _('FILE')),
5522 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5522 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5523 ('', 'stdio', None, _('for remote clients')),
5523 ('', 'stdio', None, _('for remote clients')),
5524 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5524 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5525 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5525 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5526 ('', 'style', '', _('template style to use'), _('STYLE')),
5526 ('', 'style', '', _('template style to use'), _('STYLE')),
5527 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5527 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5528 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5528 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5529 _('[OPTION]...'),
5529 _('[OPTION]...'),
5530 optionalrepo=True)
5530 optionalrepo=True)
5531 def serve(ui, repo, **opts):
5531 def serve(ui, repo, **opts):
5532 """start stand-alone webserver
5532 """start stand-alone webserver
5533
5533
5534 Start a local HTTP repository browser and pull server. You can use
5534 Start a local HTTP repository browser and pull server. You can use
5535 this for ad-hoc sharing and browsing of repositories. It is
5535 this for ad-hoc sharing and browsing of repositories. It is
5536 recommended to use a real web server to serve a repository for
5536 recommended to use a real web server to serve a repository for
5537 longer periods of time.
5537 longer periods of time.
5538
5538
5539 Please note that the server does not implement access control.
5539 Please note that the server does not implement access control.
5540 This means that, by default, anybody can read from the server and
5540 This means that, by default, anybody can read from the server and
5541 nobody can write to it by default. Set the ``web.allow_push``
5541 nobody can write to it by default. Set the ``web.allow_push``
5542 option to ``*`` to allow everybody to push to the server. You
5542 option to ``*`` to allow everybody to push to the server. You
5543 should use a real web server if you need to authenticate users.
5543 should use a real web server if you need to authenticate users.
5544
5544
5545 By default, the server logs accesses to stdout and errors to
5545 By default, the server logs accesses to stdout and errors to
5546 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5546 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5547 files.
5547 files.
5548
5548
5549 To have the server choose a free port number to listen on, specify
5549 To have the server choose a free port number to listen on, specify
5550 a port number of 0; in this case, the server will print the port
5550 a port number of 0; in this case, the server will print the port
5551 number it uses.
5551 number it uses.
5552
5552
5553 Returns 0 on success.
5553 Returns 0 on success.
5554 """
5554 """
5555
5555
5556 if opts["stdio"] and opts["cmdserver"]:
5556 if opts["stdio"] and opts["cmdserver"]:
5557 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5557 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5558
5558
5559 if opts["stdio"]:
5559 if opts["stdio"]:
5560 if repo is None:
5560 if repo is None:
5561 raise error.RepoError(_("there is no Mercurial repository here"
5561 raise error.RepoError(_("there is no Mercurial repository here"
5562 " (.hg not found)"))
5562 " (.hg not found)"))
5563 s = sshserver.sshserver(ui, repo)
5563 s = sshserver.sshserver(ui, repo)
5564 s.serve_forever()
5564 s.serve_forever()
5565
5565
5566 if opts["cmdserver"]:
5566 if opts["cmdserver"]:
5567 service = commandserver.createservice(ui, repo, opts)
5567 service = commandserver.createservice(ui, repo, opts)
5568 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5568 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5569
5569
5570 # this way we can check if something was given in the command-line
5570 # this way we can check if something was given in the command-line
5571 if opts.get('port'):
5571 if opts.get('port'):
5572 opts['port'] = util.getport(opts.get('port'))
5572 opts['port'] = util.getport(opts.get('port'))
5573
5573
5574 if repo:
5574 if repo:
5575 baseui = repo.baseui
5575 baseui = repo.baseui
5576 else:
5576 else:
5577 baseui = ui
5577 baseui = ui
5578 optlist = ("name templates style address port prefix ipv6"
5578 optlist = ("name templates style address port prefix ipv6"
5579 " accesslog errorlog certificate encoding")
5579 " accesslog errorlog certificate encoding")
5580 for o in optlist.split():
5580 for o in optlist.split():
5581 val = opts.get(o, '')
5581 val = opts.get(o, '')
5582 if val in (None, ''): # should check against default options instead
5582 if val in (None, ''): # should check against default options instead
5583 continue
5583 continue
5584 baseui.setconfig("web", o, val, 'serve')
5584 baseui.setconfig("web", o, val, 'serve')
5585 if repo and repo.ui != baseui:
5585 if repo and repo.ui != baseui:
5586 repo.ui.setconfig("web", o, val, 'serve')
5586 repo.ui.setconfig("web", o, val, 'serve')
5587
5587
5588 o = opts.get('web_conf') or opts.get('webdir_conf')
5588 o = opts.get('web_conf') or opts.get('webdir_conf')
5589 if not o:
5589 if not o:
5590 if not repo:
5590 if not repo:
5591 raise error.RepoError(_("there is no Mercurial repository"
5591 raise error.RepoError(_("there is no Mercurial repository"
5592 " here (.hg not found)"))
5592 " here (.hg not found)"))
5593 o = repo
5593 o = repo
5594
5594
5595 app = hgweb.hgweb(o, baseui=baseui)
5595 app = hgweb.hgweb(o, baseui=baseui)
5596 service = httpservice(ui, app, opts)
5596 service = httpservice(ui, app, opts)
5597 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5597 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5598
5598
5599 class httpservice(object):
5599 class httpservice(object):
5600 def __init__(self, ui, app, opts):
5600 def __init__(self, ui, app, opts):
5601 self.ui = ui
5601 self.ui = ui
5602 self.app = app
5602 self.app = app
5603 self.opts = opts
5603 self.opts = opts
5604
5604
5605 def init(self):
5605 def init(self):
5606 util.setsignalhandler()
5606 util.setsignalhandler()
5607 self.httpd = hgweb_server.create_server(self.ui, self.app)
5607 self.httpd = hgweb_server.create_server(self.ui, self.app)
5608
5608
5609 if self.opts['port'] and not self.ui.verbose:
5609 if self.opts['port'] and not self.ui.verbose:
5610 return
5610 return
5611
5611
5612 if self.httpd.prefix:
5612 if self.httpd.prefix:
5613 prefix = self.httpd.prefix.strip('/') + '/'
5613 prefix = self.httpd.prefix.strip('/') + '/'
5614 else:
5614 else:
5615 prefix = ''
5615 prefix = ''
5616
5616
5617 port = ':%d' % self.httpd.port
5617 port = ':%d' % self.httpd.port
5618 if port == ':80':
5618 if port == ':80':
5619 port = ''
5619 port = ''
5620
5620
5621 bindaddr = self.httpd.addr
5621 bindaddr = self.httpd.addr
5622 if bindaddr == '0.0.0.0':
5622 if bindaddr == '0.0.0.0':
5623 bindaddr = '*'
5623 bindaddr = '*'
5624 elif ':' in bindaddr: # IPv6
5624 elif ':' in bindaddr: # IPv6
5625 bindaddr = '[%s]' % bindaddr
5625 bindaddr = '[%s]' % bindaddr
5626
5626
5627 fqaddr = self.httpd.fqaddr
5627 fqaddr = self.httpd.fqaddr
5628 if ':' in fqaddr:
5628 if ':' in fqaddr:
5629 fqaddr = '[%s]' % fqaddr
5629 fqaddr = '[%s]' % fqaddr
5630 if self.opts['port']:
5630 if self.opts['port']:
5631 write = self.ui.status
5631 write = self.ui.status
5632 else:
5632 else:
5633 write = self.ui.write
5633 write = self.ui.write
5634 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5634 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5635 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5635 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5636 self.ui.flush() # avoid buffering of status message
5636 self.ui.flush() # avoid buffering of status message
5637
5637
5638 def run(self):
5638 def run(self):
5639 self.httpd.serve_forever()
5639 self.httpd.serve_forever()
5640
5640
5641
5641
5642 @command('^status|st',
5642 @command('^status|st',
5643 [('A', 'all', None, _('show status of all files')),
5643 [('A', 'all', None, _('show status of all files')),
5644 ('m', 'modified', None, _('show only modified files')),
5644 ('m', 'modified', None, _('show only modified files')),
5645 ('a', 'added', None, _('show only added files')),
5645 ('a', 'added', None, _('show only added files')),
5646 ('r', 'removed', None, _('show only removed files')),
5646 ('r', 'removed', None, _('show only removed files')),
5647 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5647 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5648 ('c', 'clean', None, _('show only files without changes')),
5648 ('c', 'clean', None, _('show only files without changes')),
5649 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5649 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5650 ('i', 'ignored', None, _('show only ignored files')),
5650 ('i', 'ignored', None, _('show only ignored files')),
5651 ('n', 'no-status', None, _('hide status prefix')),
5651 ('n', 'no-status', None, _('hide status prefix')),
5652 ('C', 'copies', None, _('show source of copied files')),
5652 ('C', 'copies', None, _('show source of copied files')),
5653 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5653 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5654 ('', 'rev', [], _('show difference from revision'), _('REV')),
5654 ('', 'rev', [], _('show difference from revision'), _('REV')),
5655 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5655 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5656 ] + walkopts + subrepoopts + formatteropts,
5656 ] + walkopts + subrepoopts + formatteropts,
5657 _('[OPTION]... [FILE]...'),
5657 _('[OPTION]... [FILE]...'),
5658 inferrepo=True)
5658 inferrepo=True)
5659 def status(ui, repo, *pats, **opts):
5659 def status(ui, repo, *pats, **opts):
5660 """show changed files in the working directory
5660 """show changed files in the working directory
5661
5661
5662 Show status of files in the repository. If names are given, only
5662 Show status of files in the repository. If names are given, only
5663 files that match are shown. Files that are clean or ignored or
5663 files that match are shown. Files that are clean or ignored or
5664 the source of a copy/move operation, are not listed unless
5664 the source of a copy/move operation, are not listed unless
5665 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5665 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5666 Unless options described with "show only ..." are given, the
5666 Unless options described with "show only ..." are given, the
5667 options -mardu are used.
5667 options -mardu are used.
5668
5668
5669 Option -q/--quiet hides untracked (unknown and ignored) files
5669 Option -q/--quiet hides untracked (unknown and ignored) files
5670 unless explicitly requested with -u/--unknown or -i/--ignored.
5670 unless explicitly requested with -u/--unknown or -i/--ignored.
5671
5671
5672 .. note::
5672 .. note::
5673
5673
5674 status may appear to disagree with diff if permissions have
5674 status may appear to disagree with diff if permissions have
5675 changed or a merge has occurred. The standard diff format does
5675 changed or a merge has occurred. The standard diff format does
5676 not report permission changes and diff only reports changes
5676 not report permission changes and diff only reports changes
5677 relative to one merge parent.
5677 relative to one merge parent.
5678
5678
5679 If one revision is given, it is used as the base revision.
5679 If one revision is given, it is used as the base revision.
5680 If two revisions are given, the differences between them are
5680 If two revisions are given, the differences between them are
5681 shown. The --change option can also be used as a shortcut to list
5681 shown. The --change option can also be used as a shortcut to list
5682 the changed files of a revision from its first parent.
5682 the changed files of a revision from its first parent.
5683
5683
5684 The codes used to show the status of files are::
5684 The codes used to show the status of files are::
5685
5685
5686 M = modified
5686 M = modified
5687 A = added
5687 A = added
5688 R = removed
5688 R = removed
5689 C = clean
5689 C = clean
5690 ! = missing (deleted by non-hg command, but still tracked)
5690 ! = missing (deleted by non-hg command, but still tracked)
5691 ? = not tracked
5691 ? = not tracked
5692 I = ignored
5692 I = ignored
5693 = origin of the previous file (with --copies)
5693 = origin of the previous file (with --copies)
5694
5694
5695 .. container:: verbose
5695 .. container:: verbose
5696
5696
5697 Examples:
5697 Examples:
5698
5698
5699 - show changes in the working directory relative to a
5699 - show changes in the working directory relative to a
5700 changeset::
5700 changeset::
5701
5701
5702 hg status --rev 9353
5702 hg status --rev 9353
5703
5703
5704 - show all changes including copies in an existing changeset::
5704 - show all changes including copies in an existing changeset::
5705
5705
5706 hg status --copies --change 9353
5706 hg status --copies --change 9353
5707
5707
5708 - get a NUL separated list of added files, suitable for xargs::
5708 - get a NUL separated list of added files, suitable for xargs::
5709
5709
5710 hg status -an0
5710 hg status -an0
5711
5711
5712 Returns 0 on success.
5712 Returns 0 on success.
5713 """
5713 """
5714
5714
5715 revs = opts.get('rev')
5715 revs = opts.get('rev')
5716 change = opts.get('change')
5716 change = opts.get('change')
5717
5717
5718 if revs and change:
5718 if revs and change:
5719 msg = _('cannot specify --rev and --change at the same time')
5719 msg = _('cannot specify --rev and --change at the same time')
5720 raise util.Abort(msg)
5720 raise util.Abort(msg)
5721 elif change:
5721 elif change:
5722 node2 = scmutil.revsingle(repo, change, None).node()
5722 node2 = scmutil.revsingle(repo, change, None).node()
5723 node1 = repo[node2].p1().node()
5723 node1 = repo[node2].p1().node()
5724 else:
5724 else:
5725 node1, node2 = scmutil.revpair(repo, revs)
5725 node1, node2 = scmutil.revpair(repo, revs)
5726
5726
5727 if pats:
5727 if pats:
5728 cwd = repo.getcwd()
5728 cwd = repo.getcwd()
5729 else:
5729 else:
5730 cwd = ''
5730 cwd = ''
5731
5731
5732 if opts.get('print0'):
5732 if opts.get('print0'):
5733 end = '\0'
5733 end = '\0'
5734 else:
5734 else:
5735 end = '\n'
5735 end = '\n'
5736 copy = {}
5736 copy = {}
5737 states = 'modified added removed deleted unknown ignored clean'.split()
5737 states = 'modified added removed deleted unknown ignored clean'.split()
5738 show = [k for k in states if opts.get(k)]
5738 show = [k for k in states if opts.get(k)]
5739 if opts.get('all'):
5739 if opts.get('all'):
5740 show += ui.quiet and (states[:4] + ['clean']) or states
5740 show += ui.quiet and (states[:4] + ['clean']) or states
5741 if not show:
5741 if not show:
5742 if ui.quiet:
5742 if ui.quiet:
5743 show = states[:4]
5743 show = states[:4]
5744 else:
5744 else:
5745 show = states[:5]
5745 show = states[:5]
5746
5746
5747 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5747 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5748 'ignored' in show, 'clean' in show, 'unknown' in show,
5748 'ignored' in show, 'clean' in show, 'unknown' in show,
5749 opts.get('subrepos'))
5749 opts.get('subrepos'))
5750 changestates = zip(states, 'MAR!?IC', stat)
5750 changestates = zip(states, 'MAR!?IC', stat)
5751
5751
5752 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5752 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5753 copy = copies.pathcopies(repo[node1], repo[node2])
5753 copy = copies.pathcopies(repo[node1], repo[node2])
5754
5754
5755 fm = ui.formatter('status', opts)
5755 fm = ui.formatter('status', opts)
5756 fmt = '%s' + end
5756 fmt = '%s' + end
5757 showchar = not opts.get('no_status')
5757 showchar = not opts.get('no_status')
5758
5758
5759 for state, char, files in changestates:
5759 for state, char, files in changestates:
5760 if state in show:
5760 if state in show:
5761 label = 'status.' + state
5761 label = 'status.' + state
5762 for f in files:
5762 for f in files:
5763 fm.startitem()
5763 fm.startitem()
5764 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5764 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5765 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5765 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5766 if f in copy:
5766 if f in copy:
5767 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5767 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5768 label='status.copied')
5768 label='status.copied')
5769 fm.end()
5769 fm.end()
5770
5770
5771 @command('^summary|sum',
5771 @command('^summary|sum',
5772 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5772 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5773 def summary(ui, repo, **opts):
5773 def summary(ui, repo, **opts):
5774 """summarize working directory state
5774 """summarize working directory state
5775
5775
5776 This generates a brief summary of the working directory state,
5776 This generates a brief summary of the working directory state,
5777 including parents, branch, commit status, and available updates.
5777 including parents, branch, commit status, and available updates.
5778
5778
5779 With the --remote option, this will check the default paths for
5779 With the --remote option, this will check the default paths for
5780 incoming and outgoing changes. This can be time-consuming.
5780 incoming and outgoing changes. This can be time-consuming.
5781
5781
5782 Returns 0 on success.
5782 Returns 0 on success.
5783 """
5783 """
5784
5784
5785 ctx = repo[None]
5785 ctx = repo[None]
5786 parents = ctx.parents()
5786 parents = ctx.parents()
5787 pnode = parents[0].node()
5787 pnode = parents[0].node()
5788 marks = []
5788 marks = []
5789
5789
5790 for p in parents:
5790 for p in parents:
5791 # label with log.changeset (instead of log.parent) since this
5791 # label with log.changeset (instead of log.parent) since this
5792 # shows a working directory parent *changeset*:
5792 # shows a working directory parent *changeset*:
5793 # i18n: column positioning for "hg summary"
5793 # i18n: column positioning for "hg summary"
5794 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5794 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5795 label='log.changeset changeset.%s' % p.phasestr())
5795 label='log.changeset changeset.%s' % p.phasestr())
5796 ui.write(' '.join(p.tags()), label='log.tag')
5796 ui.write(' '.join(p.tags()), label='log.tag')
5797 if p.bookmarks():
5797 if p.bookmarks():
5798 marks.extend(p.bookmarks())
5798 marks.extend(p.bookmarks())
5799 if p.rev() == -1:
5799 if p.rev() == -1:
5800 if not len(repo):
5800 if not len(repo):
5801 ui.write(_(' (empty repository)'))
5801 ui.write(_(' (empty repository)'))
5802 else:
5802 else:
5803 ui.write(_(' (no revision checked out)'))
5803 ui.write(_(' (no revision checked out)'))
5804 ui.write('\n')
5804 ui.write('\n')
5805 if p.description():
5805 if p.description():
5806 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5806 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5807 label='log.summary')
5807 label='log.summary')
5808
5808
5809 branch = ctx.branch()
5809 branch = ctx.branch()
5810 bheads = repo.branchheads(branch)
5810 bheads = repo.branchheads(branch)
5811 # i18n: column positioning for "hg summary"
5811 # i18n: column positioning for "hg summary"
5812 m = _('branch: %s\n') % branch
5812 m = _('branch: %s\n') % branch
5813 if branch != 'default':
5813 if branch != 'default':
5814 ui.write(m, label='log.branch')
5814 ui.write(m, label='log.branch')
5815 else:
5815 else:
5816 ui.status(m, label='log.branch')
5816 ui.status(m, label='log.branch')
5817
5817
5818 if marks:
5818 if marks:
5819 current = repo._bookmarkcurrent
5819 current = repo._bookmarkcurrent
5820 # i18n: column positioning for "hg summary"
5820 # i18n: column positioning for "hg summary"
5821 ui.write(_('bookmarks:'), label='log.bookmark')
5821 ui.write(_('bookmarks:'), label='log.bookmark')
5822 if current is not None:
5822 if current is not None:
5823 if current in marks:
5823 if current in marks:
5824 ui.write(' *' + current, label='bookmarks.current')
5824 ui.write(' *' + current, label='bookmarks.current')
5825 marks.remove(current)
5825 marks.remove(current)
5826 else:
5826 else:
5827 ui.write(' [%s]' % current, label='bookmarks.current')
5827 ui.write(' [%s]' % current, label='bookmarks.current')
5828 for m in marks:
5828 for m in marks:
5829 ui.write(' ' + m, label='log.bookmark')
5829 ui.write(' ' + m, label='log.bookmark')
5830 ui.write('\n', label='log.bookmark')
5830 ui.write('\n', label='log.bookmark')
5831
5831
5832 status = repo.status(unknown=True)
5832 status = repo.status(unknown=True)
5833
5833
5834 c = repo.dirstate.copies()
5834 c = repo.dirstate.copies()
5835 copied, renamed = [], []
5835 copied, renamed = [], []
5836 for d, s in c.iteritems():
5836 for d, s in c.iteritems():
5837 if s in status.removed:
5837 if s in status.removed:
5838 status.removed.remove(s)
5838 status.removed.remove(s)
5839 renamed.append(d)
5839 renamed.append(d)
5840 else:
5840 else:
5841 copied.append(d)
5841 copied.append(d)
5842 if d in status.added:
5842 if d in status.added:
5843 status.added.remove(d)
5843 status.added.remove(d)
5844
5844
5845 ms = mergemod.mergestate(repo)
5845 ms = mergemod.mergestate(repo)
5846 unresolved = [f for f in ms if ms[f] == 'u']
5846 unresolved = [f for f in ms if ms[f] == 'u']
5847
5847
5848 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5848 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5849
5849
5850 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5850 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5851 (ui.label(_('%d added'), 'status.added'), status.added),
5851 (ui.label(_('%d added'), 'status.added'), status.added),
5852 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5852 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5853 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5853 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5854 (ui.label(_('%d copied'), 'status.copied'), copied),
5854 (ui.label(_('%d copied'), 'status.copied'), copied),
5855 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5855 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5856 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5856 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5857 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5857 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5858 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5858 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5859 t = []
5859 t = []
5860 for l, s in labels:
5860 for l, s in labels:
5861 if s:
5861 if s:
5862 t.append(l % len(s))
5862 t.append(l % len(s))
5863
5863
5864 t = ', '.join(t)
5864 t = ', '.join(t)
5865 cleanworkdir = False
5865 cleanworkdir = False
5866
5866
5867 if repo.vfs.exists('updatestate'):
5867 if repo.vfs.exists('updatestate'):
5868 t += _(' (interrupted update)')
5868 t += _(' (interrupted update)')
5869 elif len(parents) > 1:
5869 elif len(parents) > 1:
5870 t += _(' (merge)')
5870 t += _(' (merge)')
5871 elif branch != parents[0].branch():
5871 elif branch != parents[0].branch():
5872 t += _(' (new branch)')
5872 t += _(' (new branch)')
5873 elif (parents[0].closesbranch() and
5873 elif (parents[0].closesbranch() and
5874 pnode in repo.branchheads(branch, closed=True)):
5874 pnode in repo.branchheads(branch, closed=True)):
5875 t += _(' (head closed)')
5875 t += _(' (head closed)')
5876 elif not (status.modified or status.added or status.removed or renamed or
5876 elif not (status.modified or status.added or status.removed or renamed or
5877 copied or subs):
5877 copied or subs):
5878 t += _(' (clean)')
5878 t += _(' (clean)')
5879 cleanworkdir = True
5879 cleanworkdir = True
5880 elif pnode not in bheads:
5880 elif pnode not in bheads:
5881 t += _(' (new branch head)')
5881 t += _(' (new branch head)')
5882
5882
5883 if cleanworkdir:
5883 if cleanworkdir:
5884 # i18n: column positioning for "hg summary"
5884 # i18n: column positioning for "hg summary"
5885 ui.status(_('commit: %s\n') % t.strip())
5885 ui.status(_('commit: %s\n') % t.strip())
5886 else:
5886 else:
5887 # i18n: column positioning for "hg summary"
5887 # i18n: column positioning for "hg summary"
5888 ui.write(_('commit: %s\n') % t.strip())
5888 ui.write(_('commit: %s\n') % t.strip())
5889
5889
5890 # all ancestors of branch heads - all ancestors of parent = new csets
5890 # all ancestors of branch heads - all ancestors of parent = new csets
5891 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5891 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5892 bheads))
5892 bheads))
5893
5893
5894 if new == 0:
5894 if new == 0:
5895 # i18n: column positioning for "hg summary"
5895 # i18n: column positioning for "hg summary"
5896 ui.status(_('update: (current)\n'))
5896 ui.status(_('update: (current)\n'))
5897 elif pnode not in bheads:
5897 elif pnode not in bheads:
5898 # i18n: column positioning for "hg summary"
5898 # i18n: column positioning for "hg summary"
5899 ui.write(_('update: %d new changesets (update)\n') % new)
5899 ui.write(_('update: %d new changesets (update)\n') % new)
5900 else:
5900 else:
5901 # i18n: column positioning for "hg summary"
5901 # i18n: column positioning for "hg summary"
5902 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5902 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5903 (new, len(bheads)))
5903 (new, len(bheads)))
5904
5904
5905 cmdutil.summaryhooks(ui, repo)
5905 cmdutil.summaryhooks(ui, repo)
5906
5906
5907 if opts.get('remote'):
5907 if opts.get('remote'):
5908 needsincoming, needsoutgoing = True, True
5908 needsincoming, needsoutgoing = True, True
5909 else:
5909 else:
5910 needsincoming, needsoutgoing = False, False
5910 needsincoming, needsoutgoing = False, False
5911 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5911 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5912 if i:
5912 if i:
5913 needsincoming = True
5913 needsincoming = True
5914 if o:
5914 if o:
5915 needsoutgoing = True
5915 needsoutgoing = True
5916 if not needsincoming and not needsoutgoing:
5916 if not needsincoming and not needsoutgoing:
5917 return
5917 return
5918
5918
5919 def getincoming():
5919 def getincoming():
5920 source, branches = hg.parseurl(ui.expandpath('default'))
5920 source, branches = hg.parseurl(ui.expandpath('default'))
5921 sbranch = branches[0]
5921 sbranch = branches[0]
5922 try:
5922 try:
5923 other = hg.peer(repo, {}, source)
5923 other = hg.peer(repo, {}, source)
5924 except error.RepoError:
5924 except error.RepoError:
5925 if opts.get('remote'):
5925 if opts.get('remote'):
5926 raise
5926 raise
5927 return source, sbranch, None, None, None
5927 return source, sbranch, None, None, None
5928 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5928 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5929 if revs:
5929 if revs:
5930 revs = [other.lookup(rev) for rev in revs]
5930 revs = [other.lookup(rev) for rev in revs]
5931 ui.debug('comparing with %s\n' % util.hidepassword(source))
5931 ui.debug('comparing with %s\n' % util.hidepassword(source))
5932 repo.ui.pushbuffer()
5932 repo.ui.pushbuffer()
5933 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5933 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5934 repo.ui.popbuffer()
5934 repo.ui.popbuffer()
5935 return source, sbranch, other, commoninc, commoninc[1]
5935 return source, sbranch, other, commoninc, commoninc[1]
5936
5936
5937 if needsincoming:
5937 if needsincoming:
5938 source, sbranch, sother, commoninc, incoming = getincoming()
5938 source, sbranch, sother, commoninc, incoming = getincoming()
5939 else:
5939 else:
5940 source = sbranch = sother = commoninc = incoming = None
5940 source = sbranch = sother = commoninc = incoming = None
5941
5941
5942 def getoutgoing():
5942 def getoutgoing():
5943 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5943 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5944 dbranch = branches[0]
5944 dbranch = branches[0]
5945 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5945 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5946 if source != dest:
5946 if source != dest:
5947 try:
5947 try:
5948 dother = hg.peer(repo, {}, dest)
5948 dother = hg.peer(repo, {}, dest)
5949 except error.RepoError:
5949 except error.RepoError:
5950 if opts.get('remote'):
5950 if opts.get('remote'):
5951 raise
5951 raise
5952 return dest, dbranch, None, None
5952 return dest, dbranch, None, None
5953 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5953 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5954 elif sother is None:
5954 elif sother is None:
5955 # there is no explicit destination peer, but source one is invalid
5955 # there is no explicit destination peer, but source one is invalid
5956 return dest, dbranch, None, None
5956 return dest, dbranch, None, None
5957 else:
5957 else:
5958 dother = sother
5958 dother = sother
5959 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5959 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5960 common = None
5960 common = None
5961 else:
5961 else:
5962 common = commoninc
5962 common = commoninc
5963 if revs:
5963 if revs:
5964 revs = [repo.lookup(rev) for rev in revs]
5964 revs = [repo.lookup(rev) for rev in revs]
5965 repo.ui.pushbuffer()
5965 repo.ui.pushbuffer()
5966 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5966 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5967 commoninc=common)
5967 commoninc=common)
5968 repo.ui.popbuffer()
5968 repo.ui.popbuffer()
5969 return dest, dbranch, dother, outgoing
5969 return dest, dbranch, dother, outgoing
5970
5970
5971 if needsoutgoing:
5971 if needsoutgoing:
5972 dest, dbranch, dother, outgoing = getoutgoing()
5972 dest, dbranch, dother, outgoing = getoutgoing()
5973 else:
5973 else:
5974 dest = dbranch = dother = outgoing = None
5974 dest = dbranch = dother = outgoing = None
5975
5975
5976 if opts.get('remote'):
5976 if opts.get('remote'):
5977 t = []
5977 t = []
5978 if incoming:
5978 if incoming:
5979 t.append(_('1 or more incoming'))
5979 t.append(_('1 or more incoming'))
5980 o = outgoing.missing
5980 o = outgoing.missing
5981 if o:
5981 if o:
5982 t.append(_('%d outgoing') % len(o))
5982 t.append(_('%d outgoing') % len(o))
5983 other = dother or sother
5983 other = dother or sother
5984 if 'bookmarks' in other.listkeys('namespaces'):
5984 if 'bookmarks' in other.listkeys('namespaces'):
5985 lmarks = repo.listkeys('bookmarks')
5985 lmarks = repo.listkeys('bookmarks')
5986 rmarks = other.listkeys('bookmarks')
5986 rmarks = other.listkeys('bookmarks')
5987 diff = set(rmarks) - set(lmarks)
5987 diff = set(rmarks) - set(lmarks)
5988 if len(diff) > 0:
5988 if len(diff) > 0:
5989 t.append(_('%d incoming bookmarks') % len(diff))
5989 t.append(_('%d incoming bookmarks') % len(diff))
5990 diff = set(lmarks) - set(rmarks)
5990 diff = set(lmarks) - set(rmarks)
5991 if len(diff) > 0:
5991 if len(diff) > 0:
5992 t.append(_('%d outgoing bookmarks') % len(diff))
5992 t.append(_('%d outgoing bookmarks') % len(diff))
5993
5993
5994 if t:
5994 if t:
5995 # i18n: column positioning for "hg summary"
5995 # i18n: column positioning for "hg summary"
5996 ui.write(_('remote: %s\n') % (', '.join(t)))
5996 ui.write(_('remote: %s\n') % (', '.join(t)))
5997 else:
5997 else:
5998 # i18n: column positioning for "hg summary"
5998 # i18n: column positioning for "hg summary"
5999 ui.status(_('remote: (synced)\n'))
5999 ui.status(_('remote: (synced)\n'))
6000
6000
6001 cmdutil.summaryremotehooks(ui, repo, opts,
6001 cmdutil.summaryremotehooks(ui, repo, opts,
6002 ((source, sbranch, sother, commoninc),
6002 ((source, sbranch, sother, commoninc),
6003 (dest, dbranch, dother, outgoing)))
6003 (dest, dbranch, dother, outgoing)))
6004
6004
6005 @command('tag',
6005 @command('tag',
6006 [('f', 'force', None, _('force tag')),
6006 [('f', 'force', None, _('force tag')),
6007 ('l', 'local', None, _('make the tag local')),
6007 ('l', 'local', None, _('make the tag local')),
6008 ('r', 'rev', '', _('revision to tag'), _('REV')),
6008 ('r', 'rev', '', _('revision to tag'), _('REV')),
6009 ('', 'remove', None, _('remove a tag')),
6009 ('', 'remove', None, _('remove a tag')),
6010 # -l/--local is already there, commitopts cannot be used
6010 # -l/--local is already there, commitopts cannot be used
6011 ('e', 'edit', None, _('invoke editor on commit messages')),
6011 ('e', 'edit', None, _('invoke editor on commit messages')),
6012 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6012 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6013 ] + commitopts2,
6013 ] + commitopts2,
6014 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6014 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6015 def tag(ui, repo, name1, *names, **opts):
6015 def tag(ui, repo, name1, *names, **opts):
6016 """add one or more tags for the current or given revision
6016 """add one or more tags for the current or given revision
6017
6017
6018 Name a particular revision using <name>.
6018 Name a particular revision using <name>.
6019
6019
6020 Tags are used to name particular revisions of the repository and are
6020 Tags are used to name particular revisions of the repository and are
6021 very useful to compare different revisions, to go back to significant
6021 very useful to compare different revisions, to go back to significant
6022 earlier versions or to mark branch points as releases, etc. Changing
6022 earlier versions or to mark branch points as releases, etc. Changing
6023 an existing tag is normally disallowed; use -f/--force to override.
6023 an existing tag is normally disallowed; use -f/--force to override.
6024
6024
6025 If no revision is given, the parent of the working directory is
6025 If no revision is given, the parent of the working directory is
6026 used.
6026 used.
6027
6027
6028 To facilitate version control, distribution, and merging of tags,
6028 To facilitate version control, distribution, and merging of tags,
6029 they are stored as a file named ".hgtags" which is managed similarly
6029 they are stored as a file named ".hgtags" which is managed similarly
6030 to other project files and can be hand-edited if necessary. This
6030 to other project files and can be hand-edited if necessary. This
6031 also means that tagging creates a new commit. The file
6031 also means that tagging creates a new commit. The file
6032 ".hg/localtags" is used for local tags (not shared among
6032 ".hg/localtags" is used for local tags (not shared among
6033 repositories).
6033 repositories).
6034
6034
6035 Tag commits are usually made at the head of a branch. If the parent
6035 Tag commits are usually made at the head of a branch. If the parent
6036 of the working directory is not a branch head, :hg:`tag` aborts; use
6036 of the working directory is not a branch head, :hg:`tag` aborts; use
6037 -f/--force to force the tag commit to be based on a non-head
6037 -f/--force to force the tag commit to be based on a non-head
6038 changeset.
6038 changeset.
6039
6039
6040 See :hg:`help dates` for a list of formats valid for -d/--date.
6040 See :hg:`help dates` for a list of formats valid for -d/--date.
6041
6041
6042 Since tag names have priority over branch names during revision
6042 Since tag names have priority over branch names during revision
6043 lookup, using an existing branch name as a tag name is discouraged.
6043 lookup, using an existing branch name as a tag name is discouraged.
6044
6044
6045 Returns 0 on success.
6045 Returns 0 on success.
6046 """
6046 """
6047 wlock = lock = None
6047 wlock = lock = None
6048 try:
6048 try:
6049 wlock = repo.wlock()
6049 wlock = repo.wlock()
6050 lock = repo.lock()
6050 lock = repo.lock()
6051 rev_ = "."
6051 rev_ = "."
6052 names = [t.strip() for t in (name1,) + names]
6052 names = [t.strip() for t in (name1,) + names]
6053 if len(names) != len(set(names)):
6053 if len(names) != len(set(names)):
6054 raise util.Abort(_('tag names must be unique'))
6054 raise util.Abort(_('tag names must be unique'))
6055 for n in names:
6055 for n in names:
6056 scmutil.checknewlabel(repo, n, 'tag')
6056 scmutil.checknewlabel(repo, n, 'tag')
6057 if not n:
6057 if not n:
6058 raise util.Abort(_('tag names cannot consist entirely of '
6058 raise util.Abort(_('tag names cannot consist entirely of '
6059 'whitespace'))
6059 'whitespace'))
6060 if opts.get('rev') and opts.get('remove'):
6060 if opts.get('rev') and opts.get('remove'):
6061 raise util.Abort(_("--rev and --remove are incompatible"))
6061 raise util.Abort(_("--rev and --remove are incompatible"))
6062 if opts.get('rev'):
6062 if opts.get('rev'):
6063 rev_ = opts['rev']
6063 rev_ = opts['rev']
6064 message = opts.get('message')
6064 message = opts.get('message')
6065 if opts.get('remove'):
6065 if opts.get('remove'):
6066 if opts.get('local'):
6066 if opts.get('local'):
6067 expectedtype = 'local'
6067 expectedtype = 'local'
6068 else:
6068 else:
6069 expectedtype = 'global'
6069 expectedtype = 'global'
6070
6070
6071 for n in names:
6071 for n in names:
6072 if not repo.tagtype(n):
6072 if not repo.tagtype(n):
6073 raise util.Abort(_("tag '%s' does not exist") % n)
6073 raise util.Abort(_("tag '%s' does not exist") % n)
6074 if repo.tagtype(n) != expectedtype:
6074 if repo.tagtype(n) != expectedtype:
6075 if expectedtype == 'global':
6075 if expectedtype == 'global':
6076 raise util.Abort(_("tag '%s' is not a global tag") % n)
6076 raise util.Abort(_("tag '%s' is not a global tag") % n)
6077 else:
6077 else:
6078 raise util.Abort(_("tag '%s' is not a local tag") % n)
6078 raise util.Abort(_("tag '%s' is not a local tag") % n)
6079 rev_ = nullid
6079 rev_ = nullid
6080 if not message:
6080 if not message:
6081 # we don't translate commit messages
6081 # we don't translate commit messages
6082 message = 'Removed tag %s' % ', '.join(names)
6082 message = 'Removed tag %s' % ', '.join(names)
6083 elif not opts.get('force'):
6083 elif not opts.get('force'):
6084 for n in names:
6084 for n in names:
6085 if n in repo.tags():
6085 if n in repo.tags():
6086 raise util.Abort(_("tag '%s' already exists "
6086 raise util.Abort(_("tag '%s' already exists "
6087 "(use -f to force)") % n)
6087 "(use -f to force)") % n)
6088 if not opts.get('local'):
6088 if not opts.get('local'):
6089 p1, p2 = repo.dirstate.parents()
6089 p1, p2 = repo.dirstate.parents()
6090 if p2 != nullid:
6090 if p2 != nullid:
6091 raise util.Abort(_('uncommitted merge'))
6091 raise util.Abort(_('uncommitted merge'))
6092 bheads = repo.branchheads()
6092 bheads = repo.branchheads()
6093 if not opts.get('force') and bheads and p1 not in bheads:
6093 if not opts.get('force') and bheads and p1 not in bheads:
6094 raise util.Abort(_('not at a branch head (use -f to force)'))
6094 raise util.Abort(_('not at a branch head (use -f to force)'))
6095 r = scmutil.revsingle(repo, rev_).node()
6095 r = scmutil.revsingle(repo, rev_).node()
6096
6096
6097 if not message:
6097 if not message:
6098 # we don't translate commit messages
6098 # we don't translate commit messages
6099 message = ('Added tag %s for changeset %s' %
6099 message = ('Added tag %s for changeset %s' %
6100 (', '.join(names), short(r)))
6100 (', '.join(names), short(r)))
6101
6101
6102 date = opts.get('date')
6102 date = opts.get('date')
6103 if date:
6103 if date:
6104 date = util.parsedate(date)
6104 date = util.parsedate(date)
6105
6105
6106 if opts.get('remove'):
6106 if opts.get('remove'):
6107 editform = 'tag.remove'
6107 editform = 'tag.remove'
6108 else:
6108 else:
6109 editform = 'tag.add'
6109 editform = 'tag.add'
6110 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6110 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6111
6111
6112 # don't allow tagging the null rev
6112 # don't allow tagging the null rev
6113 if (not opts.get('remove') and
6113 if (not opts.get('remove') and
6114 scmutil.revsingle(repo, rev_).rev() == nullrev):
6114 scmutil.revsingle(repo, rev_).rev() == nullrev):
6115 raise util.Abort(_("cannot tag null revision"))
6115 raise util.Abort(_("cannot tag null revision"))
6116
6116
6117 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6117 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6118 editor=editor)
6118 editor=editor)
6119 finally:
6119 finally:
6120 release(lock, wlock)
6120 release(lock, wlock)
6121
6121
6122 @command('tags', formatteropts, '')
6122 @command('tags', formatteropts, '')
6123 def tags(ui, repo, **opts):
6123 def tags(ui, repo, **opts):
6124 """list repository tags
6124 """list repository tags
6125
6125
6126 This lists both regular and local tags. When the -v/--verbose
6126 This lists both regular and local tags. When the -v/--verbose
6127 switch is used, a third column "local" is printed for local tags.
6127 switch is used, a third column "local" is printed for local tags.
6128
6128
6129 Returns 0 on success.
6129 Returns 0 on success.
6130 """
6130 """
6131
6131
6132 fm = ui.formatter('tags', opts)
6132 fm = ui.formatter('tags', opts)
6133 hexfunc = fm.hexfunc
6133 hexfunc = fm.hexfunc
6134 tagtype = ""
6134 tagtype = ""
6135
6135
6136 for t, n in reversed(repo.tagslist()):
6136 for t, n in reversed(repo.tagslist()):
6137 hn = hexfunc(n)
6137 hn = hexfunc(n)
6138 label = 'tags.normal'
6138 label = 'tags.normal'
6139 tagtype = ''
6139 tagtype = ''
6140 if repo.tagtype(t) == 'local':
6140 if repo.tagtype(t) == 'local':
6141 label = 'tags.local'
6141 label = 'tags.local'
6142 tagtype = 'local'
6142 tagtype = 'local'
6143
6143
6144 fm.startitem()
6144 fm.startitem()
6145 fm.write('tag', '%s', t, label=label)
6145 fm.write('tag', '%s', t, label=label)
6146 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6146 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6147 fm.condwrite(not ui.quiet, 'rev node', fmt,
6147 fm.condwrite(not ui.quiet, 'rev node', fmt,
6148 repo.changelog.rev(n), hn, label=label)
6148 repo.changelog.rev(n), hn, label=label)
6149 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6149 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6150 tagtype, label=label)
6150 tagtype, label=label)
6151 fm.plain('\n')
6151 fm.plain('\n')
6152 fm.end()
6152 fm.end()
6153
6153
6154 @command('tip',
6154 @command('tip',
6155 [('p', 'patch', None, _('show patch')),
6155 [('p', 'patch', None, _('show patch')),
6156 ('g', 'git', None, _('use git extended diff format')),
6156 ('g', 'git', None, _('use git extended diff format')),
6157 ] + templateopts,
6157 ] + templateopts,
6158 _('[-p] [-g]'))
6158 _('[-p] [-g]'))
6159 def tip(ui, repo, **opts):
6159 def tip(ui, repo, **opts):
6160 """show the tip revision (DEPRECATED)
6160 """show the tip revision (DEPRECATED)
6161
6161
6162 The tip revision (usually just called the tip) is the changeset
6162 The tip revision (usually just called the tip) is the changeset
6163 most recently added to the repository (and therefore the most
6163 most recently added to the repository (and therefore the most
6164 recently changed head).
6164 recently changed head).
6165
6165
6166 If you have just made a commit, that commit will be the tip. If
6166 If you have just made a commit, that commit will be the tip. If
6167 you have just pulled changes from another repository, the tip of
6167 you have just pulled changes from another repository, the tip of
6168 that repository becomes the current tip. The "tip" tag is special
6168 that repository becomes the current tip. The "tip" tag is special
6169 and cannot be renamed or assigned to a different changeset.
6169 and cannot be renamed or assigned to a different changeset.
6170
6170
6171 This command is deprecated, please use :hg:`heads` instead.
6171 This command is deprecated, please use :hg:`heads` instead.
6172
6172
6173 Returns 0 on success.
6173 Returns 0 on success.
6174 """
6174 """
6175 displayer = cmdutil.show_changeset(ui, repo, opts)
6175 displayer = cmdutil.show_changeset(ui, repo, opts)
6176 displayer.show(repo['tip'])
6176 displayer.show(repo['tip'])
6177 displayer.close()
6177 displayer.close()
6178
6178
6179 @command('unbundle',
6179 @command('unbundle',
6180 [('u', 'update', None,
6180 [('u', 'update', None,
6181 _('update to new branch head if changesets were unbundled'))],
6181 _('update to new branch head if changesets were unbundled'))],
6182 _('[-u] FILE...'))
6182 _('[-u] FILE...'))
6183 def unbundle(ui, repo, fname1, *fnames, **opts):
6183 def unbundle(ui, repo, fname1, *fnames, **opts):
6184 """apply one or more changegroup files
6184 """apply one or more changegroup files
6185
6185
6186 Apply one or more compressed changegroup files generated by the
6186 Apply one or more compressed changegroup files generated by the
6187 bundle command.
6187 bundle command.
6188
6188
6189 Returns 0 on success, 1 if an update has unresolved files.
6189 Returns 0 on success, 1 if an update has unresolved files.
6190 """
6190 """
6191 fnames = (fname1,) + fnames
6191 fnames = (fname1,) + fnames
6192
6192
6193 lock = repo.lock()
6193 lock = repo.lock()
6194 try:
6194 try:
6195 for fname in fnames:
6195 for fname in fnames:
6196 f = hg.openpath(ui, fname)
6196 f = hg.openpath(ui, fname)
6197 gen = exchange.readbundle(ui, f, fname)
6197 gen = exchange.readbundle(ui, f, fname)
6198 if isinstance(gen, bundle2.unbundle20):
6198 if isinstance(gen, bundle2.unbundle20):
6199 tr = repo.transaction('unbundle')
6199 tr = repo.transaction('unbundle')
6200 try:
6200 try:
6201 op = bundle2.processbundle(repo, gen, lambda: tr)
6201 op = bundle2.processbundle(repo, gen, lambda: tr)
6202 tr.close()
6202 tr.close()
6203 finally:
6203 finally:
6204 if tr:
6204 if tr:
6205 tr.release()
6205 tr.release()
6206 changes = [r.get('result', 0)
6206 changes = [r.get('result', 0)
6207 for r in op.records['changegroup']]
6207 for r in op.records['changegroup']]
6208 modheads = changegroup.combineresults(changes)
6208 modheads = changegroup.combineresults(changes)
6209 else:
6209 else:
6210 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6210 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6211 'bundle:' + fname)
6211 'bundle:' + fname)
6212 finally:
6212 finally:
6213 lock.release()
6213 lock.release()
6214
6214
6215 return postincoming(ui, repo, modheads, opts.get('update'), None)
6215 return postincoming(ui, repo, modheads, opts.get('update'), None)
6216
6216
6217 @command('^update|up|checkout|co',
6217 @command('^update|up|checkout|co',
6218 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6218 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6219 ('c', 'check', None,
6219 ('c', 'check', None,
6220 _('update across branches if no uncommitted changes')),
6220 _('update across branches if no uncommitted changes')),
6221 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6221 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6222 ('r', 'rev', '', _('revision'), _('REV'))
6222 ('r', 'rev', '', _('revision'), _('REV'))
6223 ] + mergetoolopts,
6223 ] + mergetoolopts,
6224 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6224 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6225 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6225 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6226 tool=None):
6226 tool=None):
6227 """update working directory (or switch revisions)
6227 """update working directory (or switch revisions)
6228
6228
6229 Update the repository's working directory to the specified
6229 Update the repository's working directory to the specified
6230 changeset. If no changeset is specified, update to the tip of the
6230 changeset. If no changeset is specified, update to the tip of the
6231 current named branch and move the current bookmark (see :hg:`help
6231 current named branch and move the current bookmark (see :hg:`help
6232 bookmarks`).
6232 bookmarks`).
6233
6233
6234 Update sets the working directory's parent revision to the specified
6234 Update sets the working directory's parent revision to the specified
6235 changeset (see :hg:`help parents`).
6235 changeset (see :hg:`help parents`).
6236
6236
6237 If the changeset is not a descendant or ancestor of the working
6237 If the changeset is not a descendant or ancestor of the working
6238 directory's parent, the update is aborted. With the -c/--check
6238 directory's parent, the update is aborted. With the -c/--check
6239 option, the working directory is checked for uncommitted changes; if
6239 option, the working directory is checked for uncommitted changes; if
6240 none are found, the working directory is updated to the specified
6240 none are found, the working directory is updated to the specified
6241 changeset.
6241 changeset.
6242
6242
6243 .. container:: verbose
6243 .. container:: verbose
6244
6244
6245 The following rules apply when the working directory contains
6245 The following rules apply when the working directory contains
6246 uncommitted changes:
6246 uncommitted changes:
6247
6247
6248 1. If neither -c/--check nor -C/--clean is specified, and if
6248 1. If neither -c/--check nor -C/--clean is specified, and if
6249 the requested changeset is an ancestor or descendant of
6249 the requested changeset is an ancestor or descendant of
6250 the working directory's parent, the uncommitted changes
6250 the working directory's parent, the uncommitted changes
6251 are merged into the requested changeset and the merged
6251 are merged into the requested changeset and the merged
6252 result is left uncommitted. If the requested changeset is
6252 result is left uncommitted. If the requested changeset is
6253 not an ancestor or descendant (that is, it is on another
6253 not an ancestor or descendant (that is, it is on another
6254 branch), the update is aborted and the uncommitted changes
6254 branch), the update is aborted and the uncommitted changes
6255 are preserved.
6255 are preserved.
6256
6256
6257 2. With the -c/--check option, the update is aborted and the
6257 2. With the -c/--check option, the update is aborted and the
6258 uncommitted changes are preserved.
6258 uncommitted changes are preserved.
6259
6259
6260 3. With the -C/--clean option, uncommitted changes are discarded and
6260 3. With the -C/--clean option, uncommitted changes are discarded and
6261 the working directory is updated to the requested changeset.
6261 the working directory is updated to the requested changeset.
6262
6262
6263 To cancel an uncommitted merge (and lose your changes), use
6263 To cancel an uncommitted merge (and lose your changes), use
6264 :hg:`update --clean .`.
6264 :hg:`update --clean .`.
6265
6265
6266 Use null as the changeset to remove the working directory (like
6266 Use null as the changeset to remove the working directory (like
6267 :hg:`clone -U`).
6267 :hg:`clone -U`).
6268
6268
6269 If you want to revert just one file to an older revision, use
6269 If you want to revert just one file to an older revision, use
6270 :hg:`revert [-r REV] NAME`.
6270 :hg:`revert [-r REV] NAME`.
6271
6271
6272 See :hg:`help dates` for a list of formats valid for -d/--date.
6272 See :hg:`help dates` for a list of formats valid for -d/--date.
6273
6273
6274 Returns 0 on success, 1 if there are unresolved files.
6274 Returns 0 on success, 1 if there are unresolved files.
6275 """
6275 """
6276 if rev and node:
6276 if rev and node:
6277 raise util.Abort(_("please specify just one revision"))
6277 raise util.Abort(_("please specify just one revision"))
6278
6278
6279 if rev is None or rev == '':
6279 if rev is None or rev == '':
6280 rev = node
6280 rev = node
6281
6281
6282 cmdutil.clearunfinished(repo)
6282 cmdutil.clearunfinished(repo)
6283
6283
6284 # with no argument, we also move the current bookmark, if any
6284 # with no argument, we also move the current bookmark, if any
6285 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6285 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6286
6286
6287 # if we defined a bookmark, we have to remember the original bookmark name
6287 # if we defined a bookmark, we have to remember the original bookmark name
6288 brev = rev
6288 brev = rev
6289 rev = scmutil.revsingle(repo, rev, rev).rev()
6289 rev = scmutil.revsingle(repo, rev, rev).rev()
6290
6290
6291 if check and clean:
6291 if check and clean:
6292 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6292 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6293
6293
6294 if date:
6294 if date:
6295 if rev is not None:
6295 if rev is not None:
6296 raise util.Abort(_("you can't specify a revision and a date"))
6296 raise util.Abort(_("you can't specify a revision and a date"))
6297 rev = cmdutil.finddate(ui, repo, date)
6297 rev = cmdutil.finddate(ui, repo, date)
6298
6298
6299 if check:
6299 if check:
6300 c = repo[None]
6300 c = repo[None]
6301 if c.dirty(merge=False, branch=False, missing=True):
6301 if c.dirty(merge=False, branch=False, missing=True):
6302 raise util.Abort(_("uncommitted changes"))
6302 raise util.Abort(_("uncommitted changes"))
6303 if rev is None:
6303 if rev is None:
6304 rev = repo[repo[None].branch()].rev()
6304 rev = repo[repo[None].branch()].rev()
6305
6305
6306 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6306 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6307
6307
6308 if clean:
6308 if clean:
6309 ret = hg.clean(repo, rev)
6309 ret = hg.clean(repo, rev)
6310 else:
6310 else:
6311 ret = hg.update(repo, rev)
6311 ret = hg.update(repo, rev)
6312
6312
6313 if not ret and movemarkfrom:
6313 if not ret and movemarkfrom:
6314 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6314 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6315 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6315 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6316 elif brev in repo._bookmarks:
6316 elif brev in repo._bookmarks:
6317 bookmarks.setcurrent(repo, brev)
6317 bookmarks.setcurrent(repo, brev)
6318 ui.status(_("(activating bookmark %s)\n") % brev)
6318 ui.status(_("(activating bookmark %s)\n") % brev)
6319 elif brev:
6319 elif brev:
6320 if repo._bookmarkcurrent:
6320 if repo._bookmarkcurrent:
6321 ui.status(_("(leaving bookmark %s)\n") %
6321 ui.status(_("(leaving bookmark %s)\n") %
6322 repo._bookmarkcurrent)
6322 repo._bookmarkcurrent)
6323 bookmarks.unsetcurrent(repo)
6323 bookmarks.unsetcurrent(repo)
6324
6324
6325 return ret
6325 return ret
6326
6326
6327 @command('verify', [])
6327 @command('verify', [])
6328 def verify(ui, repo):
6328 def verify(ui, repo):
6329 """verify the integrity of the repository
6329 """verify the integrity of the repository
6330
6330
6331 Verify the integrity of the current repository.
6331 Verify the integrity of the current repository.
6332
6332
6333 This will perform an extensive check of the repository's
6333 This will perform an extensive check of the repository's
6334 integrity, validating the hashes and checksums of each entry in
6334 integrity, validating the hashes and checksums of each entry in
6335 the changelog, manifest, and tracked files, as well as the
6335 the changelog, manifest, and tracked files, as well as the
6336 integrity of their crosslinks and indices.
6336 integrity of their crosslinks and indices.
6337
6337
6338 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6338 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6339 for more information about recovery from corruption of the
6339 for more information about recovery from corruption of the
6340 repository.
6340 repository.
6341
6341
6342 Returns 0 on success, 1 if errors are encountered.
6342 Returns 0 on success, 1 if errors are encountered.
6343 """
6343 """
6344 return hg.verify(repo)
6344 return hg.verify(repo)
6345
6345
6346 @command('version', [], norepo=True)
6346 @command('version', [], norepo=True)
6347 def version_(ui):
6347 def version_(ui):
6348 """output version and copyright information"""
6348 """output version and copyright information"""
6349 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6349 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6350 % util.version())
6350 % util.version())
6351 ui.status(_(
6351 ui.status(_(
6352 "(see http://mercurial.selenic.com for more information)\n"
6352 "(see http://mercurial.selenic.com for more information)\n"
6353 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6353 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6354 "This is free software; see the source for copying conditions. "
6354 "This is free software; see the source for copying conditions. "
6355 "There is NO\nwarranty; "
6355 "There is NO\nwarranty; "
6356 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6356 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6357 ))
6357 ))
6358
6358
6359 ui.note(_("\nEnabled extensions:\n\n"))
6359 ui.note(_("\nEnabled extensions:\n\n"))
6360 if ui.verbose:
6360 if ui.verbose:
6361 # format names and versions into columns
6361 # format names and versions into columns
6362 names = []
6362 names = []
6363 vers = []
6363 vers = []
6364 for name, module in extensions.extensions():
6364 for name, module in extensions.extensions():
6365 names.append(name)
6365 names.append(name)
6366 vers.append(extensions.moduleversion(module))
6366 vers.append(extensions.moduleversion(module))
6367 if names:
6367 if names:
6368 maxnamelen = max(len(n) for n in names)
6368 maxnamelen = max(len(n) for n in names)
6369 for i, name in enumerate(names):
6369 for i, name in enumerate(names):
6370 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
6370 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
@@ -1,431 +1,431 b''
1 #require serve
1 #require serve
2
2
3 $ echo "[extensions]" >> $HGRCPATH
3 $ echo "[extensions]" >> $HGRCPATH
4 $ echo "fetch=" >> $HGRCPATH
4 $ echo "fetch=" >> $HGRCPATH
5
5
6 test fetch with default branches only
6 test fetch with default branches only
7
7
8 $ hg init a
8 $ hg init a
9 $ echo a > a/a
9 $ echo a > a/a
10 $ hg --cwd a commit -Ama
10 $ hg --cwd a commit -Ama
11 adding a
11 adding a
12 $ hg clone a b
12 $ hg clone a b
13 updating to branch default
13 updating to branch default
14 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
14 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
15 $ hg clone a c
15 $ hg clone a c
16 updating to branch default
16 updating to branch default
17 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
17 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
18 $ echo b > a/b
18 $ echo b > a/b
19 $ hg --cwd a commit -Amb
19 $ hg --cwd a commit -Amb
20 adding b
20 adding b
21 $ hg --cwd a parents -q
21 $ hg --cwd a parents -q
22 1:d2ae7f538514
22 1:d2ae7f538514
23
23
24 should pull one change
24 should pull one change
25
25
26 $ hg --cwd b fetch ../a
26 $ hg --cwd b fetch ../a
27 pulling from ../a
27 pulling from ../a
28 searching for changes
28 searching for changes
29 adding changesets
29 adding changesets
30 adding manifests
30 adding manifests
31 adding file changes
31 adding file changes
32 added 1 changesets with 1 changes to 1 files
32 added 1 changesets with 1 changes to 1 files
33 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
33 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
34 $ hg --cwd b parents -q
34 $ hg --cwd b parents -q
35 1:d2ae7f538514
35 1:d2ae7f538514
36 $ echo c > c/c
36 $ echo c > c/c
37 $ hg --cwd c commit -Amc
37 $ hg --cwd c commit -Amc
38 adding c
38 adding c
39 $ hg clone c d
39 $ hg clone c d
40 updating to branch default
40 updating to branch default
41 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
41 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
42 $ hg clone c e
42 $ hg clone c e
43 updating to branch default
43 updating to branch default
44 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
44 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
45
45
46 We cannot use the default commit message if fetching from a local
46 We cannot use the default commit message if fetching from a local
47 repo, because the path of the repo will be included in the commit
47 repo, because the path of the repo will be included in the commit
48 message, making every commit appear different.
48 message, making every commit appear different.
49 should merge c into a
49 should merge c into a
50
50
51 $ hg --cwd c fetch -d '0 0' -m 'automated merge' ../a
51 $ hg --cwd c fetch -d '0 0' -m 'automated merge' ../a
52 pulling from ../a
52 pulling from ../a
53 searching for changes
53 searching for changes
54 adding changesets
54 adding changesets
55 adding manifests
55 adding manifests
56 adding file changes
56 adding file changes
57 added 1 changesets with 1 changes to 1 files (+1 heads)
57 added 1 changesets with 1 changes to 1 files (+1 heads)
58 updating to 2:d2ae7f538514
58 updating to 2:d2ae7f538514
59 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
59 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
60 merging with 1:d36c0562f908
60 merging with 1:d36c0562f908
61 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
61 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
62 new changeset 3:a323a0c43ec4 merges remote changes with local
62 new changeset 3:a323a0c43ec4 merges remote changes with local
63 $ ls c
63 $ ls c
64 a
64 a
65 b
65 b
66 c
66 c
67 $ hg --cwd a serve -a localhost -p $HGPORT -d --pid-file=hg.pid
67 $ hg --cwd a serve -a localhost -p $HGPORT -d --pid-file=hg.pid
68 $ cat a/hg.pid >> "$DAEMON_PIDS"
68 $ cat a/hg.pid >> "$DAEMON_PIDS"
69
69
70 fetch over http, no auth
70 fetch over http, no auth
71 (this also tests that editor is invoked if '--edit' is specified)
71 (this also tests that editor is invoked if '--edit' is specified)
72
72
73 $ HGEDITOR=cat hg --cwd d fetch --edit http://localhost:$HGPORT/
73 $ HGEDITOR=cat hg --cwd d fetch --edit http://localhost:$HGPORT/
74 pulling from http://localhost:$HGPORT/
74 pulling from http://localhost:$HGPORT/
75 searching for changes
75 searching for changes
76 adding changesets
76 adding changesets
77 adding manifests
77 adding manifests
78 adding file changes
78 adding file changes
79 added 1 changesets with 1 changes to 1 files (+1 heads)
79 added 1 changesets with 1 changes to 1 files (+1 heads)
80 updating to 2:d2ae7f538514
80 updating to 2:d2ae7f538514
81 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
81 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
82 merging with 1:d36c0562f908
82 merging with 1:d36c0562f908
83 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
83 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
84 Automated merge with http://localhost:$HGPORT/
84 Automated merge with http://localhost:$HGPORT/
85
85
86
86
87 HG: Enter commit message. Lines beginning with 'HG:' are removed.
87 HG: Enter commit message. Lines beginning with 'HG:' are removed.
88 HG: Leave message empty to abort commit.
88 HG: Leave message empty to abort commit.
89 HG: --
89 HG: --
90 HG: user: test
90 HG: user: test
91 HG: branch merge
91 HG: branch merge
92 HG: branch 'default'
92 HG: branch 'default'
93 HG: changed c
93 HG: changed c
94 new changeset 3:* merges remote changes with local (glob)
94 new changeset 3:* merges remote changes with local (glob)
95 $ hg --cwd d tip --template '{desc}\n'
95 $ hg --cwd d tip --template '{desc}\n'
96 Automated merge with http://localhost:$HGPORT/
96 Automated merge with http://localhost:$HGPORT/
97 $ hg --cwd d status --rev 'tip^1' --rev tip
97 $ hg --cwd d status --rev 'tip^1' --rev tip
98 A c
98 A c
99 $ hg --cwd d status --rev 'tip^2' --rev tip
99 $ hg --cwd d status --rev 'tip^2' --rev tip
100 A b
100 A b
101
101
102 fetch over http with auth (should be hidden in desc)
102 fetch over http with auth (should be hidden in desc)
103 (this also tests that editor is not invoked if '--edit' is not
103 (this also tests that editor is not invoked if '--edit' is not
104 specified, even though commit message is not specified explicitly)
104 specified, even though commit message is not specified explicitly)
105
105
106 $ HGEDITOR=cat hg --cwd e fetch http://user:password@localhost:$HGPORT/
106 $ HGEDITOR=cat hg --cwd e fetch http://user:password@localhost:$HGPORT/
107 pulling from http://user:***@localhost:$HGPORT/
107 pulling from http://user:***@localhost:$HGPORT/
108 searching for changes
108 searching for changes
109 adding changesets
109 adding changesets
110 adding manifests
110 adding manifests
111 adding file changes
111 adding file changes
112 added 1 changesets with 1 changes to 1 files (+1 heads)
112 added 1 changesets with 1 changes to 1 files (+1 heads)
113 updating to 2:d2ae7f538514
113 updating to 2:d2ae7f538514
114 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
114 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
115 merging with 1:d36c0562f908
115 merging with 1:d36c0562f908
116 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
116 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
117 new changeset 3:* merges remote changes with local (glob)
117 new changeset 3:* merges remote changes with local (glob)
118 $ hg --cwd e tip --template '{desc}\n'
118 $ hg --cwd e tip --template '{desc}\n'
119 Automated merge with http://localhost:$HGPORT/
119 Automated merge with http://localhost:$HGPORT/
120 $ hg clone a f
120 $ hg clone a f
121 updating to branch default
121 updating to branch default
122 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
122 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
123 $ hg clone a g
123 $ hg clone a g
124 updating to branch default
124 updating to branch default
125 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
125 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
126 $ echo f > f/f
126 $ echo f > f/f
127 $ hg --cwd f ci -Amf
127 $ hg --cwd f ci -Amf
128 adding f
128 adding f
129 $ echo g > g/g
129 $ echo g > g/g
130 $ hg --cwd g ci -Amg
130 $ hg --cwd g ci -Amg
131 adding g
131 adding g
132 $ hg clone -q f h
132 $ hg clone -q f h
133 $ hg clone -q g i
133 $ hg clone -q g i
134
134
135 should merge f into g
135 should merge f into g
136
136
137 $ hg --cwd g fetch -d '0 0' --switch -m 'automated merge' ../f
137 $ hg --cwd g fetch -d '0 0' --switch -m 'automated merge' ../f
138 pulling from ../f
138 pulling from ../f
139 searching for changes
139 searching for changes
140 adding changesets
140 adding changesets
141 adding manifests
141 adding manifests
142 adding file changes
142 adding file changes
143 added 1 changesets with 1 changes to 1 files (+1 heads)
143 added 1 changesets with 1 changes to 1 files (+1 heads)
144 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
144 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
145 merging with 3:6343ca3eff20
145 merging with 3:6343ca3eff20
146 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
146 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
147 new changeset 4:f7faa0b7d3c6 merges remote changes with local
147 new changeset 4:f7faa0b7d3c6 merges remote changes with local
148 $ rm i/g
148 $ rm i/g
149
149
150 should abort, because i is modified
150 should abort, because i is modified
151
151
152 $ hg --cwd i fetch ../h
152 $ hg --cwd i fetch ../h
153 abort: uncommitted changes
153 abort: uncommitted changes
154 [255]
154 [255]
155
155
156 test fetch with named branches
156 test fetch with named branches
157
157
158 $ hg init nbase
158 $ hg init nbase
159 $ echo base > nbase/a
159 $ echo base > nbase/a
160 $ hg -R nbase ci -Am base
160 $ hg -R nbase ci -Am base
161 adding a
161 adding a
162 $ hg -R nbase branch a
162 $ hg -R nbase branch a
163 marked working directory as branch a
163 marked working directory as branch a
164 (branches are permanent and global, did you want a bookmark?)
164 (branches are permanent and global, did you want a bookmark?)
165 $ echo a > nbase/a
165 $ echo a > nbase/a
166 $ hg -R nbase ci -m a
166 $ hg -R nbase ci -m a
167 $ hg -R nbase up -C 0
167 $ hg -R nbase up -C 0
168 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
168 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
169 $ hg -R nbase branch b
169 $ hg -R nbase branch b
170 marked working directory as branch b
170 marked working directory as branch b
171 (branches are permanent and global, did you want a bookmark?)
171 (branches are permanent and global, did you want a bookmark?)
172 $ echo b > nbase/b
172 $ echo b > nbase/b
173 $ hg -R nbase ci -Am b
173 $ hg -R nbase ci -Am b
174 adding b
174 adding b
175
175
176 pull in change on foreign branch
176 pull in change on foreign branch
177
177
178 $ hg clone nbase n1
178 $ hg clone nbase n1
179 updating to branch default
179 updating to branch default
180 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
180 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
181 $ hg clone nbase n2
181 $ hg clone nbase n2
182 updating to branch default
182 updating to branch default
183 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
183 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
184 $ hg -R n1 up -C a
184 $ hg -R n1 up -C a
185 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
185 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
186 $ echo aa > n1/a
186 $ echo aa > n1/a
187 $ hg -R n1 ci -m a1
187 $ hg -R n1 ci -m a1
188 $ hg -R n2 up -C b
188 $ hg -R n2 up -C b
189 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
189 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
190 $ hg -R n2 fetch -m 'merge' n1
190 $ hg -R n2 fetch -m 'merge' n1
191 pulling from n1
191 pulling from n1
192 searching for changes
192 searching for changes
193 adding changesets
193 adding changesets
194 adding manifests
194 adding manifests
195 adding file changes
195 adding file changes
196 added 1 changesets with 1 changes to 1 files
196 added 1 changesets with 1 changes to 1 files
197
197
198 parent should be 2 (no automatic update)
198 parent should be 2 (no automatic update)
199
199
200 $ hg -R n2 parents --template '{rev}\n'
200 $ hg -R n2 parents --template '{rev}\n'
201 2
201 2
202 $ rm -fr n1 n2
202 $ rm -fr n1 n2
203
203
204 pull in changes on both foreign and local branches
204 pull in changes on both foreign and local branches
205
205
206 $ hg clone nbase n1
206 $ hg clone nbase n1
207 updating to branch default
207 updating to branch default
208 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
208 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
209 $ hg clone nbase n2
209 $ hg clone nbase n2
210 updating to branch default
210 updating to branch default
211 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
211 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
212 $ hg -R n1 up -C a
212 $ hg -R n1 up -C a
213 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
213 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
214 $ echo aa > n1/a
214 $ echo aa > n1/a
215 $ hg -R n1 ci -m a1
215 $ hg -R n1 ci -m a1
216 $ hg -R n1 up -C b
216 $ hg -R n1 up -C b
217 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
217 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
218 $ echo bb > n1/b
218 $ echo bb > n1/b
219 $ hg -R n1 ci -m b1
219 $ hg -R n1 ci -m b1
220 $ hg -R n2 up -C b
220 $ hg -R n2 up -C b
221 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
221 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
222 $ hg -R n2 fetch -m 'merge' n1
222 $ hg -R n2 fetch -m 'merge' n1
223 pulling from n1
223 pulling from n1
224 searching for changes
224 searching for changes
225 adding changesets
225 adding changesets
226 adding manifests
226 adding manifests
227 adding file changes
227 adding file changes
228 added 2 changesets with 2 changes to 2 files
228 added 2 changesets with 2 changes to 2 files
229 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
229 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
230
230
231 parent should be 4 (fast forward)
231 parent should be 4 (fast forward)
232
232
233 $ hg -R n2 parents --template '{rev}\n'
233 $ hg -R n2 parents --template '{rev}\n'
234 4
234 4
235 $ rm -fr n1 n2
235 $ rm -fr n1 n2
236
236
237 pull changes on foreign (2 new heads) and local (1 new head) branches
237 pull changes on foreign (2 new heads) and local (1 new head) branches
238 with a local change
238 with a local change
239
239
240 $ hg clone nbase n1
240 $ hg clone nbase n1
241 updating to branch default
241 updating to branch default
242 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
242 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
243 $ hg clone nbase n2
243 $ hg clone nbase n2
244 updating to branch default
244 updating to branch default
245 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
245 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
246 $ hg -R n1 up -C a
246 $ hg -R n1 up -C a
247 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
247 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
248 $ echo a1 > n1/a
248 $ echo a1 > n1/a
249 $ hg -R n1 ci -m a1
249 $ hg -R n1 ci -m a1
250 $ hg -R n1 up -C b
250 $ hg -R n1 up -C b
251 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
251 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
252 $ echo bb > n1/b
252 $ echo bb > n1/b
253 $ hg -R n1 ci -m b1
253 $ hg -R n1 ci -m b1
254 $ hg -R n1 up -C 1
254 $ hg -R n1 up -C 1
255 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
255 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
256 $ echo a2 > n1/a
256 $ echo a2 > n1/a
257 $ hg -R n1 ci -m a2
257 $ hg -R n1 ci -m a2
258 created new head
258 created new head
259 $ hg -R n2 up -C b
259 $ hg -R n2 up -C b
260 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
260 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
261 $ echo change >> n2/c
261 $ echo change >> n2/c
262 $ hg -R n2 ci -A -m local
262 $ hg -R n2 ci -A -m local
263 adding c
263 adding c
264 $ hg -R n2 fetch -d '0 0' -m 'merge' n1
264 $ hg -R n2 fetch -d '0 0' -m 'merge' n1
265 pulling from n1
265 pulling from n1
266 searching for changes
266 searching for changes
267 adding changesets
267 adding changesets
268 adding manifests
268 adding manifests
269 adding file changes
269 adding file changes
270 added 3 changesets with 3 changes to 2 files (+2 heads)
270 added 3 changesets with 3 changes to 2 files (+2 heads)
271 updating to 5:3c4a837a864f
271 updating to 5:3c4a837a864f
272 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
272 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
273 merging with 3:1267f84a9ea5
273 merging with 3:1267f84a9ea5
274 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
274 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
275 new changeset 7:2cf2a1261f21 merges remote changes with local
275 new changeset 7:2cf2a1261f21 merges remote changes with local
276
276
277 parent should be 7 (new merge changeset)
277 parent should be 7 (new merge changeset)
278
278
279 $ hg -R n2 parents --template '{rev}\n'
279 $ hg -R n2 parents --template '{rev}\n'
280 7
280 7
281 $ rm -fr n1 n2
281 $ rm -fr n1 n2
282
282
283 pull in changes on foreign (merge of local branch) and local (2 new
283 pull in changes on foreign (merge of local branch) and local (2 new
284 heads) with a local change
284 heads) with a local change
285
285
286 $ hg clone nbase n1
286 $ hg clone nbase n1
287 updating to branch default
287 updating to branch default
288 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
288 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
289 $ hg clone nbase n2
289 $ hg clone nbase n2
290 updating to branch default
290 updating to branch default
291 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
291 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
292 $ hg -R n1 up -C a
292 $ hg -R n1 up -C a
293 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
293 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
294 $ hg -R n1 merge b
294 $ hg -R n1 merge b
295 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
295 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
296 (branch merge, don't forget to commit)
296 (branch merge, don't forget to commit)
297 $ hg -R n1 ci -m merge
297 $ hg -R n1 ci -m merge
298 $ hg -R n1 up -C 2
298 $ hg -R n1 up -C 2
299 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
299 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
300 $ echo c > n1/a
300 $ echo c > n1/a
301 $ hg -R n1 ci -m c
301 $ hg -R n1 ci -m c
302 $ hg -R n1 up -C 2
302 $ hg -R n1 up -C 2
303 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
303 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
304 $ echo cc > n1/a
304 $ echo cc > n1/a
305 $ hg -R n1 ci -m cc
305 $ hg -R n1 ci -m cc
306 created new head
306 created new head
307 $ hg -R n2 up -C b
307 $ hg -R n2 up -C b
308 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
308 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
309 $ echo change >> n2/b
309 $ echo change >> n2/b
310 $ hg -R n2 ci -A -m local
310 $ hg -R n2 ci -A -m local
311 $ hg -R n2 fetch -m 'merge' n1
311 $ hg -R n2 fetch -m 'merge' n1
312 pulling from n1
312 pulling from n1
313 searching for changes
313 searching for changes
314 adding changesets
314 adding changesets
315 adding manifests
315 adding manifests
316 adding file changes
316 adding file changes
317 added 3 changesets with 2 changes to 1 files (+2 heads)
317 added 3 changesets with 2 changes to 1 files (+2 heads)
318 not merging with 1 other new branch heads (use "hg heads ." and "hg merge" to merge them)
318 not merging with 1 other new branch heads (use "hg heads ." and "hg merge" to merge them)
319 [1]
319 [1]
320
320
321 parent should be 3 (fetch did not merge anything)
321 parent should be 3 (fetch did not merge anything)
322
322
323 $ hg -R n2 parents --template '{rev}\n'
323 $ hg -R n2 parents --template '{rev}\n'
324 3
324 3
325 $ rm -fr n1 n2
325 $ rm -fr n1 n2
326
326
327 pull in change on different branch than dirstate
327 pull in change on different branch than dirstate
328
328
329 $ hg init n1
329 $ hg init n1
330 $ echo a > n1/a
330 $ echo a > n1/a
331 $ hg -R n1 ci -Am initial
331 $ hg -R n1 ci -Am initial
332 adding a
332 adding a
333 $ hg clone n1 n2
333 $ hg clone n1 n2
334 updating to branch default
334 updating to branch default
335 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
335 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
336 $ echo b > n1/a
336 $ echo b > n1/a
337 $ hg -R n1 ci -m next
337 $ hg -R n1 ci -m next
338 $ hg -R n2 branch topic
338 $ hg -R n2 branch topic
339 marked working directory as branch topic
339 marked working directory as branch topic
340 (branches are permanent and global, did you want a bookmark?)
340 (branches are permanent and global, did you want a bookmark?)
341 $ hg -R n2 fetch -m merge n1
341 $ hg -R n2 fetch -m merge n1
342 abort: working dir not at branch tip (use "hg update" to check out branch tip)
342 abort: working directory not at branch tip (use "hg update" to check out branch tip)
343 [255]
343 [255]
344
344
345 parent should be 0 (fetch did not update or merge anything)
345 parent should be 0 (fetch did not update or merge anything)
346
346
347 $ hg -R n2 parents --template '{rev}\n'
347 $ hg -R n2 parents --template '{rev}\n'
348 0
348 0
349 $ rm -fr n1 n2
349 $ rm -fr n1 n2
350
350
351 test fetch with inactive branches
351 test fetch with inactive branches
352
352
353 $ hg init ib1
353 $ hg init ib1
354 $ echo a > ib1/a
354 $ echo a > ib1/a
355 $ hg --cwd ib1 ci -Am base
355 $ hg --cwd ib1 ci -Am base
356 adding a
356 adding a
357 $ hg --cwd ib1 branch second
357 $ hg --cwd ib1 branch second
358 marked working directory as branch second
358 marked working directory as branch second
359 (branches are permanent and global, did you want a bookmark?)
359 (branches are permanent and global, did you want a bookmark?)
360 $ echo b > ib1/b
360 $ echo b > ib1/b
361 $ hg --cwd ib1 ci -Am onsecond
361 $ hg --cwd ib1 ci -Am onsecond
362 adding b
362 adding b
363 $ hg --cwd ib1 branch -f default
363 $ hg --cwd ib1 branch -f default
364 marked working directory as branch default
364 marked working directory as branch default
365 (branches are permanent and global, did you want a bookmark?)
365 (branches are permanent and global, did you want a bookmark?)
366 $ echo c > ib1/c
366 $ echo c > ib1/c
367 $ hg --cwd ib1 ci -Am newdefault
367 $ hg --cwd ib1 ci -Am newdefault
368 adding c
368 adding c
369 created new head
369 created new head
370 $ hg clone ib1 ib2
370 $ hg clone ib1 ib2
371 updating to branch default
371 updating to branch default
372 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
372 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
373
373
374 fetch should succeed
374 fetch should succeed
375
375
376 $ hg --cwd ib2 fetch ../ib1
376 $ hg --cwd ib2 fetch ../ib1
377 pulling from ../ib1
377 pulling from ../ib1
378 searching for changes
378 searching for changes
379 no changes found
379 no changes found
380 $ rm -fr ib1 ib2
380 $ rm -fr ib1 ib2
381
381
382 test issue1726
382 test issue1726
383
383
384 $ hg init i1726r1
384 $ hg init i1726r1
385 $ echo a > i1726r1/a
385 $ echo a > i1726r1/a
386 $ hg --cwd i1726r1 ci -Am base
386 $ hg --cwd i1726r1 ci -Am base
387 adding a
387 adding a
388 $ hg clone i1726r1 i1726r2
388 $ hg clone i1726r1 i1726r2
389 updating to branch default
389 updating to branch default
390 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
390 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
391 $ echo b > i1726r1/a
391 $ echo b > i1726r1/a
392 $ hg --cwd i1726r1 ci -m second
392 $ hg --cwd i1726r1 ci -m second
393 $ echo c > i1726r2/a
393 $ echo c > i1726r2/a
394 $ hg --cwd i1726r2 ci -m third
394 $ hg --cwd i1726r2 ci -m third
395 $ HGMERGE=true hg --cwd i1726r2 fetch ../i1726r1
395 $ HGMERGE=true hg --cwd i1726r2 fetch ../i1726r1
396 pulling from ../i1726r1
396 pulling from ../i1726r1
397 searching for changes
397 searching for changes
398 adding changesets
398 adding changesets
399 adding manifests
399 adding manifests
400 adding file changes
400 adding file changes
401 added 1 changesets with 1 changes to 1 files (+1 heads)
401 added 1 changesets with 1 changes to 1 files (+1 heads)
402 updating to 2:7837755a2789
402 updating to 2:7837755a2789
403 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
403 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
404 merging with 1:d1f0c6c48ebd
404 merging with 1:d1f0c6c48ebd
405 merging a
405 merging a
406 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
406 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
407 new changeset 3:* merges remote changes with local (glob)
407 new changeset 3:* merges remote changes with local (glob)
408 $ hg --cwd i1726r2 heads default --template '{rev}\n'
408 $ hg --cwd i1726r2 heads default --template '{rev}\n'
409 3
409 3
410
410
411 test issue2047
411 test issue2047
412
412
413 $ hg -q init i2047a
413 $ hg -q init i2047a
414 $ cd i2047a
414 $ cd i2047a
415 $ echo a > a
415 $ echo a > a
416 $ hg -q ci -Am a
416 $ hg -q ci -Am a
417 $ hg -q branch stable
417 $ hg -q branch stable
418 $ echo b > b
418 $ echo b > b
419 $ hg -q ci -Am b
419 $ hg -q ci -Am b
420 $ cd ..
420 $ cd ..
421 $ hg -q clone -r 0 i2047a i2047b
421 $ hg -q clone -r 0 i2047a i2047b
422 $ cd i2047b
422 $ cd i2047b
423 $ hg fetch ../i2047a
423 $ hg fetch ../i2047a
424 pulling from ../i2047a
424 pulling from ../i2047a
425 searching for changes
425 searching for changes
426 adding changesets
426 adding changesets
427 adding manifests
427 adding manifests
428 adding file changes
428 adding file changes
429 added 1 changesets with 1 changes to 1 files
429 added 1 changesets with 1 changes to 1 files
430
430
431 $ cd ..
431 $ cd ..
@@ -1,211 +1,211 b''
1
1
2 Test interactions between mq and patch.eol
2 Test interactions between mq and patch.eol
3
3
4
4
5 $ cat <<EOF >> $HGRCPATH
5 $ cat <<EOF >> $HGRCPATH
6 > [extensions]
6 > [extensions]
7 > mq =
7 > mq =
8 > [diff]
8 > [diff]
9 > nodates = 1
9 > nodates = 1
10 > EOF
10 > EOF
11
11
12 $ cat > makepatch.py <<EOF
12 $ cat > makepatch.py <<EOF
13 > f = file('eol.diff', 'wb')
13 > f = file('eol.diff', 'wb')
14 > w = f.write
14 > w = f.write
15 > w('test message\n')
15 > w('test message\n')
16 > w('diff --git a/a b/a\n')
16 > w('diff --git a/a b/a\n')
17 > w('--- a/a\n')
17 > w('--- a/a\n')
18 > w('+++ b/a\n')
18 > w('+++ b/a\n')
19 > w('@@ -1,5 +1,5 @@\n')
19 > w('@@ -1,5 +1,5 @@\n')
20 > w(' a\n')
20 > w(' a\n')
21 > w('-b\r\n')
21 > w('-b\r\n')
22 > w('+y\r\n')
22 > w('+y\r\n')
23 > w(' c\r\n')
23 > w(' c\r\n')
24 > w(' d\n')
24 > w(' d\n')
25 > w('-e\n')
25 > w('-e\n')
26 > w('\ No newline at end of file\n')
26 > w('\ No newline at end of file\n')
27 > w('+z\r\n')
27 > w('+z\r\n')
28 > w('\ No newline at end of file\r\n')
28 > w('\ No newline at end of file\r\n')
29 > EOF
29 > EOF
30
30
31 $ cat > cateol.py <<EOF
31 $ cat > cateol.py <<EOF
32 > import sys
32 > import sys
33 > for line in file(sys.argv[1], 'rb'):
33 > for line in file(sys.argv[1], 'rb'):
34 > line = line.replace('\r', '<CR>')
34 > line = line.replace('\r', '<CR>')
35 > line = line.replace('\n', '<LF>')
35 > line = line.replace('\n', '<LF>')
36 > print line
36 > print line
37 > EOF
37 > EOF
38
38
39 $ hg init repo
39 $ hg init repo
40 $ cd repo
40 $ cd repo
41 $ echo '\.diff' > .hgignore
41 $ echo '\.diff' > .hgignore
42 $ echo '\.rej' >> .hgignore
42 $ echo '\.rej' >> .hgignore
43
43
44
44
45 Test different --eol values
45 Test different --eol values
46
46
47 $ $PYTHON -c 'file("a", "wb").write("a\nb\nc\nd\ne")'
47 $ $PYTHON -c 'file("a", "wb").write("a\nb\nc\nd\ne")'
48 $ hg ci -Am adda
48 $ hg ci -Am adda
49 adding .hgignore
49 adding .hgignore
50 adding a
50 adding a
51 $ python ../makepatch.py
51 $ python ../makepatch.py
52 $ hg qimport eol.diff
52 $ hg qimport eol.diff
53 adding eol.diff to series file
53 adding eol.diff to series file
54
54
55 should fail in strict mode
55 should fail in strict mode
56
56
57 $ hg qpush
57 $ hg qpush
58 applying eol.diff
58 applying eol.diff
59 patching file a
59 patching file a
60 Hunk #1 FAILED at 0
60 Hunk #1 FAILED at 0
61 1 out of 1 hunks FAILED -- saving rejects to file a.rej
61 1 out of 1 hunks FAILED -- saving rejects to file a.rej
62 patch failed, unable to continue (try -v)
62 patch failed, unable to continue (try -v)
63 patch failed, rejects left in working dir
63 patch failed, rejects left in working directory
64 errors during apply, please fix and refresh eol.diff
64 errors during apply, please fix and refresh eol.diff
65 [2]
65 [2]
66 $ hg qpop
66 $ hg qpop
67 popping eol.diff
67 popping eol.diff
68 patch queue now empty
68 patch queue now empty
69
69
70 invalid eol
70 invalid eol
71
71
72 $ hg --config patch.eol='LFCR' qpush
72 $ hg --config patch.eol='LFCR' qpush
73 applying eol.diff
73 applying eol.diff
74 patch failed, unable to continue (try -v)
74 patch failed, unable to continue (try -v)
75 patch failed, rejects left in working dir
75 patch failed, rejects left in working directory
76 errors during apply, please fix and refresh eol.diff
76 errors during apply, please fix and refresh eol.diff
77 [2]
77 [2]
78 $ hg qpop
78 $ hg qpop
79 popping eol.diff
79 popping eol.diff
80 patch queue now empty
80 patch queue now empty
81
81
82 force LF
82 force LF
83
83
84 $ hg --config patch.eol='CRLF' qpush
84 $ hg --config patch.eol='CRLF' qpush
85 applying eol.diff
85 applying eol.diff
86 now at: eol.diff
86 now at: eol.diff
87 $ hg qrefresh
87 $ hg qrefresh
88 $ python ../cateol.py .hg/patches/eol.diff
88 $ python ../cateol.py .hg/patches/eol.diff
89 # HG changeset patch<LF>
89 # HG changeset patch<LF>
90 # Parent 0d0bf99a8b7a3842c6f8ef09e34f69156c4bd9d0<LF>
90 # Parent 0d0bf99a8b7a3842c6f8ef09e34f69156c4bd9d0<LF>
91 test message<LF>
91 test message<LF>
92 <LF>
92 <LF>
93 diff -r 0d0bf99a8b7a a<LF>
93 diff -r 0d0bf99a8b7a a<LF>
94 --- a/a<LF>
94 --- a/a<LF>
95 +++ b/a<LF>
95 +++ b/a<LF>
96 @@ -1,5 +1,5 @@<LF>
96 @@ -1,5 +1,5 @@<LF>
97 -a<LF>
97 -a<LF>
98 -b<LF>
98 -b<LF>
99 -c<LF>
99 -c<LF>
100 -d<LF>
100 -d<LF>
101 -e<LF>
101 -e<LF>
102 \ No newline at end of file<LF>
102 \ No newline at end of file<LF>
103 +a<CR><LF>
103 +a<CR><LF>
104 +y<CR><LF>
104 +y<CR><LF>
105 +c<CR><LF>
105 +c<CR><LF>
106 +d<CR><LF>
106 +d<CR><LF>
107 +z<LF>
107 +z<LF>
108 \ No newline at end of file<LF>
108 \ No newline at end of file<LF>
109 $ python ../cateol.py a
109 $ python ../cateol.py a
110 a<CR><LF>
110 a<CR><LF>
111 y<CR><LF>
111 y<CR><LF>
112 c<CR><LF>
112 c<CR><LF>
113 d<CR><LF>
113 d<CR><LF>
114 z
114 z
115 $ hg qpop
115 $ hg qpop
116 popping eol.diff
116 popping eol.diff
117 patch queue now empty
117 patch queue now empty
118
118
119 push again forcing LF and compare revisions
119 push again forcing LF and compare revisions
120
120
121 $ hg --config patch.eol='CRLF' qpush
121 $ hg --config patch.eol='CRLF' qpush
122 applying eol.diff
122 applying eol.diff
123 now at: eol.diff
123 now at: eol.diff
124 $ python ../cateol.py a
124 $ python ../cateol.py a
125 a<CR><LF>
125 a<CR><LF>
126 y<CR><LF>
126 y<CR><LF>
127 c<CR><LF>
127 c<CR><LF>
128 d<CR><LF>
128 d<CR><LF>
129 z
129 z
130 $ hg qpop
130 $ hg qpop
131 popping eol.diff
131 popping eol.diff
132 patch queue now empty
132 patch queue now empty
133
133
134 push again without LF and compare revisions
134 push again without LF and compare revisions
135
135
136 $ hg qpush
136 $ hg qpush
137 applying eol.diff
137 applying eol.diff
138 now at: eol.diff
138 now at: eol.diff
139 $ python ../cateol.py a
139 $ python ../cateol.py a
140 a<CR><LF>
140 a<CR><LF>
141 y<CR><LF>
141 y<CR><LF>
142 c<CR><LF>
142 c<CR><LF>
143 d<CR><LF>
143 d<CR><LF>
144 z
144 z
145 $ hg qpop
145 $ hg qpop
146 popping eol.diff
146 popping eol.diff
147 patch queue now empty
147 patch queue now empty
148 $ cd ..
148 $ cd ..
149
149
150
150
151 Test .rej file EOL are left unchanged
151 Test .rej file EOL are left unchanged
152
152
153 $ hg init testeol
153 $ hg init testeol
154 $ cd testeol
154 $ cd testeol
155 $ $PYTHON -c "file('a', 'wb').write('1\r\n2\r\n3\r\n4')"
155 $ $PYTHON -c "file('a', 'wb').write('1\r\n2\r\n3\r\n4')"
156 $ hg ci -Am adda
156 $ hg ci -Am adda
157 adding a
157 adding a
158 $ $PYTHON -c "file('a', 'wb').write('1\r\n2\r\n33\r\n4')"
158 $ $PYTHON -c "file('a', 'wb').write('1\r\n2\r\n33\r\n4')"
159 $ hg qnew patch1
159 $ hg qnew patch1
160 $ hg qpop
160 $ hg qpop
161 popping patch1
161 popping patch1
162 patch queue now empty
162 patch queue now empty
163 $ $PYTHON -c "file('a', 'wb').write('1\r\n22\r\n33\r\n4')"
163 $ $PYTHON -c "file('a', 'wb').write('1\r\n22\r\n33\r\n4')"
164 $ hg ci -m changea
164 $ hg ci -m changea
165
165
166 $ hg --config 'patch.eol=LF' qpush
166 $ hg --config 'patch.eol=LF' qpush
167 applying patch1
167 applying patch1
168 patching file a
168 patching file a
169 Hunk #1 FAILED at 0
169 Hunk #1 FAILED at 0
170 1 out of 1 hunks FAILED -- saving rejects to file a.rej
170 1 out of 1 hunks FAILED -- saving rejects to file a.rej
171 patch failed, unable to continue (try -v)
171 patch failed, unable to continue (try -v)
172 patch failed, rejects left in working dir
172 patch failed, rejects left in working directory
173 errors during apply, please fix and refresh patch1
173 errors during apply, please fix and refresh patch1
174 [2]
174 [2]
175 $ hg qpop
175 $ hg qpop
176 popping patch1
176 popping patch1
177 patch queue now empty
177 patch queue now empty
178 $ cat a.rej
178 $ cat a.rej
179 --- a
179 --- a
180 +++ a
180 +++ a
181 @@ -1,4 +1,4 @@
181 @@ -1,4 +1,4 @@
182 1\r (esc)
182 1\r (esc)
183 2\r (esc)
183 2\r (esc)
184 -3\r (esc)
184 -3\r (esc)
185 +33\r (esc)
185 +33\r (esc)
186 4
186 4
187 \ No newline at end of file
187 \ No newline at end of file
188
188
189 $ hg --config 'patch.eol=auto' qpush
189 $ hg --config 'patch.eol=auto' qpush
190 applying patch1
190 applying patch1
191 patching file a
191 patching file a
192 Hunk #1 FAILED at 0
192 Hunk #1 FAILED at 0
193 1 out of 1 hunks FAILED -- saving rejects to file a.rej
193 1 out of 1 hunks FAILED -- saving rejects to file a.rej
194 patch failed, unable to continue (try -v)
194 patch failed, unable to continue (try -v)
195 patch failed, rejects left in working dir
195 patch failed, rejects left in working directory
196 errors during apply, please fix and refresh patch1
196 errors during apply, please fix and refresh patch1
197 [2]
197 [2]
198 $ hg qpop
198 $ hg qpop
199 popping patch1
199 popping patch1
200 patch queue now empty
200 patch queue now empty
201 $ cat a.rej
201 $ cat a.rej
202 --- a
202 --- a
203 +++ a
203 +++ a
204 @@ -1,4 +1,4 @@
204 @@ -1,4 +1,4 @@
205 1\r (esc)
205 1\r (esc)
206 2\r (esc)
206 2\r (esc)
207 -3\r (esc)
207 -3\r (esc)
208 +33\r (esc)
208 +33\r (esc)
209 4
209 4
210 \ No newline at end of file
210 \ No newline at end of file
211 $ cd ..
211 $ cd ..
@@ -1,195 +1,195 b''
1
1
2 Issue835: qpush fails immediately when patching a missing file, but
2 Issue835: qpush fails immediately when patching a missing file, but
3 remaining added files are still created empty which will trick a
3 remaining added files are still created empty which will trick a
4 future qrefresh.
4 future qrefresh.
5
5
6 $ cat > writelines.py <<EOF
6 $ cat > writelines.py <<EOF
7 > import sys
7 > import sys
8 > path = sys.argv[1]
8 > path = sys.argv[1]
9 > args = sys.argv[2:]
9 > args = sys.argv[2:]
10 > assert (len(args) % 2) == 0
10 > assert (len(args) % 2) == 0
11 >
11 >
12 > f = file(path, 'wb')
12 > f = file(path, 'wb')
13 > for i in xrange(len(args)/2):
13 > for i in xrange(len(args)/2):
14 > count, s = args[2*i:2*i+2]
14 > count, s = args[2*i:2*i+2]
15 > count = int(count)
15 > count = int(count)
16 > s = s.decode('string_escape')
16 > s = s.decode('string_escape')
17 > f.write(s*count)
17 > f.write(s*count)
18 > f.close()
18 > f.close()
19 > EOF
19 > EOF
20
20
21 $ echo "[extensions]" >> $HGRCPATH
21 $ echo "[extensions]" >> $HGRCPATH
22 $ echo "mq=" >> $HGRCPATH
22 $ echo "mq=" >> $HGRCPATH
23
23
24 $ hg init normal
24 $ hg init normal
25 $ cd normal
25 $ cd normal
26 $ python ../writelines.py b 10 'a\n'
26 $ python ../writelines.py b 10 'a\n'
27 $ hg ci -Am addb
27 $ hg ci -Am addb
28 adding b
28 adding b
29 $ echo a > a
29 $ echo a > a
30 $ python ../writelines.py b 2 'b\n' 10 'a\n' 2 'c\n'
30 $ python ../writelines.py b 2 'b\n' 10 'a\n' 2 'c\n'
31 $ echo c > c
31 $ echo c > c
32 $ hg add a c
32 $ hg add a c
33 $ hg qnew -f changeb
33 $ hg qnew -f changeb
34 $ hg qpop
34 $ hg qpop
35 popping changeb
35 popping changeb
36 patch queue now empty
36 patch queue now empty
37 $ hg rm b
37 $ hg rm b
38 $ hg ci -Am rmb
38 $ hg ci -Am rmb
39
39
40 Push patch with missing target:
40 Push patch with missing target:
41
41
42 $ hg qpush
42 $ hg qpush
43 applying changeb
43 applying changeb
44 unable to find 'b' for patching
44 unable to find 'b' for patching
45 2 out of 2 hunks FAILED -- saving rejects to file b.rej
45 2 out of 2 hunks FAILED -- saving rejects to file b.rej
46 patch failed, unable to continue (try -v)
46 patch failed, unable to continue (try -v)
47 patch failed, rejects left in working dir
47 patch failed, rejects left in working directory
48 errors during apply, please fix and refresh changeb
48 errors during apply, please fix and refresh changeb
49 [2]
49 [2]
50
50
51 Display added files:
51 Display added files:
52
52
53 $ cat a
53 $ cat a
54 a
54 a
55 $ cat c
55 $ cat c
56 c
56 c
57
57
58 Display rejections:
58 Display rejections:
59
59
60 $ cat b.rej
60 $ cat b.rej
61 --- b
61 --- b
62 +++ b
62 +++ b
63 @@ -1,3 +1,5 @@
63 @@ -1,3 +1,5 @@
64 +b
64 +b
65 +b
65 +b
66 a
66 a
67 a
67 a
68 a
68 a
69 @@ -8,3 +10,5 @@
69 @@ -8,3 +10,5 @@
70 a
70 a
71 a
71 a
72 a
72 a
73 +c
73 +c
74 +c
74 +c
75
75
76 Test missing renamed file
76 Test missing renamed file
77
77
78 $ hg qpop
78 $ hg qpop
79 popping changeb
79 popping changeb
80 patch queue now empty
80 patch queue now empty
81 $ hg up -qC 0
81 $ hg up -qC 0
82 $ echo a > a
82 $ echo a > a
83 $ hg mv b bb
83 $ hg mv b bb
84 $ python ../writelines.py bb 2 'b\n' 10 'a\n' 2 'c\n'
84 $ python ../writelines.py bb 2 'b\n' 10 'a\n' 2 'c\n'
85 $ echo c > c
85 $ echo c > c
86 $ hg add a c
86 $ hg add a c
87 $ hg qnew changebb
87 $ hg qnew changebb
88 $ hg qpop
88 $ hg qpop
89 popping changebb
89 popping changebb
90 patch queue now empty
90 patch queue now empty
91 $ hg up -qC 1
91 $ hg up -qC 1
92 $ hg qpush
92 $ hg qpush
93 applying changebb
93 applying changebb
94 patching file bb
94 patching file bb
95 Hunk #1 FAILED at 0
95 Hunk #1 FAILED at 0
96 Hunk #2 FAILED at 7
96 Hunk #2 FAILED at 7
97 2 out of 2 hunks FAILED -- saving rejects to file bb.rej
97 2 out of 2 hunks FAILED -- saving rejects to file bb.rej
98 b not tracked!
98 b not tracked!
99 patch failed, unable to continue (try -v)
99 patch failed, unable to continue (try -v)
100 patch failed, rejects left in working dir
100 patch failed, rejects left in working directory
101 errors during apply, please fix and refresh changebb
101 errors during apply, please fix and refresh changebb
102 [2]
102 [2]
103 $ cat a
103 $ cat a
104 a
104 a
105 $ cat c
105 $ cat c
106 c
106 c
107 $ cat bb.rej
107 $ cat bb.rej
108 --- bb
108 --- bb
109 +++ bb
109 +++ bb
110 @@ -1,3 +1,5 @@
110 @@ -1,3 +1,5 @@
111 +b
111 +b
112 +b
112 +b
113 a
113 a
114 a
114 a
115 a
115 a
116 @@ -8,3 +10,5 @@
116 @@ -8,3 +10,5 @@
117 a
117 a
118 a
118 a
119 a
119 a
120 +c
120 +c
121 +c
121 +c
122
122
123 $ cd ..
123 $ cd ..
124
124
125
125
126 $ echo "[diff]" >> $HGRCPATH
126 $ echo "[diff]" >> $HGRCPATH
127 $ echo "git=1" >> $HGRCPATH
127 $ echo "git=1" >> $HGRCPATH
128
128
129 $ hg init git
129 $ hg init git
130 $ cd git
130 $ cd git
131 $ python ../writelines.py b 1 '\x00'
131 $ python ../writelines.py b 1 '\x00'
132 $ hg ci -Am addb
132 $ hg ci -Am addb
133 adding b
133 adding b
134 $ echo a > a
134 $ echo a > a
135 $ python ../writelines.py b 1 '\x01' 1 '\x00'
135 $ python ../writelines.py b 1 '\x01' 1 '\x00'
136 $ echo c > c
136 $ echo c > c
137 $ hg add a c
137 $ hg add a c
138 $ hg qnew -f changeb
138 $ hg qnew -f changeb
139 $ hg qpop
139 $ hg qpop
140 popping changeb
140 popping changeb
141 patch queue now empty
141 patch queue now empty
142 $ hg rm b
142 $ hg rm b
143 $ hg ci -Am rmb
143 $ hg ci -Am rmb
144
144
145 Push git patch with missing target:
145 Push git patch with missing target:
146
146
147 $ hg qpush
147 $ hg qpush
148 applying changeb
148 applying changeb
149 unable to find 'b' for patching
149 unable to find 'b' for patching
150 1 out of 1 hunks FAILED -- saving rejects to file b.rej
150 1 out of 1 hunks FAILED -- saving rejects to file b.rej
151 patch failed, unable to continue (try -v)
151 patch failed, unable to continue (try -v)
152 patch failed, rejects left in working dir
152 patch failed, rejects left in working directory
153 errors during apply, please fix and refresh changeb
153 errors during apply, please fix and refresh changeb
154 [2]
154 [2]
155 $ hg st
155 $ hg st
156 ? b.rej
156 ? b.rej
157
157
158 Display added files:
158 Display added files:
159
159
160 $ cat a
160 $ cat a
161 a
161 a
162 $ cat c
162 $ cat c
163 c
163 c
164
164
165 Display rejections:
165 Display rejections:
166
166
167 $ cat b.rej
167 $ cat b.rej
168 --- b
168 --- b
169 +++ b
169 +++ b
170 GIT binary patch
170 GIT binary patch
171 literal 2
171 literal 2
172 Jc${No0000400IC2
172 Jc${No0000400IC2
173
173
174 $ cd ..
174 $ cd ..
175
175
176 Test push creating directory during git copy or rename:
176 Test push creating directory during git copy or rename:
177
177
178 $ hg init missingdir
178 $ hg init missingdir
179 $ cd missingdir
179 $ cd missingdir
180 $ echo a > a
180 $ echo a > a
181 $ hg ci -Am adda
181 $ hg ci -Am adda
182 adding a
182 adding a
183 $ mkdir d
183 $ mkdir d
184 $ hg copy a d/a2
184 $ hg copy a d/a2
185 $ hg mv a d/a
185 $ hg mv a d/a
186 $ hg qnew -g -f patch
186 $ hg qnew -g -f patch
187 $ hg qpop
187 $ hg qpop
188 popping patch
188 popping patch
189 patch queue now empty
189 patch queue now empty
190 $ hg qpush
190 $ hg qpush
191 applying patch
191 applying patch
192 now at: patch
192 now at: patch
193
193
194 $ cd ..
194 $ cd ..
195
195
@@ -1,289 +1,289 b''
1 $ echo "[extensions]" >> $HGRCPATH
1 $ echo "[extensions]" >> $HGRCPATH
2 $ echo "mq=" >> $HGRCPATH
2 $ echo "mq=" >> $HGRCPATH
3
3
4 make a test repository that looks like this:
4 make a test repository that looks like this:
5
5
6 o 2:28bc7b1afd6a
6 o 2:28bc7b1afd6a
7 |
7 |
8 | @ 1:d7fe2034f71b
8 | @ 1:d7fe2034f71b
9 |/
9 |/
10 o 0/62ecad8b70e5
10 o 0/62ecad8b70e5
11
11
12 $ hg init r0
12 $ hg init r0
13 $ cd r0
13 $ cd r0
14 $ touch f0
14 $ touch f0
15 $ hg ci -m0 -Aq
15 $ hg ci -m0 -Aq
16 $ touch f1
16 $ touch f1
17 $ hg ci -m1 -Aq
17 $ hg ci -m1 -Aq
18
18
19 $ hg update 0 -q
19 $ hg update 0 -q
20 $ touch f2
20 $ touch f2
21 $ hg ci -m2 -Aq
21 $ hg ci -m2 -Aq
22 $ hg update 1 -q
22 $ hg update 1 -q
23
23
24 make some patches with a parent: 1:d7fe2034f71b -> p0 -> p1
24 make some patches with a parent: 1:d7fe2034f71b -> p0 -> p1
25
25
26 $ echo cp0 >> fp0
26 $ echo cp0 >> fp0
27 $ hg add fp0
27 $ hg add fp0
28 $ hg ci -m p0 -d "0 0"
28 $ hg ci -m p0 -d "0 0"
29 $ hg export -r. > p0
29 $ hg export -r. > p0
30 $ hg strip -qn .
30 $ hg strip -qn .
31 $ hg qimport p0
31 $ hg qimport p0
32 adding p0 to series file
32 adding p0 to series file
33 $ hg qpush
33 $ hg qpush
34 applying p0
34 applying p0
35 now at: p0
35 now at: p0
36
36
37 $ echo cp1 >> fp1
37 $ echo cp1 >> fp1
38 $ hg add fp1
38 $ hg add fp1
39 $ hg qnew p1 -d "0 0"
39 $ hg qnew p1 -d "0 0"
40
40
41 $ hg qpop -aq
41 $ hg qpop -aq
42 patch queue now empty
42 patch queue now empty
43
43
44 qpush --exact when at the parent
44 qpush --exact when at the parent
45
45
46 $ hg update 1 -q
46 $ hg update 1 -q
47 $ hg qpush -e
47 $ hg qpush -e
48 applying p0
48 applying p0
49 now at: p0
49 now at: p0
50 $ hg parents -qr qbase
50 $ hg parents -qr qbase
51 1:d7fe2034f71b
51 1:d7fe2034f71b
52 $ hg qpop -aq
52 $ hg qpop -aq
53 patch queue now empty
53 patch queue now empty
54
54
55 $ hg qpush -e p0
55 $ hg qpush -e p0
56 applying p0
56 applying p0
57 now at: p0
57 now at: p0
58 $ hg parents -qr qbase
58 $ hg parents -qr qbase
59 1:d7fe2034f71b
59 1:d7fe2034f71b
60 $ hg qpop -aq
60 $ hg qpop -aq
61 patch queue now empty
61 patch queue now empty
62
62
63 $ hg qpush -e p1
63 $ hg qpush -e p1
64 applying p0
64 applying p0
65 applying p1
65 applying p1
66 now at: p1
66 now at: p1
67 $ hg parents -qr qbase
67 $ hg parents -qr qbase
68 1:d7fe2034f71b
68 1:d7fe2034f71b
69 $ hg qpop -aq
69 $ hg qpop -aq
70 patch queue now empty
70 patch queue now empty
71
71
72 qpush --exact when at another rev
72 qpush --exact when at another rev
73
73
74 $ hg update 0 -q
74 $ hg update 0 -q
75 $ hg qpush -e
75 $ hg qpush -e
76 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
76 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
77 applying p0
77 applying p0
78 now at: p0
78 now at: p0
79 $ hg parents -qr qbase
79 $ hg parents -qr qbase
80 1:d7fe2034f71b
80 1:d7fe2034f71b
81 $ hg qpop -aq
81 $ hg qpop -aq
82 patch queue now empty
82 patch queue now empty
83
83
84 $ hg update 0 -q
84 $ hg update 0 -q
85 $ hg qpush -e p0
85 $ hg qpush -e p0
86 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
86 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
87 applying p0
87 applying p0
88 now at: p0
88 now at: p0
89 $ hg parents -qr qbase
89 $ hg parents -qr qbase
90 1:d7fe2034f71b
90 1:d7fe2034f71b
91 $ hg qpop -aq
91 $ hg qpop -aq
92 patch queue now empty
92 patch queue now empty
93
93
94 $ hg update 0 -q
94 $ hg update 0 -q
95 $ hg qpush -e p1
95 $ hg qpush -e p1
96 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
96 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
97 applying p0
97 applying p0
98 applying p1
98 applying p1
99 now at: p1
99 now at: p1
100 $ hg parents -qr qbase
100 $ hg parents -qr qbase
101 1:d7fe2034f71b
101 1:d7fe2034f71b
102 $ hg qpop -aq
102 $ hg qpop -aq
103 patch queue now empty
103 patch queue now empty
104
104
105 $ hg update 0 -q
105 $ hg update 0 -q
106 $ hg qpush -ea
106 $ hg qpush -ea
107 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
107 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
108 applying p0
108 applying p0
109 applying p1
109 applying p1
110 now at: p1
110 now at: p1
111 $ hg parents -qr qbase
111 $ hg parents -qr qbase
112 1:d7fe2034f71b
112 1:d7fe2034f71b
113 $ hg qpop -aq
113 $ hg qpop -aq
114 patch queue now empty
114 patch queue now empty
115
115
116 qpush --exact while crossing branches
116 qpush --exact while crossing branches
117
117
118 $ hg update 2 -q
118 $ hg update 2 -q
119 $ hg qpush -e
119 $ hg qpush -e
120 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
120 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
121 applying p0
121 applying p0
122 now at: p0
122 now at: p0
123 $ hg parents -qr qbase
123 $ hg parents -qr qbase
124 1:d7fe2034f71b
124 1:d7fe2034f71b
125 $ hg qpop -aq
125 $ hg qpop -aq
126 patch queue now empty
126 patch queue now empty
127
127
128 $ hg update 2 -q
128 $ hg update 2 -q
129 $ hg qpush -e p0
129 $ hg qpush -e p0
130 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
130 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
131 applying p0
131 applying p0
132 now at: p0
132 now at: p0
133 $ hg parents -qr qbase
133 $ hg parents -qr qbase
134 1:d7fe2034f71b
134 1:d7fe2034f71b
135 $ hg qpop -aq
135 $ hg qpop -aq
136 patch queue now empty
136 patch queue now empty
137
137
138 $ hg update 2 -q
138 $ hg update 2 -q
139 $ hg qpush -e p1
139 $ hg qpush -e p1
140 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
140 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
141 applying p0
141 applying p0
142 applying p1
142 applying p1
143 now at: p1
143 now at: p1
144 $ hg parents -qr qbase
144 $ hg parents -qr qbase
145 1:d7fe2034f71b
145 1:d7fe2034f71b
146 $ hg qpop -aq
146 $ hg qpop -aq
147 patch queue now empty
147 patch queue now empty
148
148
149 $ hg update 2 -q
149 $ hg update 2 -q
150 $ hg qpush -ea
150 $ hg qpush -ea
151 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
151 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
152 applying p0
152 applying p0
153 applying p1
153 applying p1
154 now at: p1
154 now at: p1
155 $ hg parents -qr qbase
155 $ hg parents -qr qbase
156 1:d7fe2034f71b
156 1:d7fe2034f71b
157 $ hg qpop -aq
157 $ hg qpop -aq
158 patch queue now empty
158 patch queue now empty
159
159
160 qpush --exact --force with changes to an unpatched file
160 qpush --exact --force with changes to an unpatched file
161
161
162 $ hg update 1 -q
162 $ hg update 1 -q
163 $ echo c0 >> f0
163 $ echo c0 >> f0
164 $ hg qpush -e
164 $ hg qpush -e
165 abort: local changes found
165 abort: local changes found
166 [255]
166 [255]
167 $ hg qpush -ef
167 $ hg qpush -ef
168 applying p0
168 applying p0
169 now at: p0
169 now at: p0
170 $ cat f0
170 $ cat f0
171 c0
171 c0
172 $ rm f0
172 $ rm f0
173 $ touch f0
173 $ touch f0
174 $ hg qpop -aq
174 $ hg qpop -aq
175 patch queue now empty
175 patch queue now empty
176
176
177 $ hg update 1 -q
177 $ hg update 1 -q
178 $ echo c0 >> f0
178 $ echo c0 >> f0
179 $ hg qpush -e p1
179 $ hg qpush -e p1
180 abort: local changes found
180 abort: local changes found
181 [255]
181 [255]
182 $ hg qpush -e p1 -f
182 $ hg qpush -e p1 -f
183 applying p0
183 applying p0
184 applying p1
184 applying p1
185 now at: p1
185 now at: p1
186 $ cat f0
186 $ cat f0
187 c0
187 c0
188 $ rm f0
188 $ rm f0
189 $ touch f0
189 $ touch f0
190 $ hg qpop -aq
190 $ hg qpop -aq
191 patch queue now empty
191 patch queue now empty
192
192
193 qpush --exact --force with changes to a patched file
193 qpush --exact --force with changes to a patched file
194
194
195 $ hg update 1 -q
195 $ hg update 1 -q
196 $ echo cp0-bad >> fp0
196 $ echo cp0-bad >> fp0
197 $ hg add fp0
197 $ hg add fp0
198 $ hg qpush -e
198 $ hg qpush -e
199 abort: local changes found
199 abort: local changes found
200 [255]
200 [255]
201 $ hg qpush -ef
201 $ hg qpush -ef
202 applying p0
202 applying p0
203 file fp0 already exists
203 file fp0 already exists
204 1 out of 1 hunks FAILED -- saving rejects to file fp0.rej
204 1 out of 1 hunks FAILED -- saving rejects to file fp0.rej
205 patch failed, unable to continue (try -v)
205 patch failed, unable to continue (try -v)
206 patch failed, rejects left in working dir
206 patch failed, rejects left in working directory
207 errors during apply, please fix and refresh p0
207 errors during apply, please fix and refresh p0
208 [2]
208 [2]
209 $ cat fp0
209 $ cat fp0
210 cp0-bad
210 cp0-bad
211 $ cat fp0.rej
211 $ cat fp0.rej
212 --- fp0
212 --- fp0
213 +++ fp0
213 +++ fp0
214 @@ -0,0 +1,1 @@
214 @@ -0,0 +1,1 @@
215 +cp0
215 +cp0
216 $ hg qpop -aqf
216 $ hg qpop -aqf
217 patch queue now empty
217 patch queue now empty
218 $ rm fp0
218 $ rm fp0
219 $ rm fp0.rej
219 $ rm fp0.rej
220
220
221 $ hg update 1 -q
221 $ hg update 1 -q
222 $ echo cp1-bad >> fp1
222 $ echo cp1-bad >> fp1
223 $ hg add fp1
223 $ hg add fp1
224 $ hg qpush -e p1
224 $ hg qpush -e p1
225 abort: local changes found
225 abort: local changes found
226 [255]
226 [255]
227 $ hg qpush -e p1 -f
227 $ hg qpush -e p1 -f
228 applying p0
228 applying p0
229 applying p1
229 applying p1
230 file fp1 already exists
230 file fp1 already exists
231 1 out of 1 hunks FAILED -- saving rejects to file fp1.rej
231 1 out of 1 hunks FAILED -- saving rejects to file fp1.rej
232 patch failed, unable to continue (try -v)
232 patch failed, unable to continue (try -v)
233 patch failed, rejects left in working dir
233 patch failed, rejects left in working directory
234 errors during apply, please fix and refresh p1
234 errors during apply, please fix and refresh p1
235 [2]
235 [2]
236 $ cat fp1
236 $ cat fp1
237 cp1-bad
237 cp1-bad
238 $ cat fp1.rej
238 $ cat fp1.rej
239 --- fp1
239 --- fp1
240 +++ fp1
240 +++ fp1
241 @@ -0,0 +1,1 @@
241 @@ -0,0 +1,1 @@
242 +cp1
242 +cp1
243 $ hg qpop -aqf
243 $ hg qpop -aqf
244 patch queue now empty
244 patch queue now empty
245 $ hg forget fp1
245 $ hg forget fp1
246 $ rm fp1
246 $ rm fp1
247 $ rm fp1.rej
247 $ rm fp1.rej
248
248
249 qpush --exact when already at a patch
249 qpush --exact when already at a patch
250
250
251 $ hg update 1
251 $ hg update 1
252 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
252 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
253 $ hg qpush -e p0
253 $ hg qpush -e p0
254 applying p0
254 applying p0
255 now at: p0
255 now at: p0
256 $ hg qpush -e p1
256 $ hg qpush -e p1
257 abort: cannot push --exact with applied patches
257 abort: cannot push --exact with applied patches
258 [255]
258 [255]
259 $ hg qpop -aq
259 $ hg qpop -aq
260 patch queue now empty
260 patch queue now empty
261
261
262 qpush --exact --move should fail
262 qpush --exact --move should fail
263
263
264 $ hg qpush -e --move p1
264 $ hg qpush -e --move p1
265 abort: cannot use --exact and --move together
265 abort: cannot use --exact and --move together
266 [255]
266 [255]
267
267
268 qpush --exact a patch without a parent recorded
268 qpush --exact a patch without a parent recorded
269
269
270 $ hg qpush -q
270 $ hg qpush -q
271 now at: p0
271 now at: p0
272 $ grep -v '# Parent' .hg/patches/p0 > p0.new
272 $ grep -v '# Parent' .hg/patches/p0 > p0.new
273 $ mv p0.new .hg/patches/p0
273 $ mv p0.new .hg/patches/p0
274 $ hg qpop -aq
274 $ hg qpop -aq
275 patch queue now empty
275 patch queue now empty
276 $ hg qpush -e
276 $ hg qpush -e
277 abort: p0 does not have a parent recorded
277 abort: p0 does not have a parent recorded
278 [255]
278 [255]
279 $ hg qpush -e p0
279 $ hg qpush -e p0
280 abort: p0 does not have a parent recorded
280 abort: p0 does not have a parent recorded
281 [255]
281 [255]
282 $ hg qpush -e p1
282 $ hg qpush -e p1
283 abort: p0 does not have a parent recorded
283 abort: p0 does not have a parent recorded
284 [255]
284 [255]
285 $ hg qpush -ea
285 $ hg qpush -ea
286 abort: p0 does not have a parent recorded
286 abort: p0 does not have a parent recorded
287 [255]
287 [255]
288
288
289 $ cd ..
289 $ cd ..
@@ -1,441 +1,441 b''
1 Test that qpush cleans things up if it doesn't complete
1 Test that qpush cleans things up if it doesn't complete
2
2
3 $ echo "[extensions]" >> $HGRCPATH
3 $ echo "[extensions]" >> $HGRCPATH
4 $ echo "mq=" >> $HGRCPATH
4 $ echo "mq=" >> $HGRCPATH
5 $ hg init repo
5 $ hg init repo
6 $ cd repo
6 $ cd repo
7 $ echo foo > foo
7 $ echo foo > foo
8 $ hg ci -Am 'add foo'
8 $ hg ci -Am 'add foo'
9 adding foo
9 adding foo
10 $ touch untracked-file
10 $ touch untracked-file
11 $ echo 'syntax: glob' > .hgignore
11 $ echo 'syntax: glob' > .hgignore
12 $ echo '.hgignore' >> .hgignore
12 $ echo '.hgignore' >> .hgignore
13 $ hg qinit
13 $ hg qinit
14
14
15 test qpush on empty series
15 test qpush on empty series
16
16
17 $ hg qpush
17 $ hg qpush
18 no patches in series
18 no patches in series
19 $ hg qnew patch1
19 $ hg qnew patch1
20 $ echo >> foo
20 $ echo >> foo
21 $ hg qrefresh -m 'patch 1'
21 $ hg qrefresh -m 'patch 1'
22 $ hg qnew patch2
22 $ hg qnew patch2
23 $ echo bar > bar
23 $ echo bar > bar
24 $ hg add bar
24 $ hg add bar
25 $ hg qrefresh -m 'patch 2'
25 $ hg qrefresh -m 'patch 2'
26 $ hg qnew --config 'mq.plain=true' -U bad-patch
26 $ hg qnew --config 'mq.plain=true' -U bad-patch
27 $ echo >> foo
27 $ echo >> foo
28 $ hg qrefresh
28 $ hg qrefresh
29 $ hg qpop -a
29 $ hg qpop -a
30 popping bad-patch
30 popping bad-patch
31 popping patch2
31 popping patch2
32 popping patch1
32 popping patch1
33 patch queue now empty
33 patch queue now empty
34 $ $PYTHON -c 'print "\xe9"' > message
34 $ $PYTHON -c 'print "\xe9"' > message
35 $ cat .hg/patches/bad-patch >> message
35 $ cat .hg/patches/bad-patch >> message
36 $ mv message .hg/patches/bad-patch
36 $ mv message .hg/patches/bad-patch
37 $ hg qpush -a && echo 'qpush succeeded?!'
37 $ hg qpush -a && echo 'qpush succeeded?!'
38 applying patch1
38 applying patch1
39 applying patch2
39 applying patch2
40 applying bad-patch
40 applying bad-patch
41 transaction abort!
41 transaction abort!
42 rollback completed
42 rollback completed
43 cleaning up working directory...done
43 cleaning up working directory...done
44 abort: decoding near '\xe9': 'ascii' codec can't decode byte 0xe9 in position 0: ordinal not in range(128)! (esc)
44 abort: decoding near '\xe9': 'ascii' codec can't decode byte 0xe9 in position 0: ordinal not in range(128)! (esc)
45 [255]
45 [255]
46 $ hg parents
46 $ hg parents
47 changeset: 0:bbd179dfa0a7
47 changeset: 0:bbd179dfa0a7
48 tag: tip
48 tag: tip
49 user: test
49 user: test
50 date: Thu Jan 01 00:00:00 1970 +0000
50 date: Thu Jan 01 00:00:00 1970 +0000
51 summary: add foo
51 summary: add foo
52
52
53
53
54 test corrupt status file
54 test corrupt status file
55 $ hg qpush
55 $ hg qpush
56 applying patch1
56 applying patch1
57 now at: patch1
57 now at: patch1
58 $ cp .hg/patches/status .hg/patches/status.orig
58 $ cp .hg/patches/status .hg/patches/status.orig
59 $ hg qpop
59 $ hg qpop
60 popping patch1
60 popping patch1
61 patch queue now empty
61 patch queue now empty
62 $ cp .hg/patches/status.orig .hg/patches/status
62 $ cp .hg/patches/status.orig .hg/patches/status
63 $ hg qpush
63 $ hg qpush
64 abort: working directory revision is not qtip
64 abort: working directory revision is not qtip
65 [255]
65 [255]
66 $ rm .hg/patches/status .hg/patches/status.orig
66 $ rm .hg/patches/status .hg/patches/status.orig
67
67
68
68
69 bar should be gone; other unknown/ignored files should still be around
69 bar should be gone; other unknown/ignored files should still be around
70
70
71 $ hg status -A
71 $ hg status -A
72 ? untracked-file
72 ? untracked-file
73 I .hgignore
73 I .hgignore
74 C foo
74 C foo
75
75
76 preparing qpush of a missing patch
76 preparing qpush of a missing patch
77
77
78 $ hg qpop -a
78 $ hg qpop -a
79 no patches applied
79 no patches applied
80 $ hg qpush
80 $ hg qpush
81 applying patch1
81 applying patch1
82 now at: patch1
82 now at: patch1
83 $ rm .hg/patches/patch2
83 $ rm .hg/patches/patch2
84
84
85 now we expect the push to fail, but it should NOT complain about patch1
85 now we expect the push to fail, but it should NOT complain about patch1
86
86
87 $ hg qpush
87 $ hg qpush
88 applying patch2
88 applying patch2
89 unable to read patch2
89 unable to read patch2
90 now at: patch1
90 now at: patch1
91 [1]
91 [1]
92
92
93 preparing qpush of missing patch with no patch applied
93 preparing qpush of missing patch with no patch applied
94
94
95 $ hg qpop -a
95 $ hg qpop -a
96 popping patch1
96 popping patch1
97 patch queue now empty
97 patch queue now empty
98 $ rm .hg/patches/patch1
98 $ rm .hg/patches/patch1
99
99
100 qpush should fail the same way as below
100 qpush should fail the same way as below
101
101
102 $ hg qpush
102 $ hg qpush
103 applying patch1
103 applying patch1
104 unable to read patch1
104 unable to read patch1
105 [1]
105 [1]
106
106
107 Test qpush to a patch below the currently applied patch.
107 Test qpush to a patch below the currently applied patch.
108
108
109 $ hg qq -c guardedseriesorder
109 $ hg qq -c guardedseriesorder
110 $ hg qnew a
110 $ hg qnew a
111 $ hg qguard +block
111 $ hg qguard +block
112 $ hg qnew b
112 $ hg qnew b
113 $ hg qnew c
113 $ hg qnew c
114
114
115 $ hg qpop -a
115 $ hg qpop -a
116 popping c
116 popping c
117 popping b
117 popping b
118 popping a
118 popping a
119 patch queue now empty
119 patch queue now empty
120
120
121 try to push and pop while a is guarded
121 try to push and pop while a is guarded
122
122
123 $ hg qpush a
123 $ hg qpush a
124 cannot push 'a' - guarded by '+block'
124 cannot push 'a' - guarded by '+block'
125 [1]
125 [1]
126 $ hg qpush -a
126 $ hg qpush -a
127 applying b
127 applying b
128 patch b is empty
128 patch b is empty
129 applying c
129 applying c
130 patch c is empty
130 patch c is empty
131 now at: c
131 now at: c
132
132
133 now try it when a is unguarded, and we're at the top of the queue
133 now try it when a is unguarded, and we're at the top of the queue
134
134
135 $ hg qapplied -v
135 $ hg qapplied -v
136 0 G a
136 0 G a
137 1 A b
137 1 A b
138 2 A c
138 2 A c
139 $ hg qsel block
139 $ hg qsel block
140 $ hg qpush b
140 $ hg qpush b
141 abort: cannot push to a previous patch: b
141 abort: cannot push to a previous patch: b
142 [255]
142 [255]
143 $ hg qpush a
143 $ hg qpush a
144 abort: cannot push to a previous patch: a
144 abort: cannot push to a previous patch: a
145 [255]
145 [255]
146
146
147 and now we try it one more time with a unguarded, while we're not at the top of the queue
147 and now we try it one more time with a unguarded, while we're not at the top of the queue
148
148
149 $ hg qpop b
149 $ hg qpop b
150 popping c
150 popping c
151 now at: b
151 now at: b
152 $ hg qpush a
152 $ hg qpush a
153 abort: cannot push to a previous patch: a
153 abort: cannot push to a previous patch: a
154 [255]
154 [255]
155
155
156 test qpop --force and backup files
156 test qpop --force and backup files
157
157
158 $ hg qpop -a
158 $ hg qpop -a
159 popping b
159 popping b
160 patch queue now empty
160 patch queue now empty
161 $ hg qq --create force
161 $ hg qq --create force
162 $ echo a > a
162 $ echo a > a
163 $ echo b > b
163 $ echo b > b
164 $ echo c > c
164 $ echo c > c
165 $ hg ci -Am add a b c
165 $ hg ci -Am add a b c
166 $ echo a >> a
166 $ echo a >> a
167 $ hg rm b
167 $ hg rm b
168 $ hg rm c
168 $ hg rm c
169 $ hg qnew p1
169 $ hg qnew p1
170 $ echo a >> a
170 $ echo a >> a
171 $ echo bb > b
171 $ echo bb > b
172 $ hg add b
172 $ hg add b
173 $ echo cc > c
173 $ echo cc > c
174 $ hg add c
174 $ hg add c
175 $ hg qpop --force --verbose
175 $ hg qpop --force --verbose
176 saving current version of a as a.orig
176 saving current version of a as a.orig
177 saving current version of b as b.orig
177 saving current version of b as b.orig
178 saving current version of c as c.orig
178 saving current version of c as c.orig
179 popping p1
179 popping p1
180 patch queue now empty
180 patch queue now empty
181 $ hg st
181 $ hg st
182 ? a.orig
182 ? a.orig
183 ? b.orig
183 ? b.orig
184 ? c.orig
184 ? c.orig
185 ? untracked-file
185 ? untracked-file
186 $ cat a.orig
186 $ cat a.orig
187 a
187 a
188 a
188 a
189 a
189 a
190 $ cat b.orig
190 $ cat b.orig
191 bb
191 bb
192 $ cat c.orig
192 $ cat c.orig
193 cc
193 cc
194
194
195 test qpop --force --no-backup
195 test qpop --force --no-backup
196
196
197 $ hg qpush
197 $ hg qpush
198 applying p1
198 applying p1
199 now at: p1
199 now at: p1
200 $ rm a.orig
200 $ rm a.orig
201 $ echo a >> a
201 $ echo a >> a
202 $ hg qpop --force --no-backup --verbose
202 $ hg qpop --force --no-backup --verbose
203 popping p1
203 popping p1
204 patch queue now empty
204 patch queue now empty
205 $ test -f a.orig && echo 'error: backup with --no-backup'
205 $ test -f a.orig && echo 'error: backup with --no-backup'
206 [1]
206 [1]
207
207
208 test qpop --keep-changes
208 test qpop --keep-changes
209
209
210 $ hg qpush
210 $ hg qpush
211 applying p1
211 applying p1
212 now at: p1
212 now at: p1
213 $ hg qpop --keep-changes --force
213 $ hg qpop --keep-changes --force
214 abort: cannot use both --force and --keep-changes
214 abort: cannot use both --force and --keep-changes
215 [255]
215 [255]
216 $ echo a >> a
216 $ echo a >> a
217 $ hg qpop --keep-changes
217 $ hg qpop --keep-changes
218 abort: local changes found, refresh first
218 abort: local changes found, refresh first
219 [255]
219 [255]
220 $ hg revert -qa a
220 $ hg revert -qa a
221 $ rm a
221 $ rm a
222 $ hg qpop --keep-changes
222 $ hg qpop --keep-changes
223 abort: local changes found, refresh first
223 abort: local changes found, refresh first
224 [255]
224 [255]
225 $ hg rm -A a
225 $ hg rm -A a
226 $ hg qpop --keep-changes
226 $ hg qpop --keep-changes
227 abort: local changes found, refresh first
227 abort: local changes found, refresh first
228 [255]
228 [255]
229 $ hg revert -qa a
229 $ hg revert -qa a
230 $ echo b > b
230 $ echo b > b
231 $ hg add b
231 $ hg add b
232 $ hg qpop --keep-changes
232 $ hg qpop --keep-changes
233 abort: local changes found, refresh first
233 abort: local changes found, refresh first
234 [255]
234 [255]
235 $ hg forget b
235 $ hg forget b
236 $ echo d > d
236 $ echo d > d
237 $ hg add d
237 $ hg add d
238 $ hg qpop --keep-changes
238 $ hg qpop --keep-changes
239 popping p1
239 popping p1
240 patch queue now empty
240 patch queue now empty
241 $ hg forget d
241 $ hg forget d
242 $ rm d
242 $ rm d
243
243
244 test qpush --force and backup files
244 test qpush --force and backup files
245
245
246 $ echo a >> a
246 $ echo a >> a
247 $ hg qnew p2
247 $ hg qnew p2
248 $ echo b >> b
248 $ echo b >> b
249 $ echo d > d
249 $ echo d > d
250 $ echo e > e
250 $ echo e > e
251 $ hg add d e
251 $ hg add d e
252 $ hg rm c
252 $ hg rm c
253 $ hg qnew p3
253 $ hg qnew p3
254 $ hg qpop -a
254 $ hg qpop -a
255 popping p3
255 popping p3
256 popping p2
256 popping p2
257 patch queue now empty
257 patch queue now empty
258 $ echo a >> a
258 $ echo a >> a
259 $ echo b1 >> b
259 $ echo b1 >> b
260 $ echo d1 > d
260 $ echo d1 > d
261 $ hg add d
261 $ hg add d
262 $ echo e1 > e
262 $ echo e1 > e
263 $ hg qpush -a --force --verbose
263 $ hg qpush -a --force --verbose
264 applying p2
264 applying p2
265 saving current version of a as a.orig
265 saving current version of a as a.orig
266 patching file a
266 patching file a
267 committing files:
267 committing files:
268 a
268 a
269 committing manifest
269 committing manifest
270 committing changelog
270 committing changelog
271 applying p3
271 applying p3
272 saving current version of b as b.orig
272 saving current version of b as b.orig
273 saving current version of d as d.orig
273 saving current version of d as d.orig
274 patching file b
274 patching file b
275 patching file c
275 patching file c
276 patching file d
276 patching file d
277 file d already exists
277 file d already exists
278 1 out of 1 hunks FAILED -- saving rejects to file d.rej
278 1 out of 1 hunks FAILED -- saving rejects to file d.rej
279 patching file e
279 patching file e
280 file e already exists
280 file e already exists
281 1 out of 1 hunks FAILED -- saving rejects to file e.rej
281 1 out of 1 hunks FAILED -- saving rejects to file e.rej
282 patch failed to apply
282 patch failed to apply
283 committing files:
283 committing files:
284 b
284 b
285 committing manifest
285 committing manifest
286 committing changelog
286 committing changelog
287 patch failed, rejects left in working dir
287 patch failed, rejects left in working directory
288 errors during apply, please fix and refresh p3
288 errors during apply, please fix and refresh p3
289 [2]
289 [2]
290 $ cat a.orig
290 $ cat a.orig
291 a
291 a
292 a
292 a
293 $ cat b.orig
293 $ cat b.orig
294 b
294 b
295 b1
295 b1
296 $ cat d.orig
296 $ cat d.orig
297 d1
297 d1
298
298
299 test qpush --force --no-backup
299 test qpush --force --no-backup
300
300
301 $ hg revert -qa
301 $ hg revert -qa
302 $ hg qpop -a
302 $ hg qpop -a
303 popping p3
303 popping p3
304 popping p2
304 popping p2
305 patch queue now empty
305 patch queue now empty
306 $ echo a >> a
306 $ echo a >> a
307 $ rm a.orig
307 $ rm a.orig
308 $ hg qpush --force --no-backup --verbose
308 $ hg qpush --force --no-backup --verbose
309 applying p2
309 applying p2
310 patching file a
310 patching file a
311 committing files:
311 committing files:
312 a
312 a
313 committing manifest
313 committing manifest
314 committing changelog
314 committing changelog
315 now at: p2
315 now at: p2
316 $ test -f a.orig && echo 'error: backup with --no-backup'
316 $ test -f a.orig && echo 'error: backup with --no-backup'
317 [1]
317 [1]
318
318
319 test qgoto --force --no-backup
319 test qgoto --force --no-backup
320
320
321 $ hg qpop
321 $ hg qpop
322 popping p2
322 popping p2
323 patch queue now empty
323 patch queue now empty
324 $ echo a >> a
324 $ echo a >> a
325 $ hg qgoto --force --no-backup p2 --verbose
325 $ hg qgoto --force --no-backup p2 --verbose
326 applying p2
326 applying p2
327 patching file a
327 patching file a
328 committing files:
328 committing files:
329 a
329 a
330 committing manifest
330 committing manifest
331 committing changelog
331 committing changelog
332 now at: p2
332 now at: p2
333 $ test -f a.orig && echo 'error: backup with --no-backup'
333 $ test -f a.orig && echo 'error: backup with --no-backup'
334 [1]
334 [1]
335
335
336 test qpush --keep-changes
336 test qpush --keep-changes
337
337
338 $ hg qpush --keep-changes --force
338 $ hg qpush --keep-changes --force
339 abort: cannot use both --force and --keep-changes
339 abort: cannot use both --force and --keep-changes
340 [255]
340 [255]
341 $ hg qpush --keep-changes --exact
341 $ hg qpush --keep-changes --exact
342 abort: cannot use --exact and --keep-changes together
342 abort: cannot use --exact and --keep-changes together
343 [255]
343 [255]
344 $ echo b >> b
344 $ echo b >> b
345 $ hg qpush --keep-changes
345 $ hg qpush --keep-changes
346 applying p3
346 applying p3
347 errors during apply, please fix and refresh p2
347 errors during apply, please fix and refresh p2
348 [2]
348 [2]
349 $ rm b
349 $ rm b
350 $ hg qpush --keep-changes
350 $ hg qpush --keep-changes
351 applying p3
351 applying p3
352 errors during apply, please fix and refresh p2
352 errors during apply, please fix and refresh p2
353 [2]
353 [2]
354 $ hg rm -A b
354 $ hg rm -A b
355 $ hg qpush --keep-changes
355 $ hg qpush --keep-changes
356 applying p3
356 applying p3
357 errors during apply, please fix and refresh p2
357 errors during apply, please fix and refresh p2
358 [2]
358 [2]
359 $ hg revert -aq b
359 $ hg revert -aq b
360 $ echo d > d
360 $ echo d > d
361 $ hg add d
361 $ hg add d
362 $ hg qpush --keep-changes
362 $ hg qpush --keep-changes
363 applying p3
363 applying p3
364 errors during apply, please fix and refresh p2
364 errors during apply, please fix and refresh p2
365 [2]
365 [2]
366 $ hg forget d
366 $ hg forget d
367 $ rm d
367 $ rm d
368 $ hg qpop
368 $ hg qpop
369 popping p2
369 popping p2
370 patch queue now empty
370 patch queue now empty
371 $ echo b >> b
371 $ echo b >> b
372 $ hg qpush -a --keep-changes
372 $ hg qpush -a --keep-changes
373 applying p2
373 applying p2
374 applying p3
374 applying p3
375 errors during apply, please fix and refresh p2
375 errors during apply, please fix and refresh p2
376 [2]
376 [2]
377 $ hg qtop
377 $ hg qtop
378 p2
378 p2
379 $ hg parents --template "{rev} {desc}\n"
379 $ hg parents --template "{rev} {desc}\n"
380 2 imported patch p2
380 2 imported patch p2
381 $ hg st b
381 $ hg st b
382 M b
382 M b
383 $ cat b
383 $ cat b
384 b
384 b
385 b
385 b
386
386
387 test qgoto --keep-changes
387 test qgoto --keep-changes
388
388
389 $ hg revert -aq b
389 $ hg revert -aq b
390 $ rm e
390 $ rm e
391 $ hg qgoto --keep-changes --force p3
391 $ hg qgoto --keep-changes --force p3
392 abort: cannot use both --force and --keep-changes
392 abort: cannot use both --force and --keep-changes
393 [255]
393 [255]
394 $ echo a >> a
394 $ echo a >> a
395 $ hg qgoto --keep-changes p3
395 $ hg qgoto --keep-changes p3
396 applying p3
396 applying p3
397 now at: p3
397 now at: p3
398 $ hg st a
398 $ hg st a
399 M a
399 M a
400 $ hg qgoto --keep-changes p2
400 $ hg qgoto --keep-changes p2
401 popping p3
401 popping p3
402 now at: p2
402 now at: p2
403 $ hg st a
403 $ hg st a
404 M a
404 M a
405
405
406 test mq.keepchanges setting
406 test mq.keepchanges setting
407
407
408 $ hg --config mq.keepchanges=1 qpush
408 $ hg --config mq.keepchanges=1 qpush
409 applying p3
409 applying p3
410 now at: p3
410 now at: p3
411 $ hg st a
411 $ hg st a
412 M a
412 M a
413 $ hg --config mq.keepchanges=1 qpop
413 $ hg --config mq.keepchanges=1 qpop
414 popping p3
414 popping p3
415 now at: p2
415 now at: p2
416 $ hg st a
416 $ hg st a
417 M a
417 M a
418 $ hg --config mq.keepchanges=1 qgoto p3
418 $ hg --config mq.keepchanges=1 qgoto p3
419 applying p3
419 applying p3
420 now at: p3
420 now at: p3
421 $ hg st a
421 $ hg st a
422 M a
422 M a
423 $ echo b >> b
423 $ echo b >> b
424 $ hg --config mq.keepchanges=1 qpop --force
424 $ hg --config mq.keepchanges=1 qpop --force
425 popping p3
425 popping p3
426 now at: p2
426 now at: p2
427 $ hg st b
427 $ hg st b
428 $ hg --config mq.keepchanges=1 qpush --exact
428 $ hg --config mq.keepchanges=1 qpush --exact
429 abort: local changes found, refresh first
429 abort: local changes found, refresh first
430 [255]
430 [255]
431 $ hg revert -qa a
431 $ hg revert -qa a
432 $ hg qpop
432 $ hg qpop
433 popping p2
433 popping p2
434 patch queue now empty
434 patch queue now empty
435 $ echo a >> a
435 $ echo a >> a
436 $ hg --config mq.keepchanges=1 qpush --force
436 $ hg --config mq.keepchanges=1 qpush --force
437 applying p2
437 applying p2
438 now at: p2
438 now at: p2
439 $ hg st a
439 $ hg st a
440
440
441 $ cd ..
441 $ cd ..
@@ -1,1610 +1,1610 b''
1 $ checkundo()
1 $ checkundo()
2 > {
2 > {
3 > if [ -f .hg/store/undo ]; then
3 > if [ -f .hg/store/undo ]; then
4 > echo ".hg/store/undo still exists after $1"
4 > echo ".hg/store/undo still exists after $1"
5 > fi
5 > fi
6 > }
6 > }
7
7
8 $ cat <<EOF >> $HGRCPATH
8 $ cat <<EOF >> $HGRCPATH
9 > [extensions]
9 > [extensions]
10 > mq =
10 > mq =
11 > [mq]
11 > [mq]
12 > plain = true
12 > plain = true
13 > EOF
13 > EOF
14
14
15
15
16 help
16 help
17
17
18 $ hg help mq
18 $ hg help mq
19 mq extension - manage a stack of patches
19 mq extension - manage a stack of patches
20
20
21 This extension lets you work with a stack of patches in a Mercurial
21 This extension lets you work with a stack of patches in a Mercurial
22 repository. It manages two stacks of patches - all known patches, and applied
22 repository. It manages two stacks of patches - all known patches, and applied
23 patches (subset of known patches).
23 patches (subset of known patches).
24
24
25 Known patches are represented as patch files in the .hg/patches directory.
25 Known patches are represented as patch files in the .hg/patches directory.
26 Applied patches are both patch files and changesets.
26 Applied patches are both patch files and changesets.
27
27
28 Common tasks (use "hg help command" for more details):
28 Common tasks (use "hg help command" for more details):
29
29
30 create new patch qnew
30 create new patch qnew
31 import existing patch qimport
31 import existing patch qimport
32
32
33 print patch series qseries
33 print patch series qseries
34 print applied patches qapplied
34 print applied patches qapplied
35
35
36 add known patch to applied stack qpush
36 add known patch to applied stack qpush
37 remove patch from applied stack qpop
37 remove patch from applied stack qpop
38 refresh contents of top applied patch qrefresh
38 refresh contents of top applied patch qrefresh
39
39
40 By default, mq will automatically use git patches when required to avoid
40 By default, mq will automatically use git patches when required to avoid
41 losing file mode changes, copy records, binary files or empty files creations
41 losing file mode changes, copy records, binary files or empty files creations
42 or deletions. This behaviour can be configured with:
42 or deletions. This behaviour can be configured with:
43
43
44 [mq]
44 [mq]
45 git = auto/keep/yes/no
45 git = auto/keep/yes/no
46
46
47 If set to 'keep', mq will obey the [diff] section configuration while
47 If set to 'keep', mq will obey the [diff] section configuration while
48 preserving existing git patches upon qrefresh. If set to 'yes' or 'no', mq
48 preserving existing git patches upon qrefresh. If set to 'yes' or 'no', mq
49 will override the [diff] section and always generate git or regular patches,
49 will override the [diff] section and always generate git or regular patches,
50 possibly losing data in the second case.
50 possibly losing data in the second case.
51
51
52 It may be desirable for mq changesets to be kept in the secret phase (see "hg
52 It may be desirable for mq changesets to be kept in the secret phase (see "hg
53 help phases"), which can be enabled with the following setting:
53 help phases"), which can be enabled with the following setting:
54
54
55 [mq]
55 [mq]
56 secret = True
56 secret = True
57
57
58 You will by default be managing a patch queue named "patches". You can create
58 You will by default be managing a patch queue named "patches". You can create
59 other, independent patch queues with the "hg qqueue" command.
59 other, independent patch queues with the "hg qqueue" command.
60
60
61 If the working directory contains uncommitted files, qpush, qpop and qgoto
61 If the working directory contains uncommitted files, qpush, qpop and qgoto
62 abort immediately. If -f/--force is used, the changes are discarded. Setting:
62 abort immediately. If -f/--force is used, the changes are discarded. Setting:
63
63
64 [mq]
64 [mq]
65 keepchanges = True
65 keepchanges = True
66
66
67 make them behave as if --keep-changes were passed, and non-conflicting local
67 make them behave as if --keep-changes were passed, and non-conflicting local
68 changes will be tolerated and preserved. If incompatible options such as
68 changes will be tolerated and preserved. If incompatible options such as
69 -f/--force or --exact are passed, this setting is ignored.
69 -f/--force or --exact are passed, this setting is ignored.
70
70
71 This extension used to provide a strip command. This command now lives in the
71 This extension used to provide a strip command. This command now lives in the
72 strip extension.
72 strip extension.
73
73
74 list of commands:
74 list of commands:
75
75
76 qapplied print the patches already applied
76 qapplied print the patches already applied
77 qclone clone main and patch repository at same time
77 qclone clone main and patch repository at same time
78 qdelete remove patches from queue
78 qdelete remove patches from queue
79 qdiff diff of the current patch and subsequent modifications
79 qdiff diff of the current patch and subsequent modifications
80 qfinish move applied patches into repository history
80 qfinish move applied patches into repository history
81 qfold fold the named patches into the current patch
81 qfold fold the named patches into the current patch
82 qgoto push or pop patches until named patch is at top of stack
82 qgoto push or pop patches until named patch is at top of stack
83 qguard set or print guards for a patch
83 qguard set or print guards for a patch
84 qheader print the header of the topmost or specified patch
84 qheader print the header of the topmost or specified patch
85 qimport import a patch or existing changeset
85 qimport import a patch or existing changeset
86 qnew create a new patch
86 qnew create a new patch
87 qnext print the name of the next pushable patch
87 qnext print the name of the next pushable patch
88 qpop pop the current patch off the stack
88 qpop pop the current patch off the stack
89 qprev print the name of the preceding applied patch
89 qprev print the name of the preceding applied patch
90 qpush push the next patch onto the stack
90 qpush push the next patch onto the stack
91 qqueue manage multiple patch queues
91 qqueue manage multiple patch queues
92 qrefresh update the current patch
92 qrefresh update the current patch
93 qrename rename a patch
93 qrename rename a patch
94 qselect set or print guarded patches to push
94 qselect set or print guarded patches to push
95 qseries print the entire series file
95 qseries print the entire series file
96 qtop print the name of the current patch
96 qtop print the name of the current patch
97 qunapplied print the patches not yet applied
97 qunapplied print the patches not yet applied
98
98
99 (use "hg help -v mq" to show built-in aliases and global options)
99 (use "hg help -v mq" to show built-in aliases and global options)
100
100
101 $ hg init a
101 $ hg init a
102 $ cd a
102 $ cd a
103 $ echo a > a
103 $ echo a > a
104 $ hg ci -Ama
104 $ hg ci -Ama
105 adding a
105 adding a
106
106
107 $ hg clone . ../k
107 $ hg clone . ../k
108 updating to branch default
108 updating to branch default
109 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
109 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
110
110
111 $ mkdir b
111 $ mkdir b
112 $ echo z > b/z
112 $ echo z > b/z
113 $ hg ci -Ama
113 $ hg ci -Ama
114 adding b/z
114 adding b/z
115
115
116
116
117 qinit
117 qinit
118
118
119 $ hg qinit
119 $ hg qinit
120
120
121 $ cd ..
121 $ cd ..
122 $ hg init b
122 $ hg init b
123
123
124
124
125 -R qinit
125 -R qinit
126
126
127 $ hg -R b qinit
127 $ hg -R b qinit
128
128
129 $ hg init c
129 $ hg init c
130
130
131
131
132 qinit -c
132 qinit -c
133
133
134 $ hg --cwd c qinit -c
134 $ hg --cwd c qinit -c
135 $ hg -R c/.hg/patches st
135 $ hg -R c/.hg/patches st
136 A .hgignore
136 A .hgignore
137 A series
137 A series
138
138
139
139
140 qinit; qinit -c
140 qinit; qinit -c
141
141
142 $ hg init d
142 $ hg init d
143 $ cd d
143 $ cd d
144 $ hg qinit
144 $ hg qinit
145 $ hg qinit -c
145 $ hg qinit -c
146
146
147 qinit -c should create both files if they don't exist
147 qinit -c should create both files if they don't exist
148
148
149 $ cat .hg/patches/.hgignore
149 $ cat .hg/patches/.hgignore
150 ^\.hg
150 ^\.hg
151 ^\.mq
151 ^\.mq
152 syntax: glob
152 syntax: glob
153 status
153 status
154 guards
154 guards
155 $ cat .hg/patches/series
155 $ cat .hg/patches/series
156 $ hg qinit -c
156 $ hg qinit -c
157 abort: repository $TESTTMP/d/.hg/patches already exists! (glob)
157 abort: repository $TESTTMP/d/.hg/patches already exists! (glob)
158 [255]
158 [255]
159 $ cd ..
159 $ cd ..
160
160
161 $ echo '% qinit; <stuff>; qinit -c'
161 $ echo '% qinit; <stuff>; qinit -c'
162 % qinit; <stuff>; qinit -c
162 % qinit; <stuff>; qinit -c
163 $ hg init e
163 $ hg init e
164 $ cd e
164 $ cd e
165 $ hg qnew A
165 $ hg qnew A
166 $ checkundo qnew
166 $ checkundo qnew
167 $ echo foo > foo
167 $ echo foo > foo
168 $ hg phase -r qbase
168 $ hg phase -r qbase
169 0: draft
169 0: draft
170 $ hg add foo
170 $ hg add foo
171 $ hg qrefresh
171 $ hg qrefresh
172 $ hg phase -r qbase
172 $ hg phase -r qbase
173 0: draft
173 0: draft
174 $ hg qnew B
174 $ hg qnew B
175 $ echo >> foo
175 $ echo >> foo
176 $ hg qrefresh
176 $ hg qrefresh
177 $ echo status >> .hg/patches/.hgignore
177 $ echo status >> .hg/patches/.hgignore
178 $ echo bleh >> .hg/patches/.hgignore
178 $ echo bleh >> .hg/patches/.hgignore
179 $ hg qinit -c
179 $ hg qinit -c
180 adding .hg/patches/A (glob)
180 adding .hg/patches/A (glob)
181 adding .hg/patches/B (glob)
181 adding .hg/patches/B (glob)
182 $ hg -R .hg/patches status
182 $ hg -R .hg/patches status
183 A .hgignore
183 A .hgignore
184 A A
184 A A
185 A B
185 A B
186 A series
186 A series
187
187
188 qinit -c shouldn't touch these files if they already exist
188 qinit -c shouldn't touch these files if they already exist
189
189
190 $ cat .hg/patches/.hgignore
190 $ cat .hg/patches/.hgignore
191 status
191 status
192 bleh
192 bleh
193 $ cat .hg/patches/series
193 $ cat .hg/patches/series
194 A
194 A
195 B
195 B
196
196
197 add an untracked file
197 add an untracked file
198
198
199 $ echo >> .hg/patches/flaf
199 $ echo >> .hg/patches/flaf
200
200
201 status --mq with color (issue2096)
201 status --mq with color (issue2096)
202
202
203 $ hg status --mq --config extensions.color= --config color.mode=ansi --color=always
203 $ hg status --mq --config extensions.color= --config color.mode=ansi --color=always
204 \x1b[0;32;1mA \x1b[0m\x1b[0;32;1m.hgignore\x1b[0m (esc)
204 \x1b[0;32;1mA \x1b[0m\x1b[0;32;1m.hgignore\x1b[0m (esc)
205 \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mA\x1b[0m (esc)
205 \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mA\x1b[0m (esc)
206 \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mB\x1b[0m (esc)
206 \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mB\x1b[0m (esc)
207 \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mseries\x1b[0m (esc)
207 \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mseries\x1b[0m (esc)
208 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mflaf\x1b[0m (esc)
208 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mflaf\x1b[0m (esc)
209
209
210 try the --mq option on a command provided by an extension
210 try the --mq option on a command provided by an extension
211
211
212 $ hg purge --mq --verbose --config extensions.purge=
212 $ hg purge --mq --verbose --config extensions.purge=
213 removing file flaf
213 removing file flaf
214
214
215 $ cd ..
215 $ cd ..
216
216
217 #if no-outer-repo
217 #if no-outer-repo
218
218
219 init --mq without repo
219 init --mq without repo
220
220
221 $ mkdir f
221 $ mkdir f
222 $ cd f
222 $ cd f
223 $ hg init --mq
223 $ hg init --mq
224 abort: there is no Mercurial repository here (.hg not found)
224 abort: there is no Mercurial repository here (.hg not found)
225 [255]
225 [255]
226 $ cd ..
226 $ cd ..
227
227
228 #endif
228 #endif
229
229
230 init --mq with repo path
230 init --mq with repo path
231
231
232 $ hg init g
232 $ hg init g
233 $ hg init --mq g
233 $ hg init --mq g
234 $ test -d g/.hg/patches/.hg
234 $ test -d g/.hg/patches/.hg
235
235
236 init --mq with nonexistent directory
236 init --mq with nonexistent directory
237
237
238 $ hg init --mq nonexistentdir
238 $ hg init --mq nonexistentdir
239 abort: repository nonexistentdir not found!
239 abort: repository nonexistentdir not found!
240 [255]
240 [255]
241
241
242
242
243 init --mq with bundle (non "local")
243 init --mq with bundle (non "local")
244
244
245 $ hg -R a bundle --all a.bundle >/dev/null
245 $ hg -R a bundle --all a.bundle >/dev/null
246 $ hg init --mq a.bundle
246 $ hg init --mq a.bundle
247 abort: only a local queue repository may be initialized
247 abort: only a local queue repository may be initialized
248 [255]
248 [255]
249
249
250 $ cd a
250 $ cd a
251
251
252 $ hg qnew -m 'foo bar' test.patch
252 $ hg qnew -m 'foo bar' test.patch
253
253
254 $ echo '# comment' > .hg/patches/series.tmp
254 $ echo '# comment' > .hg/patches/series.tmp
255 $ echo >> .hg/patches/series.tmp # empty line
255 $ echo >> .hg/patches/series.tmp # empty line
256 $ cat .hg/patches/series >> .hg/patches/series.tmp
256 $ cat .hg/patches/series >> .hg/patches/series.tmp
257 $ mv .hg/patches/series.tmp .hg/patches/series
257 $ mv .hg/patches/series.tmp .hg/patches/series
258
258
259
259
260 qrefresh
260 qrefresh
261
261
262 $ echo a >> a
262 $ echo a >> a
263 $ hg qrefresh
263 $ hg qrefresh
264 $ cat .hg/patches/test.patch
264 $ cat .hg/patches/test.patch
265 foo bar
265 foo bar
266
266
267 diff -r [a-f0-9]* a (re)
267 diff -r [a-f0-9]* a (re)
268 --- a/a\t(?P<date>.*) (re)
268 --- a/a\t(?P<date>.*) (re)
269 \+\+\+ b/a\t(?P<date2>.*) (re)
269 \+\+\+ b/a\t(?P<date2>.*) (re)
270 @@ -1,1 +1,2 @@
270 @@ -1,1 +1,2 @@
271 a
271 a
272 +a
272 +a
273
273
274 empty qrefresh
274 empty qrefresh
275
275
276 $ hg qrefresh -X a
276 $ hg qrefresh -X a
277
277
278 revision:
278 revision:
279
279
280 $ hg diff -r -2 -r -1
280 $ hg diff -r -2 -r -1
281
281
282 patch:
282 patch:
283
283
284 $ cat .hg/patches/test.patch
284 $ cat .hg/patches/test.patch
285 foo bar
285 foo bar
286
286
287
287
288 working dir diff:
288 working dir diff:
289
289
290 $ hg diff --nodates -q
290 $ hg diff --nodates -q
291 --- a/a
291 --- a/a
292 +++ b/a
292 +++ b/a
293 @@ -1,1 +1,2 @@
293 @@ -1,1 +1,2 @@
294 a
294 a
295 +a
295 +a
296
296
297 restore things
297 restore things
298
298
299 $ hg qrefresh
299 $ hg qrefresh
300 $ checkundo qrefresh
300 $ checkundo qrefresh
301
301
302
302
303 qpop
303 qpop
304
304
305 $ hg qpop
305 $ hg qpop
306 popping test.patch
306 popping test.patch
307 patch queue now empty
307 patch queue now empty
308 $ checkundo qpop
308 $ checkundo qpop
309
309
310
310
311 qpush with dump of tag cache
311 qpush with dump of tag cache
312 Dump the tag cache to ensure that it has exactly one head after qpush.
312 Dump the tag cache to ensure that it has exactly one head after qpush.
313
313
314 $ rm -f .hg/cache/tags
314 $ rm -f .hg/cache/tags
315 $ hg tags > /dev/null
315 $ hg tags > /dev/null
316
316
317 .hg/cache/tags (pre qpush):
317 .hg/cache/tags (pre qpush):
318
318
319 $ cat .hg/cache/tags
319 $ cat .hg/cache/tags
320 1 [\da-f]{40} (re)
320 1 [\da-f]{40} (re)
321
321
322 $ hg qpush
322 $ hg qpush
323 applying test.patch
323 applying test.patch
324 now at: test.patch
324 now at: test.patch
325 $ hg phase -r qbase
325 $ hg phase -r qbase
326 2: draft
326 2: draft
327 $ hg tags > /dev/null
327 $ hg tags > /dev/null
328
328
329 .hg/cache/tags (post qpush):
329 .hg/cache/tags (post qpush):
330
330
331 $ cat .hg/cache/tags
331 $ cat .hg/cache/tags
332 2 [\da-f]{40} (re)
332 2 [\da-f]{40} (re)
333
333
334 $ checkundo qpush
334 $ checkundo qpush
335 $ cd ..
335 $ cd ..
336
336
337
337
338 pop/push outside repo
338 pop/push outside repo
339 $ hg -R a qpop
339 $ hg -R a qpop
340 popping test.patch
340 popping test.patch
341 patch queue now empty
341 patch queue now empty
342 $ hg -R a qpush
342 $ hg -R a qpush
343 applying test.patch
343 applying test.patch
344 now at: test.patch
344 now at: test.patch
345
345
346 $ cd a
346 $ cd a
347 $ hg qnew test2.patch
347 $ hg qnew test2.patch
348
348
349 qrefresh in subdir
349 qrefresh in subdir
350
350
351 $ cd b
351 $ cd b
352 $ echo a > a
352 $ echo a > a
353 $ hg add a
353 $ hg add a
354 $ hg qrefresh
354 $ hg qrefresh
355
355
356 pop/push -a in subdir
356 pop/push -a in subdir
357
357
358 $ hg qpop -a
358 $ hg qpop -a
359 popping test2.patch
359 popping test2.patch
360 popping test.patch
360 popping test.patch
361 patch queue now empty
361 patch queue now empty
362 $ hg --traceback qpush -a
362 $ hg --traceback qpush -a
363 applying test.patch
363 applying test.patch
364 applying test2.patch
364 applying test2.patch
365 now at: test2.patch
365 now at: test2.patch
366
366
367
367
368 setting columns & formatted tests truncating (issue1912)
368 setting columns & formatted tests truncating (issue1912)
369
369
370 $ COLUMNS=4 hg qseries --config ui.formatted=true
370 $ COLUMNS=4 hg qseries --config ui.formatted=true
371 test.patch
371 test.patch
372 test2.patch
372 test2.patch
373 $ COLUMNS=20 hg qseries --config ui.formatted=true -vs
373 $ COLUMNS=20 hg qseries --config ui.formatted=true -vs
374 0 A test.patch: f...
374 0 A test.patch: f...
375 1 A test2.patch:
375 1 A test2.patch:
376 $ hg qpop
376 $ hg qpop
377 popping test2.patch
377 popping test2.patch
378 now at: test.patch
378 now at: test.patch
379 $ hg qseries -vs
379 $ hg qseries -vs
380 0 A test.patch: foo bar
380 0 A test.patch: foo bar
381 1 U test2.patch:
381 1 U test2.patch:
382 $ hg sum | grep mq
382 $ hg sum | grep mq
383 mq: 1 applied, 1 unapplied
383 mq: 1 applied, 1 unapplied
384 $ hg qpush
384 $ hg qpush
385 applying test2.patch
385 applying test2.patch
386 now at: test2.patch
386 now at: test2.patch
387 $ hg sum | grep mq
387 $ hg sum | grep mq
388 mq: 2 applied
388 mq: 2 applied
389 $ hg qapplied
389 $ hg qapplied
390 test.patch
390 test.patch
391 test2.patch
391 test2.patch
392 $ hg qtop
392 $ hg qtop
393 test2.patch
393 test2.patch
394
394
395
395
396 prev
396 prev
397
397
398 $ hg qapp -1
398 $ hg qapp -1
399 test.patch
399 test.patch
400
400
401 next
401 next
402
402
403 $ hg qunapp -1
403 $ hg qunapp -1
404 all patches applied
404 all patches applied
405 [1]
405 [1]
406
406
407 $ hg qpop
407 $ hg qpop
408 popping test2.patch
408 popping test2.patch
409 now at: test.patch
409 now at: test.patch
410
410
411 commit should fail
411 commit should fail
412
412
413 $ hg commit
413 $ hg commit
414 abort: cannot commit over an applied mq patch
414 abort: cannot commit over an applied mq patch
415 [255]
415 [255]
416
416
417 push should fail if draft
417 push should fail if draft
418
418
419 $ hg push ../../k
419 $ hg push ../../k
420 pushing to ../../k
420 pushing to ../../k
421 abort: source has mq patches applied
421 abort: source has mq patches applied
422 [255]
422 [255]
423
423
424
424
425 import should fail
425 import should fail
426
426
427 $ hg st .
427 $ hg st .
428 $ echo foo >> ../a
428 $ echo foo >> ../a
429 $ hg diff > ../../import.diff
429 $ hg diff > ../../import.diff
430 $ hg revert --no-backup ../a
430 $ hg revert --no-backup ../a
431 $ hg import ../../import.diff
431 $ hg import ../../import.diff
432 abort: cannot import over an applied patch
432 abort: cannot import over an applied patch
433 [255]
433 [255]
434 $ hg st
434 $ hg st
435
435
436 import --no-commit should succeed
436 import --no-commit should succeed
437
437
438 $ hg import --no-commit ../../import.diff
438 $ hg import --no-commit ../../import.diff
439 applying ../../import.diff
439 applying ../../import.diff
440 $ hg st
440 $ hg st
441 M a
441 M a
442 $ hg revert --no-backup ../a
442 $ hg revert --no-backup ../a
443
443
444
444
445 qunapplied
445 qunapplied
446
446
447 $ hg qunapplied
447 $ hg qunapplied
448 test2.patch
448 test2.patch
449
449
450
450
451 qpush/qpop with index
451 qpush/qpop with index
452
452
453 $ hg qnew test1b.patch
453 $ hg qnew test1b.patch
454 $ echo 1b > 1b
454 $ echo 1b > 1b
455 $ hg add 1b
455 $ hg add 1b
456 $ hg qrefresh
456 $ hg qrefresh
457 $ hg qpush 2
457 $ hg qpush 2
458 applying test2.patch
458 applying test2.patch
459 now at: test2.patch
459 now at: test2.patch
460 $ hg qpop 0
460 $ hg qpop 0
461 popping test2.patch
461 popping test2.patch
462 popping test1b.patch
462 popping test1b.patch
463 now at: test.patch
463 now at: test.patch
464 $ hg qpush test.patch+1
464 $ hg qpush test.patch+1
465 applying test1b.patch
465 applying test1b.patch
466 now at: test1b.patch
466 now at: test1b.patch
467 $ hg qpush test.patch+2
467 $ hg qpush test.patch+2
468 applying test2.patch
468 applying test2.patch
469 now at: test2.patch
469 now at: test2.patch
470 $ hg qpop test2.patch-1
470 $ hg qpop test2.patch-1
471 popping test2.patch
471 popping test2.patch
472 now at: test1b.patch
472 now at: test1b.patch
473 $ hg qpop test2.patch-2
473 $ hg qpop test2.patch-2
474 popping test1b.patch
474 popping test1b.patch
475 now at: test.patch
475 now at: test.patch
476 $ hg qpush test1b.patch+1
476 $ hg qpush test1b.patch+1
477 applying test1b.patch
477 applying test1b.patch
478 applying test2.patch
478 applying test2.patch
479 now at: test2.patch
479 now at: test2.patch
480
480
481
481
482 qpush --move
482 qpush --move
483
483
484 $ hg qpop -a
484 $ hg qpop -a
485 popping test2.patch
485 popping test2.patch
486 popping test1b.patch
486 popping test1b.patch
487 popping test.patch
487 popping test.patch
488 patch queue now empty
488 patch queue now empty
489 $ hg qguard test1b.patch -- -negguard
489 $ hg qguard test1b.patch -- -negguard
490 $ hg qguard test2.patch -- +posguard
490 $ hg qguard test2.patch -- +posguard
491 $ hg qpush --move test2.patch # can't move guarded patch
491 $ hg qpush --move test2.patch # can't move guarded patch
492 cannot push 'test2.patch' - guarded by '+posguard'
492 cannot push 'test2.patch' - guarded by '+posguard'
493 [1]
493 [1]
494 $ hg qselect posguard
494 $ hg qselect posguard
495 number of unguarded, unapplied patches has changed from 2 to 3
495 number of unguarded, unapplied patches has changed from 2 to 3
496 $ hg qpush --move test2.patch # move to front
496 $ hg qpush --move test2.patch # move to front
497 applying test2.patch
497 applying test2.patch
498 now at: test2.patch
498 now at: test2.patch
499 $ hg qpush --move test1b.patch # negative guard unselected
499 $ hg qpush --move test1b.patch # negative guard unselected
500 applying test1b.patch
500 applying test1b.patch
501 now at: test1b.patch
501 now at: test1b.patch
502 $ hg qpush --move test.patch # noop move
502 $ hg qpush --move test.patch # noop move
503 applying test.patch
503 applying test.patch
504 now at: test.patch
504 now at: test.patch
505 $ hg qseries -v
505 $ hg qseries -v
506 0 A test2.patch
506 0 A test2.patch
507 1 A test1b.patch
507 1 A test1b.patch
508 2 A test.patch
508 2 A test.patch
509 $ hg qpop -a
509 $ hg qpop -a
510 popping test.patch
510 popping test.patch
511 popping test1b.patch
511 popping test1b.patch
512 popping test2.patch
512 popping test2.patch
513 patch queue now empty
513 patch queue now empty
514
514
515 cleaning up
515 cleaning up
516
516
517 $ hg qselect --none
517 $ hg qselect --none
518 guards deactivated
518 guards deactivated
519 number of unguarded, unapplied patches has changed from 3 to 2
519 number of unguarded, unapplied patches has changed from 3 to 2
520 $ hg qguard --none test1b.patch
520 $ hg qguard --none test1b.patch
521 $ hg qguard --none test2.patch
521 $ hg qguard --none test2.patch
522 $ hg qpush --move test.patch
522 $ hg qpush --move test.patch
523 applying test.patch
523 applying test.patch
524 now at: test.patch
524 now at: test.patch
525 $ hg qpush --move test1b.patch
525 $ hg qpush --move test1b.patch
526 applying test1b.patch
526 applying test1b.patch
527 now at: test1b.patch
527 now at: test1b.patch
528 $ hg qpush --move bogus # nonexistent patch
528 $ hg qpush --move bogus # nonexistent patch
529 abort: patch bogus not in series
529 abort: patch bogus not in series
530 [255]
530 [255]
531 $ hg qpush --move # no patch
531 $ hg qpush --move # no patch
532 abort: please specify the patch to move
532 abort: please specify the patch to move
533 [255]
533 [255]
534 $ hg qpush --move test.patch # already applied
534 $ hg qpush --move test.patch # already applied
535 abort: cannot push to a previous patch: test.patch
535 abort: cannot push to a previous patch: test.patch
536 [255]
536 [255]
537 $ sed '2i\
537 $ sed '2i\
538 > # make qtip index different in series and fullseries
538 > # make qtip index different in series and fullseries
539 > ' `hg root`/.hg/patches/series > $TESTTMP/sedtmp
539 > ' `hg root`/.hg/patches/series > $TESTTMP/sedtmp
540 $ cp $TESTTMP/sedtmp `hg root`/.hg/patches/series
540 $ cp $TESTTMP/sedtmp `hg root`/.hg/patches/series
541 $ cat `hg root`/.hg/patches/series
541 $ cat `hg root`/.hg/patches/series
542 # comment
542 # comment
543 # make qtip index different in series and fullseries
543 # make qtip index different in series and fullseries
544
544
545 test.patch
545 test.patch
546 test1b.patch
546 test1b.patch
547 test2.patch
547 test2.patch
548 $ hg qpush --move test2.patch
548 $ hg qpush --move test2.patch
549 applying test2.patch
549 applying test2.patch
550 now at: test2.patch
550 now at: test2.patch
551
551
552
552
553 series after move
553 series after move
554
554
555 $ cat `hg root`/.hg/patches/series
555 $ cat `hg root`/.hg/patches/series
556 # comment
556 # comment
557 # make qtip index different in series and fullseries
557 # make qtip index different in series and fullseries
558
558
559 test.patch
559 test.patch
560 test1b.patch
560 test1b.patch
561 test2.patch
561 test2.patch
562
562
563
563
564 pop, qapplied, qunapplied
564 pop, qapplied, qunapplied
565
565
566 $ hg qseries -v
566 $ hg qseries -v
567 0 A test.patch
567 0 A test.patch
568 1 A test1b.patch
568 1 A test1b.patch
569 2 A test2.patch
569 2 A test2.patch
570
570
571 qapplied -1 test.patch
571 qapplied -1 test.patch
572
572
573 $ hg qapplied -1 test.patch
573 $ hg qapplied -1 test.patch
574 only one patch applied
574 only one patch applied
575 [1]
575 [1]
576
576
577 qapplied -1 test1b.patch
577 qapplied -1 test1b.patch
578
578
579 $ hg qapplied -1 test1b.patch
579 $ hg qapplied -1 test1b.patch
580 test.patch
580 test.patch
581
581
582 qapplied -1 test2.patch
582 qapplied -1 test2.patch
583
583
584 $ hg qapplied -1 test2.patch
584 $ hg qapplied -1 test2.patch
585 test1b.patch
585 test1b.patch
586
586
587 qapplied -1
587 qapplied -1
588
588
589 $ hg qapplied -1
589 $ hg qapplied -1
590 test1b.patch
590 test1b.patch
591
591
592 qapplied
592 qapplied
593
593
594 $ hg qapplied
594 $ hg qapplied
595 test.patch
595 test.patch
596 test1b.patch
596 test1b.patch
597 test2.patch
597 test2.patch
598
598
599 qapplied test1b.patch
599 qapplied test1b.patch
600
600
601 $ hg qapplied test1b.patch
601 $ hg qapplied test1b.patch
602 test.patch
602 test.patch
603 test1b.patch
603 test1b.patch
604
604
605 qunapplied -1
605 qunapplied -1
606
606
607 $ hg qunapplied -1
607 $ hg qunapplied -1
608 all patches applied
608 all patches applied
609 [1]
609 [1]
610
610
611 qunapplied
611 qunapplied
612
612
613 $ hg qunapplied
613 $ hg qunapplied
614
614
615 popping
615 popping
616
616
617 $ hg qpop
617 $ hg qpop
618 popping test2.patch
618 popping test2.patch
619 now at: test1b.patch
619 now at: test1b.patch
620
620
621 qunapplied -1
621 qunapplied -1
622
622
623 $ hg qunapplied -1
623 $ hg qunapplied -1
624 test2.patch
624 test2.patch
625
625
626 qunapplied
626 qunapplied
627
627
628 $ hg qunapplied
628 $ hg qunapplied
629 test2.patch
629 test2.patch
630
630
631 qunapplied test2.patch
631 qunapplied test2.patch
632
632
633 $ hg qunapplied test2.patch
633 $ hg qunapplied test2.patch
634
634
635 qunapplied -1 test2.patch
635 qunapplied -1 test2.patch
636
636
637 $ hg qunapplied -1 test2.patch
637 $ hg qunapplied -1 test2.patch
638 all patches applied
638 all patches applied
639 [1]
639 [1]
640
640
641 popping -a
641 popping -a
642
642
643 $ hg qpop -a
643 $ hg qpop -a
644 popping test1b.patch
644 popping test1b.patch
645 popping test.patch
645 popping test.patch
646 patch queue now empty
646 patch queue now empty
647
647
648 qapplied
648 qapplied
649
649
650 $ hg qapplied
650 $ hg qapplied
651
651
652 qapplied -1
652 qapplied -1
653
653
654 $ hg qapplied -1
654 $ hg qapplied -1
655 no patches applied
655 no patches applied
656 [1]
656 [1]
657 $ hg qpush
657 $ hg qpush
658 applying test.patch
658 applying test.patch
659 now at: test.patch
659 now at: test.patch
660
660
661
661
662 push should succeed
662 push should succeed
663
663
664 $ hg qpop -a
664 $ hg qpop -a
665 popping test.patch
665 popping test.patch
666 patch queue now empty
666 patch queue now empty
667 $ hg push ../../k
667 $ hg push ../../k
668 pushing to ../../k
668 pushing to ../../k
669 searching for changes
669 searching for changes
670 adding changesets
670 adding changesets
671 adding manifests
671 adding manifests
672 adding file changes
672 adding file changes
673 added 1 changesets with 1 changes to 1 files
673 added 1 changesets with 1 changes to 1 files
674
674
675
675
676 we want to start with some patches applied
676 we want to start with some patches applied
677
677
678 $ hg qpush -a
678 $ hg qpush -a
679 applying test.patch
679 applying test.patch
680 applying test1b.patch
680 applying test1b.patch
681 applying test2.patch
681 applying test2.patch
682 now at: test2.patch
682 now at: test2.patch
683
683
684 % pops all patches and succeeds
684 % pops all patches and succeeds
685
685
686 $ hg qpop -a
686 $ hg qpop -a
687 popping test2.patch
687 popping test2.patch
688 popping test1b.patch
688 popping test1b.patch
689 popping test.patch
689 popping test.patch
690 patch queue now empty
690 patch queue now empty
691
691
692 % does nothing and succeeds
692 % does nothing and succeeds
693
693
694 $ hg qpop -a
694 $ hg qpop -a
695 no patches applied
695 no patches applied
696
696
697 % fails - nothing else to pop
697 % fails - nothing else to pop
698
698
699 $ hg qpop
699 $ hg qpop
700 no patches applied
700 no patches applied
701 [1]
701 [1]
702
702
703 % pushes a patch and succeeds
703 % pushes a patch and succeeds
704
704
705 $ hg qpush
705 $ hg qpush
706 applying test.patch
706 applying test.patch
707 now at: test.patch
707 now at: test.patch
708
708
709 % pops a patch and succeeds
709 % pops a patch and succeeds
710
710
711 $ hg qpop
711 $ hg qpop
712 popping test.patch
712 popping test.patch
713 patch queue now empty
713 patch queue now empty
714
714
715 % pushes up to test1b.patch and succeeds
715 % pushes up to test1b.patch and succeeds
716
716
717 $ hg qpush test1b.patch
717 $ hg qpush test1b.patch
718 applying test.patch
718 applying test.patch
719 applying test1b.patch
719 applying test1b.patch
720 now at: test1b.patch
720 now at: test1b.patch
721
721
722 % does nothing and succeeds
722 % does nothing and succeeds
723
723
724 $ hg qpush test1b.patch
724 $ hg qpush test1b.patch
725 qpush: test1b.patch is already at the top
725 qpush: test1b.patch is already at the top
726
726
727 % does nothing and succeeds
727 % does nothing and succeeds
728
728
729 $ hg qpop test1b.patch
729 $ hg qpop test1b.patch
730 qpop: test1b.patch is already at the top
730 qpop: test1b.patch is already at the top
731
731
732 % fails - can't push to this patch
732 % fails - can't push to this patch
733
733
734 $ hg qpush test.patch
734 $ hg qpush test.patch
735 abort: cannot push to a previous patch: test.patch
735 abort: cannot push to a previous patch: test.patch
736 [255]
736 [255]
737
737
738 % fails - can't pop to this patch
738 % fails - can't pop to this patch
739
739
740 $ hg qpop test2.patch
740 $ hg qpop test2.patch
741 abort: patch test2.patch is not applied
741 abort: patch test2.patch is not applied
742 [255]
742 [255]
743
743
744 % pops up to test.patch and succeeds
744 % pops up to test.patch and succeeds
745
745
746 $ hg qpop test.patch
746 $ hg qpop test.patch
747 popping test1b.patch
747 popping test1b.patch
748 now at: test.patch
748 now at: test.patch
749
749
750 % pushes all patches and succeeds
750 % pushes all patches and succeeds
751
751
752 $ hg qpush -a
752 $ hg qpush -a
753 applying test1b.patch
753 applying test1b.patch
754 applying test2.patch
754 applying test2.patch
755 now at: test2.patch
755 now at: test2.patch
756
756
757 % does nothing and succeeds
757 % does nothing and succeeds
758
758
759 $ hg qpush -a
759 $ hg qpush -a
760 all patches are currently applied
760 all patches are currently applied
761
761
762 % fails - nothing else to push
762 % fails - nothing else to push
763
763
764 $ hg qpush
764 $ hg qpush
765 patch series already fully applied
765 patch series already fully applied
766 [1]
766 [1]
767
767
768 % does nothing and succeeds
768 % does nothing and succeeds
769
769
770 $ hg qpush test2.patch
770 $ hg qpush test2.patch
771 qpush: test2.patch is already at the top
771 qpush: test2.patch is already at the top
772
772
773 strip
773 strip
774
774
775 $ cd ../../b
775 $ cd ../../b
776 $ echo x>x
776 $ echo x>x
777 $ hg ci -Ama
777 $ hg ci -Ama
778 adding x
778 adding x
779 $ hg strip tip
779 $ hg strip tip
780 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
780 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
781 saved backup bundle to $TESTTMP/b/.hg/strip-backup/*-backup.hg (glob)
781 saved backup bundle to $TESTTMP/b/.hg/strip-backup/*-backup.hg (glob)
782 $ hg unbundle .hg/strip-backup/*
782 $ hg unbundle .hg/strip-backup/*
783 adding changesets
783 adding changesets
784 adding manifests
784 adding manifests
785 adding file changes
785 adding file changes
786 added 1 changesets with 1 changes to 1 files
786 added 1 changesets with 1 changes to 1 files
787 (run 'hg update' to get a working copy)
787 (run 'hg update' to get a working copy)
788
788
789
789
790 strip with local changes, should complain
790 strip with local changes, should complain
791
791
792 $ hg up
792 $ hg up
793 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
793 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
794 $ echo y>y
794 $ echo y>y
795 $ hg add y
795 $ hg add y
796 $ hg strip tip
796 $ hg strip tip
797 abort: local changes found
797 abort: local changes found
798 [255]
798 [255]
799
799
800 --force strip with local changes
800 --force strip with local changes
801
801
802 $ hg strip -f tip
802 $ hg strip -f tip
803 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
803 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
804 saved backup bundle to $TESTTMP/b/.hg/strip-backup/770eb8fce608-0ddcae0f-backup.hg (glob)
804 saved backup bundle to $TESTTMP/b/.hg/strip-backup/770eb8fce608-0ddcae0f-backup.hg (glob)
805 $ cd ..
805 $ cd ..
806
806
807
807
808 cd b; hg qrefresh
808 cd b; hg qrefresh
809
809
810 $ hg init refresh
810 $ hg init refresh
811 $ cd refresh
811 $ cd refresh
812 $ echo a > a
812 $ echo a > a
813 $ hg ci -Ama
813 $ hg ci -Ama
814 adding a
814 adding a
815 $ hg qnew -mfoo foo
815 $ hg qnew -mfoo foo
816 $ echo a >> a
816 $ echo a >> a
817 $ hg qrefresh
817 $ hg qrefresh
818 $ mkdir b
818 $ mkdir b
819 $ cd b
819 $ cd b
820 $ echo f > f
820 $ echo f > f
821 $ hg add f
821 $ hg add f
822 $ hg qrefresh
822 $ hg qrefresh
823 $ cat ../.hg/patches/foo
823 $ cat ../.hg/patches/foo
824 foo
824 foo
825
825
826 diff -r cb9a9f314b8b a
826 diff -r cb9a9f314b8b a
827 --- a/a\t(?P<date>.*) (re)
827 --- a/a\t(?P<date>.*) (re)
828 \+\+\+ b/a\t(?P<date>.*) (re)
828 \+\+\+ b/a\t(?P<date>.*) (re)
829 @@ -1,1 +1,2 @@
829 @@ -1,1 +1,2 @@
830 a
830 a
831 +a
831 +a
832 diff -r cb9a9f314b8b b/f
832 diff -r cb9a9f314b8b b/f
833 --- /dev/null\t(?P<date>.*) (re)
833 --- /dev/null\t(?P<date>.*) (re)
834 \+\+\+ b/b/f\t(?P<date>.*) (re)
834 \+\+\+ b/b/f\t(?P<date>.*) (re)
835 @@ -0,0 +1,1 @@
835 @@ -0,0 +1,1 @@
836 +f
836 +f
837
837
838 hg qrefresh .
838 hg qrefresh .
839
839
840 $ hg qrefresh .
840 $ hg qrefresh .
841 $ cat ../.hg/patches/foo
841 $ cat ../.hg/patches/foo
842 foo
842 foo
843
843
844 diff -r cb9a9f314b8b b/f
844 diff -r cb9a9f314b8b b/f
845 --- /dev/null\t(?P<date>.*) (re)
845 --- /dev/null\t(?P<date>.*) (re)
846 \+\+\+ b/b/f\t(?P<date>.*) (re)
846 \+\+\+ b/b/f\t(?P<date>.*) (re)
847 @@ -0,0 +1,1 @@
847 @@ -0,0 +1,1 @@
848 +f
848 +f
849 $ hg status
849 $ hg status
850 M a
850 M a
851
851
852
852
853 qpush failure
853 qpush failure
854
854
855 $ cd ..
855 $ cd ..
856 $ hg qrefresh
856 $ hg qrefresh
857 $ hg qnew -mbar bar
857 $ hg qnew -mbar bar
858 $ echo foo > foo
858 $ echo foo > foo
859 $ echo bar > bar
859 $ echo bar > bar
860 $ hg add foo bar
860 $ hg add foo bar
861 $ hg qrefresh
861 $ hg qrefresh
862 $ hg qpop -a
862 $ hg qpop -a
863 popping bar
863 popping bar
864 popping foo
864 popping foo
865 patch queue now empty
865 patch queue now empty
866 $ echo bar > foo
866 $ echo bar > foo
867 $ hg qpush -a
867 $ hg qpush -a
868 applying foo
868 applying foo
869 applying bar
869 applying bar
870 file foo already exists
870 file foo already exists
871 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
871 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
872 patch failed, unable to continue (try -v)
872 patch failed, unable to continue (try -v)
873 patch failed, rejects left in working dir
873 patch failed, rejects left in working directory
874 errors during apply, please fix and refresh bar
874 errors during apply, please fix and refresh bar
875 [2]
875 [2]
876 $ hg st
876 $ hg st
877 ? foo
877 ? foo
878 ? foo.rej
878 ? foo.rej
879
879
880
880
881 mq tags
881 mq tags
882
882
883 $ hg log --template '{rev} {tags}\n' -r qparent:qtip
883 $ hg log --template '{rev} {tags}\n' -r qparent:qtip
884 0 qparent
884 0 qparent
885 1 foo qbase
885 1 foo qbase
886 2 bar qtip tip
886 2 bar qtip tip
887
887
888 mq revset
888 mq revset
889
889
890 $ hg log -r 'mq()' --template '{rev}\n'
890 $ hg log -r 'mq()' --template '{rev}\n'
891 1
891 1
892 2
892 2
893 $ hg help revsets | grep -i mq
893 $ hg help revsets | grep -i mq
894 "mq()"
894 "mq()"
895 Changesets managed by MQ.
895 Changesets managed by MQ.
896
896
897 bad node in status
897 bad node in status
898
898
899 $ hg qpop
899 $ hg qpop
900 popping bar
900 popping bar
901 now at: foo
901 now at: foo
902 $ hg strip -qn tip
902 $ hg strip -qn tip
903 $ hg tip
903 $ hg tip
904 changeset: 0:cb9a9f314b8b
904 changeset: 0:cb9a9f314b8b
905 tag: tip
905 tag: tip
906 user: test
906 user: test
907 date: Thu Jan 01 00:00:00 1970 +0000
907 date: Thu Jan 01 00:00:00 1970 +0000
908 summary: a
908 summary: a
909
909
910 $ hg branches
910 $ hg branches
911 default 0:cb9a9f314b8b
911 default 0:cb9a9f314b8b
912 $ hg qpop
912 $ hg qpop
913 no patches applied
913 no patches applied
914 [1]
914 [1]
915
915
916 $ cd ..
916 $ cd ..
917
917
918
918
919 git patches
919 git patches
920
920
921 $ cat >>$HGRCPATH <<EOF
921 $ cat >>$HGRCPATH <<EOF
922 > [diff]
922 > [diff]
923 > git = True
923 > git = True
924 > EOF
924 > EOF
925 $ hg init git
925 $ hg init git
926 $ cd git
926 $ cd git
927 $ hg qinit
927 $ hg qinit
928
928
929 $ hg qnew -m'new file' new
929 $ hg qnew -m'new file' new
930 $ echo foo > new
930 $ echo foo > new
931 #if execbit
931 #if execbit
932 $ chmod +x new
932 $ chmod +x new
933 #endif
933 #endif
934 $ hg add new
934 $ hg add new
935 $ hg qrefresh
935 $ hg qrefresh
936 #if execbit
936 #if execbit
937 $ cat .hg/patches/new
937 $ cat .hg/patches/new
938 new file
938 new file
939
939
940 diff --git a/new b/new
940 diff --git a/new b/new
941 new file mode 100755
941 new file mode 100755
942 --- /dev/null
942 --- /dev/null
943 +++ b/new
943 +++ b/new
944 @@ -0,0 +1,1 @@
944 @@ -0,0 +1,1 @@
945 +foo
945 +foo
946 #else
946 #else
947 $ cat .hg/patches/new
947 $ cat .hg/patches/new
948 new file
948 new file
949
949
950 diff --git a/new b/new
950 diff --git a/new b/new
951 new file mode 100644
951 new file mode 100644
952 --- /dev/null
952 --- /dev/null
953 +++ b/new
953 +++ b/new
954 @@ -0,0 +1,1 @@
954 @@ -0,0 +1,1 @@
955 +foo
955 +foo
956 #endif
956 #endif
957
957
958 $ hg qnew -m'copy file' copy
958 $ hg qnew -m'copy file' copy
959 $ hg cp new copy
959 $ hg cp new copy
960 $ hg qrefresh
960 $ hg qrefresh
961 $ cat .hg/patches/copy
961 $ cat .hg/patches/copy
962 copy file
962 copy file
963
963
964 diff --git a/new b/copy
964 diff --git a/new b/copy
965 copy from new
965 copy from new
966 copy to copy
966 copy to copy
967
967
968 $ hg qpop
968 $ hg qpop
969 popping copy
969 popping copy
970 now at: new
970 now at: new
971 $ hg qpush
971 $ hg qpush
972 applying copy
972 applying copy
973 now at: copy
973 now at: copy
974 $ hg qdiff
974 $ hg qdiff
975 diff --git a/new b/copy
975 diff --git a/new b/copy
976 copy from new
976 copy from new
977 copy to copy
977 copy to copy
978 $ cat >>$HGRCPATH <<EOF
978 $ cat >>$HGRCPATH <<EOF
979 > [diff]
979 > [diff]
980 > git = False
980 > git = False
981 > EOF
981 > EOF
982 $ hg qdiff --git
982 $ hg qdiff --git
983 diff --git a/new b/copy
983 diff --git a/new b/copy
984 copy from new
984 copy from new
985 copy to copy
985 copy to copy
986 $ cd ..
986 $ cd ..
987
987
988 empty lines in status
988 empty lines in status
989
989
990 $ hg init emptystatus
990 $ hg init emptystatus
991 $ cd emptystatus
991 $ cd emptystatus
992 $ hg qinit
992 $ hg qinit
993 $ printf '\n\n' > .hg/patches/status
993 $ printf '\n\n' > .hg/patches/status
994 $ hg qser
994 $ hg qser
995 $ cd ..
995 $ cd ..
996
996
997 bad line in status (without ":")
997 bad line in status (without ":")
998
998
999 $ hg init badstatus
999 $ hg init badstatus
1000 $ cd badstatus
1000 $ cd badstatus
1001 $ hg qinit
1001 $ hg qinit
1002 $ printf 'babar has no colon in this line\n' > .hg/patches/status
1002 $ printf 'babar has no colon in this line\n' > .hg/patches/status
1003 $ hg qser
1003 $ hg qser
1004 malformated mq status line: ['babar has no colon in this line']
1004 malformated mq status line: ['babar has no colon in this line']
1005 $ cd ..
1005 $ cd ..
1006
1006
1007
1007
1008 test file addition in slow path
1008 test file addition in slow path
1009
1009
1010 $ hg init slow
1010 $ hg init slow
1011 $ cd slow
1011 $ cd slow
1012 $ hg qinit
1012 $ hg qinit
1013 $ echo foo > foo
1013 $ echo foo > foo
1014 $ hg add foo
1014 $ hg add foo
1015 $ hg ci -m 'add foo'
1015 $ hg ci -m 'add foo'
1016 $ hg qnew bar
1016 $ hg qnew bar
1017 $ echo bar > bar
1017 $ echo bar > bar
1018 $ hg add bar
1018 $ hg add bar
1019 $ hg mv foo baz
1019 $ hg mv foo baz
1020 $ hg qrefresh --git
1020 $ hg qrefresh --git
1021 $ hg up -C 0
1021 $ hg up -C 0
1022 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
1022 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
1023 $ echo >> foo
1023 $ echo >> foo
1024 $ hg ci -m 'change foo'
1024 $ hg ci -m 'change foo'
1025 created new head
1025 created new head
1026 $ hg up -C 1
1026 $ hg up -C 1
1027 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
1027 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
1028 $ hg qrefresh --git
1028 $ hg qrefresh --git
1029 $ cat .hg/patches/bar
1029 $ cat .hg/patches/bar
1030 diff --git a/bar b/bar
1030 diff --git a/bar b/bar
1031 new file mode 100644
1031 new file mode 100644
1032 --- /dev/null
1032 --- /dev/null
1033 +++ b/bar
1033 +++ b/bar
1034 @@ -0,0 +1,1 @@
1034 @@ -0,0 +1,1 @@
1035 +bar
1035 +bar
1036 diff --git a/foo b/baz
1036 diff --git a/foo b/baz
1037 rename from foo
1037 rename from foo
1038 rename to baz
1038 rename to baz
1039 $ hg log -v --template '{rev} {file_copies}\n' -r .
1039 $ hg log -v --template '{rev} {file_copies}\n' -r .
1040 2 baz (foo)
1040 2 baz (foo)
1041 $ hg qrefresh --git
1041 $ hg qrefresh --git
1042 $ cat .hg/patches/bar
1042 $ cat .hg/patches/bar
1043 diff --git a/bar b/bar
1043 diff --git a/bar b/bar
1044 new file mode 100644
1044 new file mode 100644
1045 --- /dev/null
1045 --- /dev/null
1046 +++ b/bar
1046 +++ b/bar
1047 @@ -0,0 +1,1 @@
1047 @@ -0,0 +1,1 @@
1048 +bar
1048 +bar
1049 diff --git a/foo b/baz
1049 diff --git a/foo b/baz
1050 rename from foo
1050 rename from foo
1051 rename to baz
1051 rename to baz
1052 $ hg log -v --template '{rev} {file_copies}\n' -r .
1052 $ hg log -v --template '{rev} {file_copies}\n' -r .
1053 2 baz (foo)
1053 2 baz (foo)
1054 $ hg qrefresh
1054 $ hg qrefresh
1055 $ grep 'diff --git' .hg/patches/bar
1055 $ grep 'diff --git' .hg/patches/bar
1056 diff --git a/bar b/bar
1056 diff --git a/bar b/bar
1057 diff --git a/foo b/baz
1057 diff --git a/foo b/baz
1058
1058
1059
1059
1060 test file move chains in the slow path
1060 test file move chains in the slow path
1061
1061
1062 $ hg up -C 1
1062 $ hg up -C 1
1063 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
1063 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
1064 $ echo >> foo
1064 $ echo >> foo
1065 $ hg ci -m 'change foo again'
1065 $ hg ci -m 'change foo again'
1066 $ hg up -C 2
1066 $ hg up -C 2
1067 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
1067 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
1068 $ hg mv bar quux
1068 $ hg mv bar quux
1069 $ hg mv baz bleh
1069 $ hg mv baz bleh
1070 $ hg qrefresh --git
1070 $ hg qrefresh --git
1071 $ cat .hg/patches/bar
1071 $ cat .hg/patches/bar
1072 diff --git a/foo b/bleh
1072 diff --git a/foo b/bleh
1073 rename from foo
1073 rename from foo
1074 rename to bleh
1074 rename to bleh
1075 diff --git a/quux b/quux
1075 diff --git a/quux b/quux
1076 new file mode 100644
1076 new file mode 100644
1077 --- /dev/null
1077 --- /dev/null
1078 +++ b/quux
1078 +++ b/quux
1079 @@ -0,0 +1,1 @@
1079 @@ -0,0 +1,1 @@
1080 +bar
1080 +bar
1081 $ hg log -v --template '{rev} {file_copies}\n' -r .
1081 $ hg log -v --template '{rev} {file_copies}\n' -r .
1082 3 bleh (foo)
1082 3 bleh (foo)
1083 $ hg mv quux fred
1083 $ hg mv quux fred
1084 $ hg mv bleh barney
1084 $ hg mv bleh barney
1085 $ hg qrefresh --git
1085 $ hg qrefresh --git
1086 $ cat .hg/patches/bar
1086 $ cat .hg/patches/bar
1087 diff --git a/foo b/barney
1087 diff --git a/foo b/barney
1088 rename from foo
1088 rename from foo
1089 rename to barney
1089 rename to barney
1090 diff --git a/fred b/fred
1090 diff --git a/fred b/fred
1091 new file mode 100644
1091 new file mode 100644
1092 --- /dev/null
1092 --- /dev/null
1093 +++ b/fred
1093 +++ b/fred
1094 @@ -0,0 +1,1 @@
1094 @@ -0,0 +1,1 @@
1095 +bar
1095 +bar
1096 $ hg log -v --template '{rev} {file_copies}\n' -r .
1096 $ hg log -v --template '{rev} {file_copies}\n' -r .
1097 3 barney (foo)
1097 3 barney (foo)
1098
1098
1099
1099
1100 refresh omitting an added file
1100 refresh omitting an added file
1101
1101
1102 $ hg qnew baz
1102 $ hg qnew baz
1103 $ echo newfile > newfile
1103 $ echo newfile > newfile
1104 $ hg add newfile
1104 $ hg add newfile
1105 $ hg qrefresh
1105 $ hg qrefresh
1106 $ hg st -A newfile
1106 $ hg st -A newfile
1107 C newfile
1107 C newfile
1108 $ hg qrefresh -X newfile
1108 $ hg qrefresh -X newfile
1109 $ hg st -A newfile
1109 $ hg st -A newfile
1110 A newfile
1110 A newfile
1111 $ hg revert newfile
1111 $ hg revert newfile
1112 $ rm newfile
1112 $ rm newfile
1113 $ hg qpop
1113 $ hg qpop
1114 popping baz
1114 popping baz
1115 now at: bar
1115 now at: bar
1116
1116
1117 test qdel/qrm
1117 test qdel/qrm
1118
1118
1119 $ hg qdel baz
1119 $ hg qdel baz
1120 $ echo p >> .hg/patches/series
1120 $ echo p >> .hg/patches/series
1121 $ hg qrm p
1121 $ hg qrm p
1122 $ hg qser
1122 $ hg qser
1123 bar
1123 bar
1124
1124
1125 create a git patch
1125 create a git patch
1126
1126
1127 $ echo a > alexander
1127 $ echo a > alexander
1128 $ hg add alexander
1128 $ hg add alexander
1129 $ hg qnew -f --git addalexander
1129 $ hg qnew -f --git addalexander
1130 $ grep diff .hg/patches/addalexander
1130 $ grep diff .hg/patches/addalexander
1131 diff --git a/alexander b/alexander
1131 diff --git a/alexander b/alexander
1132
1132
1133
1133
1134 create a git binary patch
1134 create a git binary patch
1135
1135
1136 $ cat > writebin.py <<EOF
1136 $ cat > writebin.py <<EOF
1137 > import sys
1137 > import sys
1138 > path = sys.argv[1]
1138 > path = sys.argv[1]
1139 > open(path, 'wb').write('BIN\x00ARY')
1139 > open(path, 'wb').write('BIN\x00ARY')
1140 > EOF
1140 > EOF
1141 $ python writebin.py bucephalus
1141 $ python writebin.py bucephalus
1142
1142
1143 $ python "$TESTDIR/md5sum.py" bucephalus
1143 $ python "$TESTDIR/md5sum.py" bucephalus
1144 8ba2a2f3e77b55d03051ff9c24ad65e7 bucephalus
1144 8ba2a2f3e77b55d03051ff9c24ad65e7 bucephalus
1145 $ hg add bucephalus
1145 $ hg add bucephalus
1146 $ hg qnew -f --git addbucephalus
1146 $ hg qnew -f --git addbucephalus
1147 $ grep diff .hg/patches/addbucephalus
1147 $ grep diff .hg/patches/addbucephalus
1148 diff --git a/bucephalus b/bucephalus
1148 diff --git a/bucephalus b/bucephalus
1149
1149
1150
1150
1151 check binary patches can be popped and pushed
1151 check binary patches can be popped and pushed
1152
1152
1153 $ hg qpop
1153 $ hg qpop
1154 popping addbucephalus
1154 popping addbucephalus
1155 now at: addalexander
1155 now at: addalexander
1156 $ test -f bucephalus && echo % bucephalus should not be there
1156 $ test -f bucephalus && echo % bucephalus should not be there
1157 [1]
1157 [1]
1158 $ hg qpush
1158 $ hg qpush
1159 applying addbucephalus
1159 applying addbucephalus
1160 now at: addbucephalus
1160 now at: addbucephalus
1161 $ test -f bucephalus
1161 $ test -f bucephalus
1162 $ python "$TESTDIR/md5sum.py" bucephalus
1162 $ python "$TESTDIR/md5sum.py" bucephalus
1163 8ba2a2f3e77b55d03051ff9c24ad65e7 bucephalus
1163 8ba2a2f3e77b55d03051ff9c24ad65e7 bucephalus
1164
1164
1165
1165
1166
1166
1167 strip again
1167 strip again
1168
1168
1169 $ cd ..
1169 $ cd ..
1170 $ hg init strip
1170 $ hg init strip
1171 $ cd strip
1171 $ cd strip
1172 $ touch foo
1172 $ touch foo
1173 $ hg add foo
1173 $ hg add foo
1174 $ hg ci -m 'add foo'
1174 $ hg ci -m 'add foo'
1175 $ echo >> foo
1175 $ echo >> foo
1176 $ hg ci -m 'change foo 1'
1176 $ hg ci -m 'change foo 1'
1177 $ hg up -C 0
1177 $ hg up -C 0
1178 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1178 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1179 $ echo 1 >> foo
1179 $ echo 1 >> foo
1180 $ hg ci -m 'change foo 2'
1180 $ hg ci -m 'change foo 2'
1181 created new head
1181 created new head
1182 $ HGMERGE=true hg merge
1182 $ HGMERGE=true hg merge
1183 merging foo
1183 merging foo
1184 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
1184 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
1185 (branch merge, don't forget to commit)
1185 (branch merge, don't forget to commit)
1186 $ hg ci -m merge
1186 $ hg ci -m merge
1187 $ hg log
1187 $ hg log
1188 changeset: 3:99615015637b
1188 changeset: 3:99615015637b
1189 tag: tip
1189 tag: tip
1190 parent: 2:20cbbe65cff7
1190 parent: 2:20cbbe65cff7
1191 parent: 1:d2871fc282d4
1191 parent: 1:d2871fc282d4
1192 user: test
1192 user: test
1193 date: Thu Jan 01 00:00:00 1970 +0000
1193 date: Thu Jan 01 00:00:00 1970 +0000
1194 summary: merge
1194 summary: merge
1195
1195
1196 changeset: 2:20cbbe65cff7
1196 changeset: 2:20cbbe65cff7
1197 parent: 0:53245c60e682
1197 parent: 0:53245c60e682
1198 user: test
1198 user: test
1199 date: Thu Jan 01 00:00:00 1970 +0000
1199 date: Thu Jan 01 00:00:00 1970 +0000
1200 summary: change foo 2
1200 summary: change foo 2
1201
1201
1202 changeset: 1:d2871fc282d4
1202 changeset: 1:d2871fc282d4
1203 user: test
1203 user: test
1204 date: Thu Jan 01 00:00:00 1970 +0000
1204 date: Thu Jan 01 00:00:00 1970 +0000
1205 summary: change foo 1
1205 summary: change foo 1
1206
1206
1207 changeset: 0:53245c60e682
1207 changeset: 0:53245c60e682
1208 user: test
1208 user: test
1209 date: Thu Jan 01 00:00:00 1970 +0000
1209 date: Thu Jan 01 00:00:00 1970 +0000
1210 summary: add foo
1210 summary: add foo
1211
1211
1212 $ hg strip 1
1212 $ hg strip 1
1213 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1213 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1214 saved backup bundle to $TESTTMP/strip/.hg/strip-backup/*-backup.hg (glob)
1214 saved backup bundle to $TESTTMP/strip/.hg/strip-backup/*-backup.hg (glob)
1215 $ checkundo strip
1215 $ checkundo strip
1216 $ hg log
1216 $ hg log
1217 changeset: 1:20cbbe65cff7
1217 changeset: 1:20cbbe65cff7
1218 tag: tip
1218 tag: tip
1219 user: test
1219 user: test
1220 date: Thu Jan 01 00:00:00 1970 +0000
1220 date: Thu Jan 01 00:00:00 1970 +0000
1221 summary: change foo 2
1221 summary: change foo 2
1222
1222
1223 changeset: 0:53245c60e682
1223 changeset: 0:53245c60e682
1224 user: test
1224 user: test
1225 date: Thu Jan 01 00:00:00 1970 +0000
1225 date: Thu Jan 01 00:00:00 1970 +0000
1226 summary: add foo
1226 summary: add foo
1227
1227
1228 $ cd ..
1228 $ cd ..
1229
1229
1230
1230
1231 qclone
1231 qclone
1232
1232
1233 $ qlog()
1233 $ qlog()
1234 > {
1234 > {
1235 > echo 'main repo:'
1235 > echo 'main repo:'
1236 > hg log --template ' rev {rev}: {desc}\n'
1236 > hg log --template ' rev {rev}: {desc}\n'
1237 > echo 'patch repo:'
1237 > echo 'patch repo:'
1238 > hg -R .hg/patches log --template ' rev {rev}: {desc}\n'
1238 > hg -R .hg/patches log --template ' rev {rev}: {desc}\n'
1239 > }
1239 > }
1240 $ hg init qclonesource
1240 $ hg init qclonesource
1241 $ cd qclonesource
1241 $ cd qclonesource
1242 $ echo foo > foo
1242 $ echo foo > foo
1243 $ hg add foo
1243 $ hg add foo
1244 $ hg ci -m 'add foo'
1244 $ hg ci -m 'add foo'
1245 $ hg qinit
1245 $ hg qinit
1246 $ hg qnew patch1
1246 $ hg qnew patch1
1247 $ echo bar >> foo
1247 $ echo bar >> foo
1248 $ hg qrefresh -m 'change foo'
1248 $ hg qrefresh -m 'change foo'
1249 $ cd ..
1249 $ cd ..
1250
1250
1251
1251
1252 repo with unversioned patch dir
1252 repo with unversioned patch dir
1253
1253
1254 $ hg qclone qclonesource failure
1254 $ hg qclone qclonesource failure
1255 abort: versioned patch repository not found (see init --mq)
1255 abort: versioned patch repository not found (see init --mq)
1256 [255]
1256 [255]
1257
1257
1258 $ cd qclonesource
1258 $ cd qclonesource
1259 $ hg qinit -c
1259 $ hg qinit -c
1260 adding .hg/patches/patch1 (glob)
1260 adding .hg/patches/patch1 (glob)
1261 $ hg qci -m checkpoint
1261 $ hg qci -m checkpoint
1262 $ qlog
1262 $ qlog
1263 main repo:
1263 main repo:
1264 rev 1: change foo
1264 rev 1: change foo
1265 rev 0: add foo
1265 rev 0: add foo
1266 patch repo:
1266 patch repo:
1267 rev 0: checkpoint
1267 rev 0: checkpoint
1268 $ cd ..
1268 $ cd ..
1269
1269
1270
1270
1271 repo with patches applied
1271 repo with patches applied
1272
1272
1273 $ hg qclone qclonesource qclonedest
1273 $ hg qclone qclonesource qclonedest
1274 updating to branch default
1274 updating to branch default
1275 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1275 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1276 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1276 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1277 $ cd qclonedest
1277 $ cd qclonedest
1278 $ qlog
1278 $ qlog
1279 main repo:
1279 main repo:
1280 rev 0: add foo
1280 rev 0: add foo
1281 patch repo:
1281 patch repo:
1282 rev 0: checkpoint
1282 rev 0: checkpoint
1283 $ cd ..
1283 $ cd ..
1284
1284
1285
1285
1286 repo with patches unapplied
1286 repo with patches unapplied
1287
1287
1288 $ cd qclonesource
1288 $ cd qclonesource
1289 $ hg qpop -a
1289 $ hg qpop -a
1290 popping patch1
1290 popping patch1
1291 patch queue now empty
1291 patch queue now empty
1292 $ qlog
1292 $ qlog
1293 main repo:
1293 main repo:
1294 rev 0: add foo
1294 rev 0: add foo
1295 patch repo:
1295 patch repo:
1296 rev 0: checkpoint
1296 rev 0: checkpoint
1297 $ cd ..
1297 $ cd ..
1298 $ hg qclone qclonesource qclonedest2
1298 $ hg qclone qclonesource qclonedest2
1299 updating to branch default
1299 updating to branch default
1300 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1300 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1301 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1301 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1302 $ cd qclonedest2
1302 $ cd qclonedest2
1303 $ qlog
1303 $ qlog
1304 main repo:
1304 main repo:
1305 rev 0: add foo
1305 rev 0: add foo
1306 patch repo:
1306 patch repo:
1307 rev 0: checkpoint
1307 rev 0: checkpoint
1308 $ cd ..
1308 $ cd ..
1309
1309
1310
1310
1311 Issue1033: test applying on an empty file
1311 Issue1033: test applying on an empty file
1312
1312
1313 $ hg init empty
1313 $ hg init empty
1314 $ cd empty
1314 $ cd empty
1315 $ touch a
1315 $ touch a
1316 $ hg ci -Am addempty
1316 $ hg ci -Am addempty
1317 adding a
1317 adding a
1318 $ echo a > a
1318 $ echo a > a
1319 $ hg qnew -f -e changea
1319 $ hg qnew -f -e changea
1320 $ hg qpop
1320 $ hg qpop
1321 popping changea
1321 popping changea
1322 patch queue now empty
1322 patch queue now empty
1323 $ hg qpush
1323 $ hg qpush
1324 applying changea
1324 applying changea
1325 now at: changea
1325 now at: changea
1326 $ cd ..
1326 $ cd ..
1327
1327
1328 test qpush with --force, issue1087
1328 test qpush with --force, issue1087
1329
1329
1330 $ hg init forcepush
1330 $ hg init forcepush
1331 $ cd forcepush
1331 $ cd forcepush
1332 $ echo hello > hello.txt
1332 $ echo hello > hello.txt
1333 $ echo bye > bye.txt
1333 $ echo bye > bye.txt
1334 $ hg ci -Ama
1334 $ hg ci -Ama
1335 adding bye.txt
1335 adding bye.txt
1336 adding hello.txt
1336 adding hello.txt
1337 $ hg qnew -d '0 0' empty
1337 $ hg qnew -d '0 0' empty
1338 $ hg qpop
1338 $ hg qpop
1339 popping empty
1339 popping empty
1340 patch queue now empty
1340 patch queue now empty
1341 $ echo world >> hello.txt
1341 $ echo world >> hello.txt
1342
1342
1343
1343
1344 qpush should fail, local changes
1344 qpush should fail, local changes
1345
1345
1346 $ hg qpush
1346 $ hg qpush
1347 abort: local changes found
1347 abort: local changes found
1348 [255]
1348 [255]
1349
1349
1350
1350
1351 apply force, should not discard changes with empty patch
1351 apply force, should not discard changes with empty patch
1352
1352
1353 $ hg qpush -f
1353 $ hg qpush -f
1354 applying empty
1354 applying empty
1355 patch empty is empty
1355 patch empty is empty
1356 now at: empty
1356 now at: empty
1357 $ hg diff --config diff.nodates=True
1357 $ hg diff --config diff.nodates=True
1358 diff -r d58265112590 hello.txt
1358 diff -r d58265112590 hello.txt
1359 --- a/hello.txt
1359 --- a/hello.txt
1360 +++ b/hello.txt
1360 +++ b/hello.txt
1361 @@ -1,1 +1,2 @@
1361 @@ -1,1 +1,2 @@
1362 hello
1362 hello
1363 +world
1363 +world
1364 $ hg qdiff --config diff.nodates=True
1364 $ hg qdiff --config diff.nodates=True
1365 diff -r 9ecee4f634e3 hello.txt
1365 diff -r 9ecee4f634e3 hello.txt
1366 --- a/hello.txt
1366 --- a/hello.txt
1367 +++ b/hello.txt
1367 +++ b/hello.txt
1368 @@ -1,1 +1,2 @@
1368 @@ -1,1 +1,2 @@
1369 hello
1369 hello
1370 +world
1370 +world
1371 $ hg log -l1 -p
1371 $ hg log -l1 -p
1372 changeset: 1:d58265112590
1372 changeset: 1:d58265112590
1373 tag: empty
1373 tag: empty
1374 tag: qbase
1374 tag: qbase
1375 tag: qtip
1375 tag: qtip
1376 tag: tip
1376 tag: tip
1377 user: test
1377 user: test
1378 date: Thu Jan 01 00:00:00 1970 +0000
1378 date: Thu Jan 01 00:00:00 1970 +0000
1379 summary: imported patch empty
1379 summary: imported patch empty
1380
1380
1381
1381
1382 $ hg qref -d '0 0'
1382 $ hg qref -d '0 0'
1383 $ hg qpop
1383 $ hg qpop
1384 popping empty
1384 popping empty
1385 patch queue now empty
1385 patch queue now empty
1386 $ echo universe >> hello.txt
1386 $ echo universe >> hello.txt
1387 $ echo universe >> bye.txt
1387 $ echo universe >> bye.txt
1388
1388
1389
1389
1390 qpush should fail, local changes
1390 qpush should fail, local changes
1391
1391
1392 $ hg qpush
1392 $ hg qpush
1393 abort: local changes found
1393 abort: local changes found
1394 [255]
1394 [255]
1395
1395
1396
1396
1397 apply force, should discard changes in hello, but not bye
1397 apply force, should discard changes in hello, but not bye
1398
1398
1399 $ hg qpush -f --verbose
1399 $ hg qpush -f --verbose
1400 applying empty
1400 applying empty
1401 saving current version of hello.txt as hello.txt.orig
1401 saving current version of hello.txt as hello.txt.orig
1402 patching file hello.txt
1402 patching file hello.txt
1403 committing files:
1403 committing files:
1404 hello.txt
1404 hello.txt
1405 committing manifest
1405 committing manifest
1406 committing changelog
1406 committing changelog
1407 now at: empty
1407 now at: empty
1408 $ hg st
1408 $ hg st
1409 M bye.txt
1409 M bye.txt
1410 ? hello.txt.orig
1410 ? hello.txt.orig
1411 $ hg diff --config diff.nodates=True
1411 $ hg diff --config diff.nodates=True
1412 diff -r ba252371dbc1 bye.txt
1412 diff -r ba252371dbc1 bye.txt
1413 --- a/bye.txt
1413 --- a/bye.txt
1414 +++ b/bye.txt
1414 +++ b/bye.txt
1415 @@ -1,1 +1,2 @@
1415 @@ -1,1 +1,2 @@
1416 bye
1416 bye
1417 +universe
1417 +universe
1418 $ hg qdiff --config diff.nodates=True
1418 $ hg qdiff --config diff.nodates=True
1419 diff -r 9ecee4f634e3 bye.txt
1419 diff -r 9ecee4f634e3 bye.txt
1420 --- a/bye.txt
1420 --- a/bye.txt
1421 +++ b/bye.txt
1421 +++ b/bye.txt
1422 @@ -1,1 +1,2 @@
1422 @@ -1,1 +1,2 @@
1423 bye
1423 bye
1424 +universe
1424 +universe
1425 diff -r 9ecee4f634e3 hello.txt
1425 diff -r 9ecee4f634e3 hello.txt
1426 --- a/hello.txt
1426 --- a/hello.txt
1427 +++ b/hello.txt
1427 +++ b/hello.txt
1428 @@ -1,1 +1,3 @@
1428 @@ -1,1 +1,3 @@
1429 hello
1429 hello
1430 +world
1430 +world
1431 +universe
1431 +universe
1432
1432
1433
1433
1434 test popping revisions not in working dir ancestry
1434 test popping revisions not in working dir ancestry
1435
1435
1436 $ hg qseries -v
1436 $ hg qseries -v
1437 0 A empty
1437 0 A empty
1438 $ hg up qparent
1438 $ hg up qparent
1439 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1439 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1440 $ hg qpop
1440 $ hg qpop
1441 popping empty
1441 popping empty
1442 patch queue now empty
1442 patch queue now empty
1443
1443
1444 $ cd ..
1444 $ cd ..
1445 $ hg init deletion-order
1445 $ hg init deletion-order
1446 $ cd deletion-order
1446 $ cd deletion-order
1447
1447
1448 $ touch a
1448 $ touch a
1449 $ hg ci -Aqm0
1449 $ hg ci -Aqm0
1450
1450
1451 $ hg qnew rename-dir
1451 $ hg qnew rename-dir
1452 $ hg rm a
1452 $ hg rm a
1453 $ hg qrefresh
1453 $ hg qrefresh
1454
1454
1455 $ mkdir a b
1455 $ mkdir a b
1456 $ touch a/a b/b
1456 $ touch a/a b/b
1457 $ hg add -q a b
1457 $ hg add -q a b
1458 $ hg qrefresh
1458 $ hg qrefresh
1459
1459
1460
1460
1461 test popping must remove files added in subdirectories first
1461 test popping must remove files added in subdirectories first
1462
1462
1463 $ hg qpop
1463 $ hg qpop
1464 popping rename-dir
1464 popping rename-dir
1465 patch queue now empty
1465 patch queue now empty
1466 $ cd ..
1466 $ cd ..
1467
1467
1468
1468
1469 test case preservation through patch pushing especially on case
1469 test case preservation through patch pushing especially on case
1470 insensitive filesystem
1470 insensitive filesystem
1471
1471
1472 $ hg init casepreserve
1472 $ hg init casepreserve
1473 $ cd casepreserve
1473 $ cd casepreserve
1474
1474
1475 $ hg qnew add-file1
1475 $ hg qnew add-file1
1476 $ echo a > TeXtFiLe.TxT
1476 $ echo a > TeXtFiLe.TxT
1477 $ hg add TeXtFiLe.TxT
1477 $ hg add TeXtFiLe.TxT
1478 $ hg qrefresh
1478 $ hg qrefresh
1479
1479
1480 $ hg qnew add-file2
1480 $ hg qnew add-file2
1481 $ echo b > AnOtHeRFiLe.TxT
1481 $ echo b > AnOtHeRFiLe.TxT
1482 $ hg add AnOtHeRFiLe.TxT
1482 $ hg add AnOtHeRFiLe.TxT
1483 $ hg qrefresh
1483 $ hg qrefresh
1484
1484
1485 $ hg qnew modify-file
1485 $ hg qnew modify-file
1486 $ echo c >> AnOtHeRFiLe.TxT
1486 $ echo c >> AnOtHeRFiLe.TxT
1487 $ hg qrefresh
1487 $ hg qrefresh
1488
1488
1489 $ hg qapplied
1489 $ hg qapplied
1490 add-file1
1490 add-file1
1491 add-file2
1491 add-file2
1492 modify-file
1492 modify-file
1493 $ hg qpop -a
1493 $ hg qpop -a
1494 popping modify-file
1494 popping modify-file
1495 popping add-file2
1495 popping add-file2
1496 popping add-file1
1496 popping add-file1
1497 patch queue now empty
1497 patch queue now empty
1498
1498
1499 this qpush causes problems below, if case preservation on case
1499 this qpush causes problems below, if case preservation on case
1500 insensitive filesystem is not enough:
1500 insensitive filesystem is not enough:
1501 (1) unexpected "adding ..." messages are shown
1501 (1) unexpected "adding ..." messages are shown
1502 (2) patching fails in modification of (1) files
1502 (2) patching fails in modification of (1) files
1503
1503
1504 $ hg qpush -a
1504 $ hg qpush -a
1505 applying add-file1
1505 applying add-file1
1506 applying add-file2
1506 applying add-file2
1507 applying modify-file
1507 applying modify-file
1508 now at: modify-file
1508 now at: modify-file
1509
1509
1510 Proper phase default with mq:
1510 Proper phase default with mq:
1511
1511
1512 1. mq.secret=false
1512 1. mq.secret=false
1513
1513
1514 $ rm .hg/store/phaseroots
1514 $ rm .hg/store/phaseroots
1515 $ hg phase 'qparent::'
1515 $ hg phase 'qparent::'
1516 -1: public
1516 -1: public
1517 0: draft
1517 0: draft
1518 1: draft
1518 1: draft
1519 2: draft
1519 2: draft
1520 $ echo '[mq]' >> $HGRCPATH
1520 $ echo '[mq]' >> $HGRCPATH
1521 $ echo 'secret=true' >> $HGRCPATH
1521 $ echo 'secret=true' >> $HGRCPATH
1522 $ rm -f .hg/store/phaseroots
1522 $ rm -f .hg/store/phaseroots
1523 $ hg phase 'qparent::'
1523 $ hg phase 'qparent::'
1524 -1: public
1524 -1: public
1525 0: secret
1525 0: secret
1526 1: secret
1526 1: secret
1527 2: secret
1527 2: secret
1528
1528
1529 Test that qfinish change phase when mq.secret=true
1529 Test that qfinish change phase when mq.secret=true
1530
1530
1531 $ hg qfinish qbase
1531 $ hg qfinish qbase
1532 patch add-file1 finalized without changeset message
1532 patch add-file1 finalized without changeset message
1533 $ hg phase 'all()'
1533 $ hg phase 'all()'
1534 0: draft
1534 0: draft
1535 1: secret
1535 1: secret
1536 2: secret
1536 2: secret
1537
1537
1538 Test that qfinish respect phases.new-commit setting
1538 Test that qfinish respect phases.new-commit setting
1539
1539
1540 $ echo '[phases]' >> $HGRCPATH
1540 $ echo '[phases]' >> $HGRCPATH
1541 $ echo 'new-commit=secret' >> $HGRCPATH
1541 $ echo 'new-commit=secret' >> $HGRCPATH
1542 $ hg qfinish qbase
1542 $ hg qfinish qbase
1543 patch add-file2 finalized without changeset message
1543 patch add-file2 finalized without changeset message
1544 $ hg phase 'all()'
1544 $ hg phase 'all()'
1545 0: draft
1545 0: draft
1546 1: secret
1546 1: secret
1547 2: secret
1547 2: secret
1548
1548
1549 (restore env for next test)
1549 (restore env for next test)
1550
1550
1551 $ sed -e 's/new-commit=secret//' $HGRCPATH > $TESTTMP/sedtmp
1551 $ sed -e 's/new-commit=secret//' $HGRCPATH > $TESTTMP/sedtmp
1552 $ cp $TESTTMP/sedtmp $HGRCPATH
1552 $ cp $TESTTMP/sedtmp $HGRCPATH
1553 $ hg qimport -r 1 --name add-file2
1553 $ hg qimport -r 1 --name add-file2
1554
1554
1555 Test that qfinish preserve phase when mq.secret=false
1555 Test that qfinish preserve phase when mq.secret=false
1556
1556
1557 $ sed -e 's/secret=true/secret=false/' $HGRCPATH > $TESTTMP/sedtmp
1557 $ sed -e 's/secret=true/secret=false/' $HGRCPATH > $TESTTMP/sedtmp
1558 $ cp $TESTTMP/sedtmp $HGRCPATH
1558 $ cp $TESTTMP/sedtmp $HGRCPATH
1559 $ hg qfinish qbase
1559 $ hg qfinish qbase
1560 patch add-file2 finalized without changeset message
1560 patch add-file2 finalized without changeset message
1561 $ hg phase 'all()'
1561 $ hg phase 'all()'
1562 0: draft
1562 0: draft
1563 1: secret
1563 1: secret
1564 2: secret
1564 2: secret
1565
1565
1566 Test that secret mq patch does not break hgweb
1566 Test that secret mq patch does not break hgweb
1567
1567
1568 $ cat > hgweb.cgi <<HGWEB
1568 $ cat > hgweb.cgi <<HGWEB
1569 > from mercurial import demandimport; demandimport.enable()
1569 > from mercurial import demandimport; demandimport.enable()
1570 > from mercurial.hgweb import hgweb
1570 > from mercurial.hgweb import hgweb
1571 > from mercurial.hgweb import wsgicgi
1571 > from mercurial.hgweb import wsgicgi
1572 > import cgitb
1572 > import cgitb
1573 > cgitb.enable()
1573 > cgitb.enable()
1574 > app = hgweb('.', 'test')
1574 > app = hgweb('.', 'test')
1575 > wsgicgi.launch(app)
1575 > wsgicgi.launch(app)
1576 > HGWEB
1576 > HGWEB
1577 $ . "$TESTDIR/cgienv"
1577 $ . "$TESTDIR/cgienv"
1578 #if msys
1578 #if msys
1579 $ PATH_INFO=//tags; export PATH_INFO
1579 $ PATH_INFO=//tags; export PATH_INFO
1580 #else
1580 #else
1581 $ PATH_INFO=/tags; export PATH_INFO
1581 $ PATH_INFO=/tags; export PATH_INFO
1582 #endif
1582 #endif
1583 $ QUERY_STRING='style=raw'
1583 $ QUERY_STRING='style=raw'
1584 $ python hgweb.cgi | grep '^tip'
1584 $ python hgweb.cgi | grep '^tip'
1585 tip [0-9a-f]{40} (re)
1585 tip [0-9a-f]{40} (re)
1586
1586
1587 $ cd ..
1587 $ cd ..
1588
1588
1589 Test interaction with revset (issue4426)
1589 Test interaction with revset (issue4426)
1590
1590
1591 $ hg init issue4426
1591 $ hg init issue4426
1592 $ cd issue4426
1592 $ cd issue4426
1593
1593
1594 $ echo a > a
1594 $ echo a > a
1595 $ hg ci -Am a
1595 $ hg ci -Am a
1596 adding a
1596 adding a
1597 $ echo a >> a
1597 $ echo a >> a
1598 $ hg ci -m a
1598 $ hg ci -m a
1599 $ echo a >> a
1599 $ echo a >> a
1600 $ hg ci -m a
1600 $ hg ci -m a
1601 $ hg qimport -r 0::
1601 $ hg qimport -r 0::
1602
1602
1603 reimport things
1603 reimport things
1604
1604
1605 $ hg qimport -r 1::
1605 $ hg qimport -r 1::
1606 abort: revision 2 is already managed
1606 abort: revision 2 is already managed
1607 [255]
1607 [255]
1608
1608
1609
1609
1610 $ cd ..
1610 $ cd ..
@@ -1,410 +1,410 b''
1 Create configuration
1 Create configuration
2
2
3 $ echo "[ui]" >> $HGRCPATH
3 $ echo "[ui]" >> $HGRCPATH
4 $ echo "interactive=true" >> $HGRCPATH
4 $ echo "interactive=true" >> $HGRCPATH
5
5
6 help record (no record)
6 help record (no record)
7
7
8 $ hg help record
8 $ hg help record
9 record extension - commands to interactively select changes for
9 record extension - commands to interactively select changes for
10 commit/qrefresh
10 commit/qrefresh
11
11
12 (use "hg help extensions" for information on enabling extensions)
12 (use "hg help extensions" for information on enabling extensions)
13
13
14 help qrecord (no record)
14 help qrecord (no record)
15
15
16 $ hg help qrecord
16 $ hg help qrecord
17 'qrecord' is provided by the following extension:
17 'qrecord' is provided by the following extension:
18
18
19 record commands to interactively select changes for commit/qrefresh
19 record commands to interactively select changes for commit/qrefresh
20
20
21 (use "hg help extensions" for information on enabling extensions)
21 (use "hg help extensions" for information on enabling extensions)
22
22
23 $ echo "[extensions]" >> $HGRCPATH
23 $ echo "[extensions]" >> $HGRCPATH
24 $ echo "record=" >> $HGRCPATH
24 $ echo "record=" >> $HGRCPATH
25
25
26 help record (record)
26 help record (record)
27
27
28 $ hg help record
28 $ hg help record
29 hg record [OPTION]... [FILE]...
29 hg record [OPTION]... [FILE]...
30
30
31 interactively select changes to commit
31 interactively select changes to commit
32
32
33 If a list of files is omitted, all changes reported by "hg status" will be
33 If a list of files is omitted, all changes reported by "hg status" will be
34 candidates for recording.
34 candidates for recording.
35
35
36 See "hg help dates" for a list of formats valid for -d/--date.
36 See "hg help dates" for a list of formats valid for -d/--date.
37
37
38 You will be prompted for whether to record changes to each modified file,
38 You will be prompted for whether to record changes to each modified file,
39 and for files with multiple changes, for each change to use. For each
39 and for files with multiple changes, for each change to use. For each
40 query, the following responses are possible:
40 query, the following responses are possible:
41
41
42 y - record this change
42 y - record this change
43 n - skip this change
43 n - skip this change
44 e - edit this change manually
44 e - edit this change manually
45
45
46 s - skip remaining changes to this file
46 s - skip remaining changes to this file
47 f - record remaining changes to this file
47 f - record remaining changes to this file
48
48
49 d - done, skip remaining changes and files
49 d - done, skip remaining changes and files
50 a - record all changes to all remaining files
50 a - record all changes to all remaining files
51 q - quit, recording no changes
51 q - quit, recording no changes
52
52
53 ? - display help
53 ? - display help
54
54
55 This command is not available when committing a merge.
55 This command is not available when committing a merge.
56
56
57 options ([+] can be repeated):
57 options ([+] can be repeated):
58
58
59 -A --addremove mark new/missing files as added/removed before
59 -A --addremove mark new/missing files as added/removed before
60 committing
60 committing
61 --close-branch mark a branch as closed, hiding it from the branch
61 --close-branch mark a branch as closed, hiding it from the branch
62 list
62 list
63 --amend amend the parent of the working dir
63 --amend amend the parent of the working directory
64 -s --secret use the secret phase for committing
64 -s --secret use the secret phase for committing
65 -e --edit invoke editor on commit messages
65 -e --edit invoke editor on commit messages
66 -I --include PATTERN [+] include names matching the given patterns
66 -I --include PATTERN [+] include names matching the given patterns
67 -X --exclude PATTERN [+] exclude names matching the given patterns
67 -X --exclude PATTERN [+] exclude names matching the given patterns
68 -m --message TEXT use text as commit message
68 -m --message TEXT use text as commit message
69 -l --logfile FILE read commit message from file
69 -l --logfile FILE read commit message from file
70 -d --date DATE record the specified date as commit date
70 -d --date DATE record the specified date as commit date
71 -u --user USER record the specified user as committer
71 -u --user USER record the specified user as committer
72 -S --subrepos recurse into subrepositories
72 -S --subrepos recurse into subrepositories
73 -w --ignore-all-space ignore white space when comparing lines
73 -w --ignore-all-space ignore white space when comparing lines
74 -b --ignore-space-change ignore changes in the amount of white space
74 -b --ignore-space-change ignore changes in the amount of white space
75 -B --ignore-blank-lines ignore changes whose lines are all blank
75 -B --ignore-blank-lines ignore changes whose lines are all blank
76
76
77 (some details hidden, use --verbose to show complete help)
77 (some details hidden, use --verbose to show complete help)
78
78
79 help (no mq, so no qrecord)
79 help (no mq, so no qrecord)
80
80
81 $ hg help qrecord
81 $ hg help qrecord
82 hg qrecord [OPTION]... PATCH [FILE]...
82 hg qrecord [OPTION]... PATCH [FILE]...
83
83
84 interactively record a new patch
84 interactively record a new patch
85
85
86 See "hg help qnew" & "hg help record" for more information and usage.
86 See "hg help qnew" & "hg help record" for more information and usage.
87
87
88 (some details hidden, use --verbose to show complete help)
88 (some details hidden, use --verbose to show complete help)
89
89
90 $ hg init a
90 $ hg init a
91
91
92 qrecord (mq not present)
92 qrecord (mq not present)
93
93
94 $ hg -R a qrecord
94 $ hg -R a qrecord
95 hg qrecord: invalid arguments
95 hg qrecord: invalid arguments
96 hg qrecord [OPTION]... PATCH [FILE]...
96 hg qrecord [OPTION]... PATCH [FILE]...
97
97
98 interactively record a new patch
98 interactively record a new patch
99
99
100 (use "hg qrecord -h" to show more help)
100 (use "hg qrecord -h" to show more help)
101 [255]
101 [255]
102
102
103 qrecord patch (mq not present)
103 qrecord patch (mq not present)
104
104
105 $ hg -R a qrecord patch
105 $ hg -R a qrecord patch
106 abort: 'mq' extension not loaded
106 abort: 'mq' extension not loaded
107 [255]
107 [255]
108
108
109 help (bad mq)
109 help (bad mq)
110
110
111 $ echo "mq=nonexistent" >> $HGRCPATH
111 $ echo "mq=nonexistent" >> $HGRCPATH
112 $ hg help qrecord
112 $ hg help qrecord
113 *** failed to import extension mq from nonexistent: [Errno *] * (glob)
113 *** failed to import extension mq from nonexistent: [Errno *] * (glob)
114 hg qrecord [OPTION]... PATCH [FILE]...
114 hg qrecord [OPTION]... PATCH [FILE]...
115
115
116 interactively record a new patch
116 interactively record a new patch
117
117
118 See "hg help qnew" & "hg help record" for more information and usage.
118 See "hg help qnew" & "hg help record" for more information and usage.
119
119
120 (some details hidden, use --verbose to show complete help)
120 (some details hidden, use --verbose to show complete help)
121
121
122 help (mq present)
122 help (mq present)
123
123
124 $ sed 's/mq=nonexistent/mq=/' $HGRCPATH > hgrc.tmp
124 $ sed 's/mq=nonexistent/mq=/' $HGRCPATH > hgrc.tmp
125 $ mv hgrc.tmp $HGRCPATH
125 $ mv hgrc.tmp $HGRCPATH
126
126
127 $ hg help qrecord
127 $ hg help qrecord
128 hg qrecord [OPTION]... PATCH [FILE]...
128 hg qrecord [OPTION]... PATCH [FILE]...
129
129
130 interactively record a new patch
130 interactively record a new patch
131
131
132 See "hg help qnew" & "hg help record" for more information and usage.
132 See "hg help qnew" & "hg help record" for more information and usage.
133
133
134 options ([+] can be repeated):
134 options ([+] can be repeated):
135
135
136 -e --edit invoke editor on commit messages
136 -e --edit invoke editor on commit messages
137 -g --git use git extended diff format
137 -g --git use git extended diff format
138 -U --currentuser add "From: <current user>" to patch
138 -U --currentuser add "From: <current user>" to patch
139 -u --user USER add "From: <USER>" to patch
139 -u --user USER add "From: <USER>" to patch
140 -D --currentdate add "Date: <current date>" to patch
140 -D --currentdate add "Date: <current date>" to patch
141 -d --date DATE add "Date: <DATE>" to patch
141 -d --date DATE add "Date: <DATE>" to patch
142 -I --include PATTERN [+] include names matching the given patterns
142 -I --include PATTERN [+] include names matching the given patterns
143 -X --exclude PATTERN [+] exclude names matching the given patterns
143 -X --exclude PATTERN [+] exclude names matching the given patterns
144 -m --message TEXT use text as commit message
144 -m --message TEXT use text as commit message
145 -l --logfile FILE read commit message from file
145 -l --logfile FILE read commit message from file
146 -w --ignore-all-space ignore white space when comparing lines
146 -w --ignore-all-space ignore white space when comparing lines
147 -b --ignore-space-change ignore changes in the amount of white space
147 -b --ignore-space-change ignore changes in the amount of white space
148 -B --ignore-blank-lines ignore changes whose lines are all blank
148 -B --ignore-blank-lines ignore changes whose lines are all blank
149 --mq operate on patch repository
149 --mq operate on patch repository
150
150
151 (some details hidden, use --verbose to show complete help)
151 (some details hidden, use --verbose to show complete help)
152
152
153 $ cd a
153 $ cd a
154
154
155 Base commit
155 Base commit
156
156
157 $ cat > 1.txt <<EOF
157 $ cat > 1.txt <<EOF
158 > 1
158 > 1
159 > 2
159 > 2
160 > 3
160 > 3
161 > 4
161 > 4
162 > 5
162 > 5
163 > EOF
163 > EOF
164 $ cat > 2.txt <<EOF
164 $ cat > 2.txt <<EOF
165 > a
165 > a
166 > b
166 > b
167 > c
167 > c
168 > d
168 > d
169 > e
169 > e
170 > f
170 > f
171 > EOF
171 > EOF
172
172
173 $ mkdir dir
173 $ mkdir dir
174 $ cat > dir/a.txt <<EOF
174 $ cat > dir/a.txt <<EOF
175 > hello world
175 > hello world
176 >
176 >
177 > someone
177 > someone
178 > up
178 > up
179 > there
179 > there
180 > loves
180 > loves
181 > me
181 > me
182 > EOF
182 > EOF
183
183
184 $ hg add 1.txt 2.txt dir/a.txt
184 $ hg add 1.txt 2.txt dir/a.txt
185 $ hg commit -m 'initial checkin'
185 $ hg commit -m 'initial checkin'
186
186
187 Changing files
187 Changing files
188
188
189 $ sed -e 's/2/2 2/;s/4/4 4/' 1.txt > 1.txt.new
189 $ sed -e 's/2/2 2/;s/4/4 4/' 1.txt > 1.txt.new
190 $ sed -e 's/b/b b/' 2.txt > 2.txt.new
190 $ sed -e 's/b/b b/' 2.txt > 2.txt.new
191 $ sed -e 's/hello world/hello world!/' dir/a.txt > dir/a.txt.new
191 $ sed -e 's/hello world/hello world!/' dir/a.txt > dir/a.txt.new
192
192
193 $ mv -f 1.txt.new 1.txt
193 $ mv -f 1.txt.new 1.txt
194 $ mv -f 2.txt.new 2.txt
194 $ mv -f 2.txt.new 2.txt
195 $ mv -f dir/a.txt.new dir/a.txt
195 $ mv -f dir/a.txt.new dir/a.txt
196
196
197 Whole diff
197 Whole diff
198
198
199 $ hg diff --nodates
199 $ hg diff --nodates
200 diff -r 1057167b20ef 1.txt
200 diff -r 1057167b20ef 1.txt
201 --- a/1.txt
201 --- a/1.txt
202 +++ b/1.txt
202 +++ b/1.txt
203 @@ -1,5 +1,5 @@
203 @@ -1,5 +1,5 @@
204 1
204 1
205 -2
205 -2
206 +2 2
206 +2 2
207 3
207 3
208 -4
208 -4
209 +4 4
209 +4 4
210 5
210 5
211 diff -r 1057167b20ef 2.txt
211 diff -r 1057167b20ef 2.txt
212 --- a/2.txt
212 --- a/2.txt
213 +++ b/2.txt
213 +++ b/2.txt
214 @@ -1,5 +1,5 @@
214 @@ -1,5 +1,5 @@
215 a
215 a
216 -b
216 -b
217 +b b
217 +b b
218 c
218 c
219 d
219 d
220 e
220 e
221 diff -r 1057167b20ef dir/a.txt
221 diff -r 1057167b20ef dir/a.txt
222 --- a/dir/a.txt
222 --- a/dir/a.txt
223 +++ b/dir/a.txt
223 +++ b/dir/a.txt
224 @@ -1,4 +1,4 @@
224 @@ -1,4 +1,4 @@
225 -hello world
225 -hello world
226 +hello world!
226 +hello world!
227
227
228 someone
228 someone
229 up
229 up
230
230
231 qrecord with bad patch name, should abort before prompting
231 qrecord with bad patch name, should abort before prompting
232
232
233 $ hg qrecord .hg
233 $ hg qrecord .hg
234 abort: patch name cannot begin with ".hg"
234 abort: patch name cannot begin with ".hg"
235 [255]
235 [255]
236
236
237 qrecord a.patch
237 qrecord a.patch
238
238
239 $ hg qrecord -d '0 0' -m aaa a.patch <<EOF
239 $ hg qrecord -d '0 0' -m aaa a.patch <<EOF
240 > y
240 > y
241 > y
241 > y
242 > n
242 > n
243 > y
243 > y
244 > y
244 > y
245 > n
245 > n
246 > EOF
246 > EOF
247 diff --git a/1.txt b/1.txt
247 diff --git a/1.txt b/1.txt
248 2 hunks, 2 lines changed
248 2 hunks, 2 lines changed
249 examine changes to '1.txt'? [Ynesfdaq?] y
249 examine changes to '1.txt'? [Ynesfdaq?] y
250
250
251 @@ -1,3 +1,3 @@
251 @@ -1,3 +1,3 @@
252 1
252 1
253 -2
253 -2
254 +2 2
254 +2 2
255 3
255 3
256 record change 1/4 to '1.txt'? [Ynesfdaq?] y
256 record change 1/4 to '1.txt'? [Ynesfdaq?] y
257
257
258 @@ -3,3 +3,3 @@
258 @@ -3,3 +3,3 @@
259 3
259 3
260 -4
260 -4
261 +4 4
261 +4 4
262 5
262 5
263 record change 2/4 to '1.txt'? [Ynesfdaq?] n
263 record change 2/4 to '1.txt'? [Ynesfdaq?] n
264
264
265 diff --git a/2.txt b/2.txt
265 diff --git a/2.txt b/2.txt
266 1 hunks, 1 lines changed
266 1 hunks, 1 lines changed
267 examine changes to '2.txt'? [Ynesfdaq?] y
267 examine changes to '2.txt'? [Ynesfdaq?] y
268
268
269 @@ -1,5 +1,5 @@
269 @@ -1,5 +1,5 @@
270 a
270 a
271 -b
271 -b
272 +b b
272 +b b
273 c
273 c
274 d
274 d
275 e
275 e
276 record change 3/4 to '2.txt'? [Ynesfdaq?] y
276 record change 3/4 to '2.txt'? [Ynesfdaq?] y
277
277
278 diff --git a/dir/a.txt b/dir/a.txt
278 diff --git a/dir/a.txt b/dir/a.txt
279 1 hunks, 1 lines changed
279 1 hunks, 1 lines changed
280 examine changes to 'dir/a.txt'? [Ynesfdaq?] n
280 examine changes to 'dir/a.txt'? [Ynesfdaq?] n
281
281
282
282
283 After qrecord a.patch 'tip'"
283 After qrecord a.patch 'tip'"
284
284
285 $ hg tip -p
285 $ hg tip -p
286 changeset: 1:5d1ca63427ee
286 changeset: 1:5d1ca63427ee
287 tag: a.patch
287 tag: a.patch
288 tag: qbase
288 tag: qbase
289 tag: qtip
289 tag: qtip
290 tag: tip
290 tag: tip
291 user: test
291 user: test
292 date: Thu Jan 01 00:00:00 1970 +0000
292 date: Thu Jan 01 00:00:00 1970 +0000
293 summary: aaa
293 summary: aaa
294
294
295 diff -r 1057167b20ef -r 5d1ca63427ee 1.txt
295 diff -r 1057167b20ef -r 5d1ca63427ee 1.txt
296 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
296 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
297 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
297 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
298 @@ -1,5 +1,5 @@
298 @@ -1,5 +1,5 @@
299 1
299 1
300 -2
300 -2
301 +2 2
301 +2 2
302 3
302 3
303 4
303 4
304 5
304 5
305 diff -r 1057167b20ef -r 5d1ca63427ee 2.txt
305 diff -r 1057167b20ef -r 5d1ca63427ee 2.txt
306 --- a/2.txt Thu Jan 01 00:00:00 1970 +0000
306 --- a/2.txt Thu Jan 01 00:00:00 1970 +0000
307 +++ b/2.txt Thu Jan 01 00:00:00 1970 +0000
307 +++ b/2.txt Thu Jan 01 00:00:00 1970 +0000
308 @@ -1,5 +1,5 @@
308 @@ -1,5 +1,5 @@
309 a
309 a
310 -b
310 -b
311 +b b
311 +b b
312 c
312 c
313 d
313 d
314 e
314 e
315
315
316
316
317 After qrecord a.patch 'diff'"
317 After qrecord a.patch 'diff'"
318
318
319 $ hg diff --nodates
319 $ hg diff --nodates
320 diff -r 5d1ca63427ee 1.txt
320 diff -r 5d1ca63427ee 1.txt
321 --- a/1.txt
321 --- a/1.txt
322 +++ b/1.txt
322 +++ b/1.txt
323 @@ -1,5 +1,5 @@
323 @@ -1,5 +1,5 @@
324 1
324 1
325 2 2
325 2 2
326 3
326 3
327 -4
327 -4
328 +4 4
328 +4 4
329 5
329 5
330 diff -r 5d1ca63427ee dir/a.txt
330 diff -r 5d1ca63427ee dir/a.txt
331 --- a/dir/a.txt
331 --- a/dir/a.txt
332 +++ b/dir/a.txt
332 +++ b/dir/a.txt
333 @@ -1,4 +1,4 @@
333 @@ -1,4 +1,4 @@
334 -hello world
334 -hello world
335 +hello world!
335 +hello world!
336
336
337 someone
337 someone
338 up
338 up
339
339
340 qrecord b.patch
340 qrecord b.patch
341
341
342 $ hg qrecord -d '0 0' -m bbb b.patch <<EOF
342 $ hg qrecord -d '0 0' -m bbb b.patch <<EOF
343 > y
343 > y
344 > y
344 > y
345 > y
345 > y
346 > y
346 > y
347 > EOF
347 > EOF
348 diff --git a/1.txt b/1.txt
348 diff --git a/1.txt b/1.txt
349 1 hunks, 1 lines changed
349 1 hunks, 1 lines changed
350 examine changes to '1.txt'? [Ynesfdaq?] y
350 examine changes to '1.txt'? [Ynesfdaq?] y
351
351
352 @@ -1,5 +1,5 @@
352 @@ -1,5 +1,5 @@
353 1
353 1
354 2 2
354 2 2
355 3
355 3
356 -4
356 -4
357 +4 4
357 +4 4
358 5
358 5
359 record change 1/2 to '1.txt'? [Ynesfdaq?] y
359 record change 1/2 to '1.txt'? [Ynesfdaq?] y
360
360
361 diff --git a/dir/a.txt b/dir/a.txt
361 diff --git a/dir/a.txt b/dir/a.txt
362 1 hunks, 1 lines changed
362 1 hunks, 1 lines changed
363 examine changes to 'dir/a.txt'? [Ynesfdaq?] y
363 examine changes to 'dir/a.txt'? [Ynesfdaq?] y
364
364
365 @@ -1,4 +1,4 @@
365 @@ -1,4 +1,4 @@
366 -hello world
366 -hello world
367 +hello world!
367 +hello world!
368
368
369 someone
369 someone
370 up
370 up
371 record change 2/2 to 'dir/a.txt'? [Ynesfdaq?] y
371 record change 2/2 to 'dir/a.txt'? [Ynesfdaq?] y
372
372
373
373
374 After qrecord b.patch 'tip'
374 After qrecord b.patch 'tip'
375
375
376 $ hg tip -p
376 $ hg tip -p
377 changeset: 2:b056198bf878
377 changeset: 2:b056198bf878
378 tag: b.patch
378 tag: b.patch
379 tag: qtip
379 tag: qtip
380 tag: tip
380 tag: tip
381 user: test
381 user: test
382 date: Thu Jan 01 00:00:00 1970 +0000
382 date: Thu Jan 01 00:00:00 1970 +0000
383 summary: bbb
383 summary: bbb
384
384
385 diff -r 5d1ca63427ee -r b056198bf878 1.txt
385 diff -r 5d1ca63427ee -r b056198bf878 1.txt
386 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
386 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
387 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
387 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
388 @@ -1,5 +1,5 @@
388 @@ -1,5 +1,5 @@
389 1
389 1
390 2 2
390 2 2
391 3
391 3
392 -4
392 -4
393 +4 4
393 +4 4
394 5
394 5
395 diff -r 5d1ca63427ee -r b056198bf878 dir/a.txt
395 diff -r 5d1ca63427ee -r b056198bf878 dir/a.txt
396 --- a/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
396 --- a/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
397 +++ b/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
397 +++ b/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
398 @@ -1,4 +1,4 @@
398 @@ -1,4 +1,4 @@
399 -hello world
399 -hello world
400 +hello world!
400 +hello world!
401
401
402 someone
402 someone
403 up
403 up
404
404
405
405
406 After qrecord b.patch 'diff'
406 After qrecord b.patch 'diff'
407
407
408 $ hg diff --nodates
408 $ hg diff --nodates
409
409
410 $ cd ..
410 $ cd ..
@@ -1,88 +1,88 b''
1 Set up a repo
1 Set up a repo
2
2
3 $ cat <<EOF >> $HGRCPATH
3 $ cat <<EOF >> $HGRCPATH
4 > [ui]
4 > [ui]
5 > interactive = true
5 > interactive = true
6 > [extensions]
6 > [extensions]
7 > record =
7 > record =
8 > EOF
8 > EOF
9
9
10 $ hg init a
10 $ hg init a
11 $ cd a
11 $ cd a
12
12
13 Record help
13 Record help
14
14
15 $ hg record -h
15 $ hg record -h
16 hg record [OPTION]... [FILE]...
16 hg record [OPTION]... [FILE]...
17
17
18 interactively select changes to commit
18 interactively select changes to commit
19
19
20 If a list of files is omitted, all changes reported by "hg status" will be
20 If a list of files is omitted, all changes reported by "hg status" will be
21 candidates for recording.
21 candidates for recording.
22
22
23 See "hg help dates" for a list of formats valid for -d/--date.
23 See "hg help dates" for a list of formats valid for -d/--date.
24
24
25 You will be prompted for whether to record changes to each modified file,
25 You will be prompted for whether to record changes to each modified file,
26 and for files with multiple changes, for each change to use. For each
26 and for files with multiple changes, for each change to use. For each
27 query, the following responses are possible:
27 query, the following responses are possible:
28
28
29 y - record this change
29 y - record this change
30 n - skip this change
30 n - skip this change
31 e - edit this change manually
31 e - edit this change manually
32
32
33 s - skip remaining changes to this file
33 s - skip remaining changes to this file
34 f - record remaining changes to this file
34 f - record remaining changes to this file
35
35
36 d - done, skip remaining changes and files
36 d - done, skip remaining changes and files
37 a - record all changes to all remaining files
37 a - record all changes to all remaining files
38 q - quit, recording no changes
38 q - quit, recording no changes
39
39
40 ? - display help
40 ? - display help
41
41
42 This command is not available when committing a merge.
42 This command is not available when committing a merge.
43
43
44 options ([+] can be repeated):
44 options ([+] can be repeated):
45
45
46 -A --addremove mark new/missing files as added/removed before
46 -A --addremove mark new/missing files as added/removed before
47 committing
47 committing
48 --close-branch mark a branch as closed, hiding it from the branch
48 --close-branch mark a branch as closed, hiding it from the branch
49 list
49 list
50 --amend amend the parent of the working dir
50 --amend amend the parent of the working directory
51 -s --secret use the secret phase for committing
51 -s --secret use the secret phase for committing
52 -e --edit invoke editor on commit messages
52 -e --edit invoke editor on commit messages
53 -I --include PATTERN [+] include names matching the given patterns
53 -I --include PATTERN [+] include names matching the given patterns
54 -X --exclude PATTERN [+] exclude names matching the given patterns
54 -X --exclude PATTERN [+] exclude names matching the given patterns
55 -m --message TEXT use text as commit message
55 -m --message TEXT use text as commit message
56 -l --logfile FILE read commit message from file
56 -l --logfile FILE read commit message from file
57 -d --date DATE record the specified date as commit date
57 -d --date DATE record the specified date as commit date
58 -u --user USER record the specified user as committer
58 -u --user USER record the specified user as committer
59 -S --subrepos recurse into subrepositories
59 -S --subrepos recurse into subrepositories
60 -w --ignore-all-space ignore white space when comparing lines
60 -w --ignore-all-space ignore white space when comparing lines
61 -b --ignore-space-change ignore changes in the amount of white space
61 -b --ignore-space-change ignore changes in the amount of white space
62 -B --ignore-blank-lines ignore changes whose lines are all blank
62 -B --ignore-blank-lines ignore changes whose lines are all blank
63
63
64 (some details hidden, use --verbose to show complete help)
64 (some details hidden, use --verbose to show complete help)
65
65
66 Select no files
66 Select no files
67
67
68 $ touch empty-rw
68 $ touch empty-rw
69 $ hg add empty-rw
69 $ hg add empty-rw
70
70
71 $ hg record empty-rw<<EOF
71 $ hg record empty-rw<<EOF
72 > n
72 > n
73 > EOF
73 > EOF
74 diff --git a/empty-rw b/empty-rw
74 diff --git a/empty-rw b/empty-rw
75 new file mode 100644
75 new file mode 100644
76 examine changes to 'empty-rw'? [Ynesfdaq?] n
76 examine changes to 'empty-rw'? [Ynesfdaq?] n
77
77
78 no changes to record
78 no changes to record
79
79
80 $ hg tip -p
80 $ hg tip -p
81 changeset: -1:000000000000
81 changeset: -1:000000000000
82 tag: tip
82 tag: tip
83 user:
83 user:
84 date: Thu Jan 01 00:00:00 1970 +0000
84 date: Thu Jan 01 00:00:00 1970 +0000
85
85
86
86
87
87
88
88
General Comments 0
You need to be logged in to leave comments. Login now