##// END OF EJS Templates
Merge with crew, fix most tests
Matt Mackall -
r2830:49988d9f merge default
parent child Browse files
Show More
@@ -0,0 +1,25 b''
1 #!/bin/sh
2
3 HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
4 echo "[extensions]" >> $HGTMP/.hgrc
5 echo "fetch=" >> $HGTMP/.hgrc
6
7 hg init a
8 echo a > a/a
9 hg --cwd a commit -d '1 0' -Ama
10
11 hg clone a b
12 hg clone a c
13
14 echo b > a/b
15 hg --cwd a commit -d '2 0' -Amb
16 hg --cwd a parents -q
17
18 echo % should pull one change
19 hg --cwd b fetch ../a
20 hg --cwd b parents -q
21
22 echo c > c/c
23 hg --cwd c commit -d '3 0' -Amc
24 hg --cwd c fetch -d '4 0' -m 'automated merge' ../a
25 ls c
@@ -0,0 +1,27 b''
1 adding a
2 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
3 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4 adding b
5 1:97d72e5f12c7
6 % should pull one change
7 pulling from ../a
8 searching for changes
9 adding changesets
10 adding manifests
11 adding file changes
12 added 1 changesets with 1 changes to 1 files
13 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
14 1:97d72e5f12c7
15 adding c
16 pulling from ../a
17 searching for changes
18 adding changesets
19 adding manifests
20 adding file changes
21 added 1 changesets with 1 changes to 1 files (+1 heads)
22 merging with new head 2:97d72e5f12c7
23 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
24 new changeset 3:cd3a41621cf0 merges remote changes with local
25 a
26 b
27 c
@@ -0,0 +1,84 b''
1 #!/bin/sh
2
3 HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
4 echo "[extensions]" >> $HGTMP/.hgrc
5 echo "mq=" >> $HGTMP/.hgrc
6
7 hg init
8 hg qinit
9
10 echo x > x
11 hg ci -Ama
12
13 hg qnew a.patch
14 echo a > a
15 hg add a
16 hg qrefresh
17
18 hg qnew b.patch
19 echo b > b
20 hg add b
21 hg qrefresh
22
23 hg qnew c.patch
24 echo c > c
25 hg add c
26 hg qrefresh
27
28 hg qpop -a
29
30 echo % should fail
31 hg qguard +fail
32
33 hg qpush
34 echo % should guard a.patch
35 hg qguard +a
36 echo % should print +a
37 hg qguard
38 hg qpop
39
40 hg qguard a.patch
41 echo % should push b.patch
42 hg qpush
43
44 hg qpop
45 hg qselect a
46 echo % should push a.patch
47 hg qpush
48
49 hg qguard c.patch -a
50 echo % should print -a
51 hg qguard c.patch
52
53 echo % should skip c.patch
54 hg qpush -a
55
56 hg qguard -n c.patch
57 echo % should push c.patch
58 hg qpush -a
59
60 hg qpop -a
61 hg qselect -n
62 echo % should push all
63 hg qpush -a
64
65 hg qpop -a
66 hg qguard a.patch +1 +2
67 hg qselect 1
68 echo % should push b.patch
69 hg qpush
70 hg qpop -a
71
72 hg qselect 2
73 hg qpush
74 hg qpop -a
75
76 hg qselect 1 2
77 echo % should push a.patch
78 hg qpush
79 hg qpop -a
80
81 hg qguard a.patch +1 +2 -3
82 hg qselect 1 2 3
83 echo % should push b.patch
84 hg qpush
@@ -0,0 +1,54 b''
1 adding x
2 Patch queue now empty
3 % should fail
4 abort: no patches applied
5 applying a.patch
6 Now at: a.patch
7 % should guard a.patch
8 % should print +a
9 a.patch: +a
10 Patch queue now empty
11 a.patch: +a
12 % should push b.patch
13 applying b.patch
14 Now at: b.patch
15 Patch queue now empty
16 3 of 3 unapplied patches active
17 % should push a.patch
18 applying a.patch
19 Now at: a.patch
20 % should print -a
21 c.patch: -a
22 % should skip c.patch
23 applying b.patch
24 skipping c.patch - guarded by '- a'
25 Now at: b.patch
26 % should push c.patch
27 applying c.patch
28 Now at: c.patch
29 Patch queue now empty
30 guards deactivated
31 2 of 3 unapplied patches active
32 % should push all
33 applying b.patch
34 applying c.patch
35 Now at: c.patch
36 Patch queue now empty
37 2 of 3 unapplied patches active
38 % should push b.patch
39 applying b.patch
40 Now at: b.patch
41 Patch queue now empty
42 2 of 3 unapplied patches active
43 applying b.patch
44 Now at: b.patch
45 Patch queue now empty
46 3 of 3 unapplied patches active
47 % should push a.patch
48 applying a.patch
49 Now at: a.patch
50 Patch queue now empty
51 2 of 3 unapplied patches active
52 % should push b.patch
53 applying b.patch
54 Now at: b.patch
@@ -0,0 +1,16 b''
1 #!/bin/sh
2
3 HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
4 echo "[extensions]" >> $HGTMP/.hgrc
5 echo "mq=" >> $HGTMP/.hgrc
6
7 hg init a
8 cd a
9
10 echo 'base' > base
11 hg ci -Ambase -d '1 0'
12
13 hg qnew -mmqbase mqbase
14
15 hg qsave
16 hg qrestore 2
@@ -0,0 +1,2 b''
1 adding base
2 restoring status: hg patches saved state
@@ -24,29 +24,29 b" def fetch(ui, repo, source='default', **"
24 if modheads == 0:
24 if modheads == 0:
25 return 0
25 return 0
26 if modheads == 1:
26 if modheads == 1:
27 return hg.update(repo, repo.changelog.tip())
27 return hg.update(repo, repo.changelog.tip(), wlock=wlock)
28 newheads = repo.heads(parent)
28 newheads = repo.heads(parent)
29 newchildren = [n for n in repo.heads(parent) if n != parent]
29 newchildren = [n for n in repo.heads(parent) if n != parent]
30 newparent = parent
30 newparent = parent
31 if newchildren:
31 if newchildren:
32 hg.update(repo, newchildren[0])
33 newparent = newchildren[0]
32 newparent = newchildren[0]
33 hg.update(repo, newparent, wlock=wlock)
34 newheads = [n for n in repo.heads() if n != newparent]
34 newheads = [n for n in repo.heads() if n != newparent]
35 err = False
35 err = False
36 if newheads:
36 if newheads:
37 ui.status(_('merging with new head %d:%s\n') %
37 ui.status(_('merging with new head %d:%s\n') %
38 (repo.changelog.rev(newheads[0]), short(newheads[0])))
38 (repo.changelog.rev(newheads[0]), short(newheads[0])))
39 err = hg.merge(repo, newheads[0], remind=False)
39 err = hg.merge(repo, newheads[0], remind=False, wlock=wlock)
40 if not err and len(newheads) > 1:
40 if not err and len(newheads) > 1:
41 ui.status(_('not merging with %d other new heads '
41 ui.status(_('not merging with %d other new heads '
42 '(use "hg heads" and "hg merge" to merge them)') %
42 '(use "hg heads" and "hg merge" to merge them)') %
43 (len(newheads) - 1))
43 (len(newheads) - 1))
44 if not err:
44 if not err:
45 mod, add, rem = repo.status()[:3]
45 mod, add, rem = repo.status(wlock=wlock)[:3]
46 message = (commands.logmessage(opts) or
46 message = (commands.logmessage(opts) or
47 (_('Automated merge with %s') % other.url()))
47 (_('Automated merge with %s') % other.url()))
48 n = repo.commit(mod + add + rem, message,
48 n = repo.commit(mod + add + rem, message,
49 opts['user'], opts['date'],
49 opts['user'], opts['date'], lock=lock, wlock=wlock,
50 force_editor=opts.get('force_editor'))
50 force_editor=opts.get('force_editor'))
51 ui.status(_('new changeset %d:%s merges remote changes '
51 ui.status(_('new changeset %d:%s merges remote changes '
52 'with local\n') % (repo.changelog.rev(n),
52 'with local\n') % (repo.changelog.rev(n),
@@ -55,13 +55,13 b" def fetch(ui, repo, source='default', **"
55 commands.setremoteconfig(ui, opts)
55 commands.setremoteconfig(ui, opts)
56
56
57 other = hg.repository(ui, ui.expandpath(source))
57 other = hg.repository(ui, ui.expandpath(source))
58 ui.status(_('pulling from %s\n') % source)
58 ui.status(_('pulling from %s\n') % ui.expandpath(source))
59 revs = None
59 revs = None
60 if opts['rev'] and not other.local():
60 if opts['rev'] and not other.local():
61 raise util.Abort(_("fetch -r doesn't work for remote repositories yet"))
61 raise util.Abort(_("fetch -r doesn't work for remote repositories yet"))
62 elif opts['rev']:
62 elif opts['rev']:
63 revs = [other.lookup(rev) for rev in opts['rev']]
63 revs = [other.lookup(rev) for rev in opts['rev']]
64 modheads = repo.pull(other, heads=revs)
64 modheads = repo.pull(other, heads=revs, lock=lock)
65 return postincoming(other, modheads)
65 return postincoming(other, modheads)
66
66
67 parent, p2 = repo.dirstate.parents()
67 parent, p2 = repo.dirstate.parents()
@@ -70,13 +70,19 b" def fetch(ui, repo, source='default', **"
70 '(use "hg update" to check out tip)'))
70 '(use "hg update" to check out tip)'))
71 if p2 != nullid:
71 if p2 != nullid:
72 raise util.Abort(_('outstanding uncommitted merge'))
72 raise util.Abort(_('outstanding uncommitted merge'))
73 mod, add, rem = repo.status()[:3]
73 wlock = repo.wlock()
74 if mod or add or rem:
74 lock = repo.lock()
75 raise util.Abort(_('outstanding uncommitted changes'))
75 try:
76 if len(repo.heads()) > 1:
76 mod, add, rem = repo.status(wlock=wlock)[:3]
77 raise util.Abort(_('multiple heads in this repository '
77 if mod or add or rem:
78 '(use "hg heads" and "hg merge" to merge them)'))
78 raise util.Abort(_('outstanding uncommitted changes'))
79 return pull()
79 if len(repo.heads()) > 1:
80 raise util.Abort(_('multiple heads in this repository '
81 '(use "hg heads" and "hg merge" to merge)'))
82 return pull()
83 finally:
84 lock.release()
85 wlock.release()
80
86
81 cmdtable = {
87 cmdtable = {
82 'fetch':
88 'fetch':
@@ -35,14 +35,16 b' demandload(globals(), "os sys re struct '
35 from mercurial.i18n import gettext as _
35 from mercurial.i18n import gettext as _
36 from mercurial import ui, hg, revlog, commands, util
36 from mercurial import ui, hg, revlog, commands, util
37
37
38 versionstr = "0.45"
39
40 commands.norepo += " qclone qversion"
38 commands.norepo += " qclone qversion"
41
39
42 class StatusEntry:
40 class statusentry:
43 def __init__(self, rev, name=None):
41 def __init__(self, rev, name=None):
44 if not name:
42 if not name:
45 self.rev, self.name = rev.split(':')
43 fields = rev.split(':')
44 if len(fields) == 2:
45 self.rev, self.name = fields
46 else:
47 self.rev, self.name = None, None
46 else:
48 else:
47 self.rev, self.name = rev, name
49 self.rev, self.name = rev, name
48
50
@@ -52,10 +54,7 b' class StatusEntry:'
52 class queue:
54 class queue:
53 def __init__(self, ui, path, patchdir=None):
55 def __init__(self, ui, path, patchdir=None):
54 self.basepath = path
56 self.basepath = path
55 if patchdir:
57 self.path = patchdir or os.path.join(path, "patches")
56 self.path = patchdir
57 else:
58 self.path = os.path.join(path, "patches")
59 self.opener = util.opener(self.path)
58 self.opener = util.opener(self.path)
60 self.ui = ui
59 self.ui = ui
61 self.applied = []
60 self.applied = []
@@ -64,14 +63,20 b' class queue:'
64 self.series_dirty = 0
63 self.series_dirty = 0
65 self.series_path = "series"
64 self.series_path = "series"
66 self.status_path = "status"
65 self.status_path = "status"
66 self.guards_path = "guards"
67 self.active_guards = None
68 self.guards_dirty = False
67
69
68 if os.path.exists(os.path.join(self.path, self.series_path)):
70 if os.path.exists(self.join(self.series_path)):
69 self.full_series = self.opener(self.series_path).read().splitlines()
71 self.full_series = self.opener(self.series_path).read().splitlines()
70 self.parse_series()
72 self.parse_series()
71
73
72 if os.path.exists(os.path.join(self.path, self.status_path)):
74 if os.path.exists(self.join(self.status_path)):
73 self.applied = [StatusEntry(l)
75 lines = self.opener(self.status_path).read().splitlines()
74 for l in self.opener(self.status_path).read().splitlines()]
76 self.applied = [statusentry(l) for l in lines]
77
78 def join(self, *p):
79 return os.path.join(self.path, *p)
75
80
76 def find_series(self, patch):
81 def find_series(self, patch):
77 pre = re.compile("(\s*)([^#]+)")
82 pre = re.compile("(\s*)([^#]+)")
@@ -86,12 +91,122 b' class queue:'
86 index += 1
91 index += 1
87 return None
92 return None
88
93
94 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
95
89 def parse_series(self):
96 def parse_series(self):
90 self.series = []
97 self.series = []
98 self.series_guards = []
91 for l in self.full_series:
99 for l in self.full_series:
92 s = l.split('#', 1)[0].strip()
100 h = l.find('#')
93 if s:
101 if h == -1:
94 self.series.append(s)
102 patch = l
103 comment = ''
104 elif h == 0:
105 continue
106 else:
107 patch = l[:h]
108 comment = l[h:]
109 patch = patch.strip()
110 if patch:
111 self.series.append(patch)
112 self.series_guards.append(self.guard_re.findall(comment))
113
114 def check_guard(self, guard):
115 bad_chars = '# \t\r\n\f'
116 first = guard[0]
117 for c in '-+':
118 if first == c:
119 return (_('guard %r starts with invalid character: %r') %
120 (guard, c))
121 for c in bad_chars:
122 if c in guard:
123 return _('invalid character in guard %r: %r') % (guard, c)
124
125 def set_active(self, guards):
126 for guard in guards:
127 bad = self.check_guard(guard)
128 if bad:
129 raise util.Abort(bad)
130 guards = dict.fromkeys(guards).keys()
131 guards.sort()
132 self.ui.debug('active guards: %s\n' % ' '.join(guards))
133 self.active_guards = guards
134 self.guards_dirty = True
135
136 def active(self):
137 if self.active_guards is None:
138 self.active_guards = []
139 try:
140 guards = self.opener(self.guards_path).read().split()
141 except IOError, err:
142 if err.errno != errno.ENOENT: raise
143 guards = []
144 for i, guard in enumerate(guards):
145 bad = self.check_guard(guard)
146 if bad:
147 self.ui.warn('%s:%d: %s\n' %
148 (self.join(self.guards_path), i + 1, bad))
149 else:
150 self.active_guards.append(guard)
151 return self.active_guards
152
153 def set_guards(self, idx, guards):
154 for g in guards:
155 if len(g) < 2:
156 raise util.Abort(_('guard %r too short') % g)
157 if g[0] not in '-+':
158 raise util.Abort(_('guard %r starts with invalid char') % g)
159 bad = self.check_guard(g[1:])
160 if bad:
161 raise util.Abort(bad)
162 drop = self.guard_re.sub('', self.full_series[idx])
163 self.full_series[idx] = drop + ''.join([' #' + g for g in guards])
164 self.parse_series()
165 self.series_dirty = True
166
167 def pushable(self, idx):
168 if isinstance(idx, str):
169 idx = self.series.index(idx)
170 patchguards = self.series_guards[idx]
171 if not patchguards:
172 return True, None
173 default = False
174 guards = self.active()
175 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
176 if exactneg:
177 return False, exactneg[0]
178 pos = [g for g in patchguards if g[0] == '+']
179 nonpos = [g for g in pos if g[1:] not in guards]
180 if pos:
181 if not nonpos:
182 return True, ''
183 return False, nonpos
184 return True, ''
185
186 def explain_pushable(self, idx, all_patches=False):
187 write = all_patches and self.ui.write or self.ui.warn
188 if all_patches or self.ui.verbose:
189 if isinstance(idx, str):
190 idx = self.series.index(idx)
191 pushable, why = self.pushable(idx)
192 if all_patches and pushable:
193 if why is None:
194 write(_('allowing %s - no guards in effect\n') %
195 self.series[idx])
196 else:
197 if not why:
198 write(_('allowing %s - no matching negative guards\n') %
199 self.series[idx])
200 else:
201 write(_('allowing %s - guarded by %r\n') %
202 (self.series[idx], why))
203 if not pushable:
204 if why:
205 write(_('skipping %s - guarded by %r\n') %
206 (self.series[idx], ' '.join(why)))
207 else:
208 write(_('skipping %s - no matching guards\n') %
209 self.series[idx])
95
210
96 def save_dirty(self):
211 def save_dirty(self):
97 def write_list(items, path):
212 def write_list(items, path):
@@ -101,6 +216,7 b' class queue:'
101 fp.close()
216 fp.close()
102 if self.applied_dirty: write_list(map(str, self.applied), self.status_path)
217 if self.applied_dirty: write_list(map(str, self.applied), self.status_path)
103 if self.series_dirty: write_list(self.full_series, self.series_path)
218 if self.series_dirty: write_list(self.full_series, self.series_path)
219 if self.guards_dirty: write_list(self.active_guards, self.guards_path)
104
220
105 def readheaders(self, patch):
221 def readheaders(self, patch):
106 def eatdiff(lines):
222 def eatdiff(lines):
@@ -120,7 +236,7 b' class queue:'
120 else:
236 else:
121 break
237 break
122
238
123 pf = os.path.join(self.path, patch)
239 pf = self.join(patch)
124 message = []
240 message = []
125 comments = []
241 comments = []
126 user = None
242 user = None
@@ -243,7 +359,7 b' class queue:'
243 pname = ".hg.patches.merge.marker"
359 pname = ".hg.patches.merge.marker"
244 n = repo.commit(None, '[mq]: merge marker', user=None, force=1,
360 n = repo.commit(None, '[mq]: merge marker', user=None, force=1,
245 wlock=wlock)
361 wlock=wlock)
246 self.applied.append(StatusEntry(revlog.hex(n), pname))
362 self.applied.append(statusentry(revlog.hex(n), pname))
247 self.applied_dirty = 1
363 self.applied_dirty = 1
248
364
249 head = self.qparents(repo)
365 head = self.qparents(repo)
@@ -253,7 +369,10 b' class queue:'
253 if not patch:
369 if not patch:
254 self.ui.warn("patch %s does not exist\n" % patch)
370 self.ui.warn("patch %s does not exist\n" % patch)
255 return (1, None)
371 return (1, None)
256
372 pushable, reason = self.pushable(patch)
373 if not pushable:
374 self.explain_pushable(patch, all_patches=True)
375 continue
257 info = mergeq.isapplied(patch)
376 info = mergeq.isapplied(patch)
258 if not info:
377 if not info:
259 self.ui.warn("patch %s is not applied\n" % patch)
378 self.ui.warn("patch %s is not applied\n" % patch)
@@ -261,7 +380,7 b' class queue:'
261 rev = revlog.bin(info[1])
380 rev = revlog.bin(info[1])
262 (err, head) = self.mergeone(repo, mergeq, head, patch, rev, wlock)
381 (err, head) = self.mergeone(repo, mergeq, head, patch, rev, wlock)
263 if head:
382 if head:
264 self.applied.append(StatusEntry(revlog.hex(head), patch))
383 self.applied.append(statusentry(revlog.hex(head), patch))
265 self.applied_dirty = 1
384 self.applied_dirty = 1
266 if err:
385 if err:
267 return (err, head)
386 return (err, head)
@@ -317,6 +436,10 b' class queue:'
317 tr = repo.transaction()
436 tr = repo.transaction()
318 n = None
437 n = None
319 for patch in series:
438 for patch in series:
439 pushable, reason = self.pushable(patch)
440 if not pushable:
441 self.explain_pushable(patch, all_patches=True)
442 continue
320 self.ui.warn("applying %s\n" % patch)
443 self.ui.warn("applying %s\n" % patch)
321 pf = os.path.join(patchdir, patch)
444 pf = os.path.join(patchdir, patch)
322
445
@@ -356,7 +479,7 b' class queue:'
356 raise util.Abort(_("repo commit failed"))
479 raise util.Abort(_("repo commit failed"))
357
480
358 if update_status:
481 if update_status:
359 self.applied.append(StatusEntry(revlog.hex(n), patch))
482 self.applied.append(statusentry(revlog.hex(n), patch))
360
483
361 if patcherr:
484 if patcherr:
362 if not patchfound:
485 if not patchfound:
@@ -386,7 +509,7 b' class queue:'
386 if r:
509 if r:
387 r.remove([patch], True)
510 r.remove([patch], True)
388 else:
511 else:
389 os.unlink(os.path.join(self.path, patch))
512 os.unlink(self.join(patch))
390 i = self.find_series(patch)
513 i = self.find_series(patch)
391 del self.full_series[i]
514 del self.full_series[i]
392 self.parse_series()
515 self.parse_series()
@@ -405,7 +528,7 b' class queue:'
405 if c or a or d or r:
528 if c or a or d or r:
406 raise util.Abort(_("local changes found, refresh first"))
529 raise util.Abort(_("local changes found, refresh first"))
407 def new(self, repo, patch, msg=None, force=None):
530 def new(self, repo, patch, msg=None, force=None):
408 if os.path.exists(os.path.join(self.path, patch)):
531 if os.path.exists(self.join(patch)):
409 raise util.Abort(_('patch "%s" already exists') % patch)
532 raise util.Abort(_('patch "%s" already exists') % patch)
410 commitfiles = []
533 commitfiles = []
411 (c, a, r, d, u) = repo.changes(None, None)
534 (c, a, r, d, u) = repo.changes(None, None)
@@ -425,7 +548,7 b' class queue:'
425 if n == None:
548 if n == None:
426 raise util.Abort(_("repo commit failed"))
549 raise util.Abort(_("repo commit failed"))
427 self.full_series[insert:insert] = [patch]
550 self.full_series[insert:insert] = [patch]
428 self.applied.append(StatusEntry(revlog.hex(n), patch))
551 self.applied.append(statusentry(revlog.hex(n), patch))
429 self.parse_series()
552 self.parse_series()
430 self.series_dirty = 1
553 self.series_dirty = 1
431 self.applied_dirty = 1
554 self.applied_dirty = 1
@@ -628,15 +751,14 b' class queue:'
628 if res and res == patch:
751 if res and res == patch:
629 return res
752 return res
630
753
631 if not os.path.isfile(os.path.join(self.path, patch)):
754 if not os.path.isfile(self.join(patch)):
632 try:
755 try:
633 sno = int(patch)
756 sno = int(patch)
634 except(ValueError, OverflowError):
757 except(ValueError, OverflowError):
635 pass
758 pass
636 else:
759 else:
637 if sno < len(self.series):
760 if sno < len(self.series):
638 patch = self.series[sno]
761 return self.series[sno]
639 return patch
640 if not strict:
762 if not strict:
641 # return any partial match made above
763 # return any partial match made above
642 if res:
764 if res:
@@ -900,7 +1022,7 b' class queue:'
900
1022
901 self.strip(repo, top, update=False, backup='strip', wlock=wlock)
1023 self.strip(repo, top, update=False, backup='strip', wlock=wlock)
902 n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock)
1024 n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock)
903 self.applied[-1] = StatusEntry(revlog.hex(n), patch)
1025 self.applied[-1] = statusentry(revlog.hex(n), patch)
904 self.applied_dirty = 1
1026 self.applied_dirty = 1
905 else:
1027 else:
906 commands.dodiff(patchf, self.ui, repo, patchparent, None)
1028 commands.dodiff(patchf, self.ui, repo, patchparent, None)
@@ -922,18 +1044,26 b' class queue:'
922 start = self.series_end()
1044 start = self.series_end()
923 else:
1045 else:
924 start = self.series.index(patch) + 1
1046 start = self.series.index(patch) + 1
925 return [(i, self.series[i]) for i in xrange(start, len(self.series))]
1047 unapplied = []
1048 for i in xrange(start, len(self.series)):
1049 pushable, reason = self.pushable(i)
1050 if pushable:
1051 unapplied.append((i, self.series[i]))
1052 self.explain_pushable(i)
1053 return unapplied
926
1054
927 def qseries(self, repo, missing=None, summary=False):
1055 def qseries(self, repo, missing=None, summary=False):
928 start = self.series_end()
1056 start = self.series_end(all_patches=True)
929 if not missing:
1057 if not missing:
930 for i in range(len(self.series)):
1058 for i in range(len(self.series)):
931 patch = self.series[i]
1059 patch = self.series[i]
932 if self.ui.verbose:
1060 if self.ui.verbose:
933 if i < start:
1061 if i < start:
934 status = 'A'
1062 status = 'A'
1063 elif self.pushable(i)[0]:
1064 status = 'U'
935 else:
1065 else:
936 status = 'U'
1066 status = 'G'
937 self.ui.write('%d %s ' % (i, status))
1067 self.ui.write('%d %s ' % (i, status))
938 if summary:
1068 if summary:
939 msg = self.readheaders(patch)[0]
1069 msg = self.readheaders(patch)[0]
@@ -958,12 +1088,11 b' class queue:'
958 self.ui.write("%s\n" % x)
1088 self.ui.write("%s\n" % x)
959
1089
960 def issaveline(self, l):
1090 def issaveline(self, l):
961 name = l.split(':')[1]
1091 if l.name == '.hg.patches.save.line':
962 if name == '.hg.patches.save.line':
963 return True
1092 return True
964
1093
965 def qrepo(self, create=False):
1094 def qrepo(self, create=False):
966 if create or os.path.isdir(os.path.join(self.path, ".hg")):
1095 if create or os.path.isdir(self.join(".hg")):
967 return hg.repository(self.ui, path=self.path, create=create)
1096 return hg.repository(self.ui, path=self.path, create=create)
968
1097
969 def restore(self, repo, rev, delete=None, qupdate=None):
1098 def restore(self, repo, rev, delete=None, qupdate=None):
@@ -984,7 +1113,7 b' class queue:'
984 qpp = [ hg.bin(x) for x in l ]
1113 qpp = [ hg.bin(x) for x in l ]
985 elif datastart != None:
1114 elif datastart != None:
986 l = lines[i].rstrip()
1115 l = lines[i].rstrip()
987 se = StatusEntry(l)
1116 se = statusentry(l)
988 file_ = se.name
1117 file_ = se.name
989 if se.rev:
1118 if se.rev:
990 applied.append(se)
1119 applied.append(se)
@@ -1039,13 +1168,13 b' class queue:'
1039 pp = r.dirstate.parents()
1168 pp = r.dirstate.parents()
1040 msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1]))
1169 msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1]))
1041 msg += "\n\nPatch Data:\n"
1170 msg += "\n\nPatch Data:\n"
1042 text = msg + "\n".join(str(self.applied)) + '\n' + (ar and "\n".join(ar)
1171 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
1043 + '\n' or "")
1172 "\n".join(ar) + '\n' or "")
1044 n = repo.commit(None, text, user=None, force=1)
1173 n = repo.commit(None, text, user=None, force=1)
1045 if not n:
1174 if not n:
1046 self.ui.warn("repo commit failed\n")
1175 self.ui.warn("repo commit failed\n")
1047 return 1
1176 return 1
1048 self.applied.append(StatusEntry(revlog.hex(n),'.hg.patches.save.line'))
1177 self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line'))
1049 self.applied_dirty = 1
1178 self.applied_dirty = 1
1050
1179
1051 def full_series_end(self):
1180 def full_series_end(self):
@@ -1057,16 +1186,27 b' class queue:'
1057 return end + 1
1186 return end + 1
1058 return 0
1187 return 0
1059
1188
1060 def series_end(self):
1189 def series_end(self, all_patches=False):
1061 end = 0
1190 end = 0
1191 def next(start):
1192 if all_patches:
1193 return start
1194 i = start
1195 while i < len(self.series):
1196 p, reason = self.pushable(i)
1197 if p:
1198 break
1199 self.explain_pushable(i)
1200 i += 1
1201 return i
1062 if len(self.applied) > 0:
1202 if len(self.applied) > 0:
1063 p = self.applied[-1].name
1203 p = self.applied[-1].name
1064 try:
1204 try:
1065 end = self.series.index(p)
1205 end = self.series.index(p)
1066 except ValueError:
1206 except ValueError:
1067 return 0
1207 return 0
1068 return end + 1
1208 return next(end + 1)
1069 return end
1209 return next(end)
1070
1210
1071 def qapplied(self, repo, patch=None):
1211 def qapplied(self, repo, patch=None):
1072 if patch and patch not in self.series:
1212 if patch and patch not in self.series:
@@ -1123,7 +1263,7 b' class queue:'
1123 if existing:
1263 if existing:
1124 if not patch:
1264 if not patch:
1125 patch = filename
1265 patch = filename
1126 if not os.path.isfile(os.path.join(self.path, patch)):
1266 if not os.path.isfile(self.join(patch)):
1127 raise util.Abort(_("patch %s does not exist") % patch)
1267 raise util.Abort(_("patch %s does not exist") % patch)
1128 else:
1268 else:
1129 try:
1269 try:
@@ -1132,7 +1272,7 b' class queue:'
1132 raise util.Abort(_("unable to read %s") % patch)
1272 raise util.Abort(_("unable to read %s") % patch)
1133 if not patch:
1273 if not patch:
1134 patch = os.path.split(filename)[1]
1274 patch = os.path.split(filename)[1]
1135 if not force and os.path.exists(os.path.join(self.path, patch)):
1275 if not force and os.path.exists(self.join(patch)):
1136 raise util.Abort(_('patch "%s" already exists') % patch)
1276 raise util.Abort(_('patch "%s" already exists') % patch)
1137 patchf = self.opener(patch, "w")
1277 patchf = self.opener(patch, "w")
1138 patchf.write(text)
1278 patchf.write(text)
@@ -1347,7 +1487,7 b' def fold(ui, repo, *files, **opts):'
1347 for patch in patches:
1487 for patch in patches:
1348 if not message:
1488 if not message:
1349 messages.append(q.readheaders(patch)[0])
1489 messages.append(q.readheaders(patch)[0])
1350 pf = os.path.join(q.path, patch)
1490 pf = q.join(patch)
1351 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1491 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1352 if not patchsuccess:
1492 if not patchsuccess:
1353 raise util.Abort(_('Error folding patch %s') % patch)
1493 raise util.Abort(_('Error folding patch %s') % patch)
@@ -1369,6 +1509,51 b' def fold(ui, repo, *files, **opts):'
1369
1509
1370 q.save_dirty()
1510 q.save_dirty()
1371
1511
1512 def guard(ui, repo, *args, **opts):
1513 '''set or print guards for a patch
1514
1515 guards control whether a patch can be pushed. a patch with no
1516 guards is aways pushed. a patch with posative guard ("+foo") is
1517 pushed only if qselect command enables guard "foo". a patch with
1518 nagative guard ("-foo") is never pushed if qselect command enables
1519 guard "foo".
1520
1521 with no arguments, default is to print current active guards.
1522 with arguments, set active guards for patch.
1523
1524 to set nagative guard "-foo" on topmost patch ("--" is needed so
1525 hg will not interpret "-foo" as argument):
1526 hg qguard -- -foo
1527
1528 to set guards on other patch:
1529 hg qguard other.patch +2.6.17 -stable
1530 '''
1531 def status(idx):
1532 guards = q.series_guards[idx] or ['unguarded']
1533 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
1534 q = repo.mq
1535 patch = None
1536 args = list(args)
1537 if opts['list']:
1538 if args or opts['none']:
1539 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
1540 for i in xrange(len(q.series)):
1541 status(i)
1542 return
1543 if not args or args[0][0:1] in '-+':
1544 if not q.applied:
1545 raise util.Abort(_('no patches applied'))
1546 patch = q.applied[-1].name
1547 if patch is None and args[0][0:1] not in '-+':
1548 patch = args.pop(0)
1549 if patch is None:
1550 raise util.Abort(_('no patch to work with'))
1551 if args or opts['none']:
1552 q.set_guards(q.find_series(patch), args)
1553 q.save_dirty()
1554 else:
1555 status(q.series.index(q.lookup(patch)))
1556
1372 def header(ui, repo, patch=None):
1557 def header(ui, repo, patch=None):
1373 """Print the header of the topmost or specified patch"""
1558 """Print the header of the topmost or specified patch"""
1374 q = repo.mq
1559 q = repo.mq
@@ -1458,7 +1643,7 b' def rename(ui, repo, patch, name=None, *'
1458 if name in q.series:
1643 if name in q.series:
1459 raise util.Abort(_('A patch named %s already exists in the series file') % name)
1644 raise util.Abort(_('A patch named %s already exists in the series file') % name)
1460
1645
1461 absdest = os.path.join(q.path, name)
1646 absdest = q.join(name)
1462 if os.path.exists(absdest):
1647 if os.path.exists(absdest):
1463 raise util.Abort(_('%s already exists') % absdest)
1648 raise util.Abort(_('%s already exists') % absdest)
1464
1649
@@ -1479,10 +1664,10 b' def rename(ui, repo, patch, name=None, *'
1479
1664
1480 info = q.isapplied(patch)
1665 info = q.isapplied(patch)
1481 if info:
1666 if info:
1482 q.applied[info[0]] = StatusEntry(info[1], name)
1667 q.applied[info[0]] = statusentry(info[1], name)
1483 q.applied_dirty = 1
1668 q.applied_dirty = 1
1484
1669
1485 util.rename(os.path.join(q.path, patch), absdest)
1670 util.rename(q.join(patch), absdest)
1486 r = q.qrepo()
1671 r = q.qrepo()
1487 if r:
1672 if r:
1488 wlock = r.wlock()
1673 wlock = r.wlock()
@@ -1527,7 +1712,7 b' def save(ui, repo, **opts):'
1527 util.copyfiles(path, newpath)
1712 util.copyfiles(path, newpath)
1528 if opts['empty']:
1713 if opts['empty']:
1529 try:
1714 try:
1530 os.unlink(os.path.join(q.path, q.status_path))
1715 os.unlink(q.join(q.status_path))
1531 except:
1716 except:
1532 pass
1717 pass
1533 return 0
1718 return 0
@@ -1543,18 +1728,76 b' def strip(ui, repo, rev, **opts):'
1543 repo.mq.strip(repo, rev, backup=backup)
1728 repo.mq.strip(repo, rev, backup=backup)
1544 return 0
1729 return 0
1545
1730
1546 def version(ui, q=None):
1731 def select(ui, repo, *args, **opts):
1547 """print the version number of the mq extension"""
1732 '''set or print guarded patches to push
1548 ui.write("mq version %s\n" % versionstr)
1733
1549 return 0
1734 use qguard command to set or print guards on patch. then use
1735 qselect to tell mq which guards to use. example:
1736
1737 qguard foo.patch -stable (nagative guard)
1738 qguard bar.patch +stable (posative guard)
1739 qselect stable
1740
1741 this sets "stable" guard. mq will skip foo.patch (because it has
1742 nagative match) but push bar.patch (because it has posative
1743 match). patch is pushed only if all posative guards match and no
1744 nagative guards match.
1745
1746 with no arguments, default is to print current active guards.
1747 with arguments, set active guards as given.
1748
1749 use -n/--none to deactivate guards (no other arguments needed).
1750 when no guards active, patches with posative guards are skipped,
1751 patches with nagative guards are pushed.
1752
1753 use -s/--series to print list of all guards in series file (no
1754 other arguments needed). use -v for more information.'''
1755
1756 q = repo.mq
1757 guards = q.active()
1758 if args or opts['none']:
1759 q.set_active(args)
1760 q.save_dirty()
1761 if not args:
1762 ui.status(_('guards deactivated\n'))
1763 if q.series:
1764 ui.status(_('%d of %d unapplied patches active\n') %
1765 (len(q.unapplied(repo)), len(q.series)))
1766 elif opts['series']:
1767 guards = {}
1768 noguards = 0
1769 for gs in q.series_guards:
1770 if not gs:
1771 noguards += 1
1772 for g in gs:
1773 guards.setdefault(g, 0)
1774 guards[g] += 1
1775 if ui.verbose:
1776 guards['NONE'] = noguards
1777 guards = guards.items()
1778 guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:]))
1779 if guards:
1780 ui.note(_('guards in series file:\n'))
1781 for guard, count in guards:
1782 ui.note('%2d ' % count)
1783 ui.write(guard, '\n')
1784 else:
1785 ui.note(_('no guards in series file\n'))
1786 else:
1787 if guards:
1788 ui.note(_('active guards:\n'))
1789 for g in guards:
1790 ui.write(g, '\n')
1791 else:
1792 ui.write(_('no active guards\n'))
1550
1793
1551 def reposetup(ui, repo):
1794 def reposetup(ui, repo):
1552 class MqRepo(repo.__class__):
1795 class mqrepo(repo.__class__):
1553 def tags(self):
1796 def tags(self):
1554 if self.tagscache:
1797 if self.tagscache:
1555 return self.tagscache
1798 return self.tagscache
1556
1799
1557 tagscache = super(MqRepo, self).tags()
1800 tagscache = super(mqrepo, self).tags()
1558
1801
1559 q = self.mq
1802 q = self.mq
1560 if not q.applied:
1803 if not q.applied:
@@ -1571,7 +1814,7 b' def reposetup(ui, repo):'
1571
1814
1572 return tagscache
1815 return tagscache
1573
1816
1574 repo.__class__ = MqRepo
1817 repo.__class__ = mqrepo
1575 repo.mq = queue(ui, repo.join(""))
1818 repo.mq = queue(ui, repo.join(""))
1576
1819
1577 cmdtable = {
1820 cmdtable = {
@@ -1602,6 +1845,9 b' cmdtable = {'
1602 ('m', 'message', '', _('set patch header to <text>')),
1845 ('m', 'message', '', _('set patch header to <text>')),
1603 ('l', 'logfile', '', _('set patch header to contents of <file>'))],
1846 ('l', 'logfile', '', _('set patch header to contents of <file>'))],
1604 'hg qfold [-e] [-m <text>] [-l <file] PATCH...'),
1847 'hg qfold [-e] [-m <text>] [-l <file] PATCH...'),
1848 'qguard': (guard, [('l', 'list', None, _('list all patches and guards')),
1849 ('n', 'none', None, _('drop all guards'))],
1850 'hg qguard [PATCH] [+GUARD...] [-GUARD...]'),
1605 'qheader': (header, [],
1851 'qheader': (header, [],
1606 _('hg qheader [PATCH]')),
1852 _('hg qheader [PATCH]')),
1607 "^qimport":
1853 "^qimport":
@@ -1659,6 +1905,10 b' cmdtable = {'
1659 ('e', 'empty', None, 'clear queue status file'),
1905 ('e', 'empty', None, 'clear queue status file'),
1660 ('f', 'force', None, 'force copy')],
1906 ('f', 'force', None, 'force copy')],
1661 'hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'),
1907 'hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'),
1908 "qselect": (select,
1909 [('n', 'none', None, _('disable all guards')),
1910 ('s', 'series', None, _('list all guards in series file'))],
1911 'hg qselect [GUARDS]'),
1662 "qseries":
1912 "qseries":
1663 (series,
1913 (series,
1664 [('m', 'missing', None, 'print patches not in series'),
1914 [('m', 'missing', None, 'print patches not in series'),
@@ -1672,6 +1922,5 b' cmdtable = {'
1672 'hg strip [-f] [-b] [-n] REV'),
1922 'hg strip [-f] [-b] [-n] REV'),
1673 "qtop": (top, [], 'hg qtop'),
1923 "qtop": (top, [], 'hg qtop'),
1674 "qunapplied": (unapplied, [], 'hg qunapplied [PATCH]'),
1924 "qunapplied": (unapplied, [], 'hg qunapplied [PATCH]'),
1675 "qversion": (version, [], 'hg qversion')
1676 }
1925 }
1677
1926
@@ -1177,22 +1177,29 b' class localrepository(repo.repository):'
1177 else:
1177 else:
1178 return subset
1178 return subset
1179
1179
1180 def pull(self, remote, heads=None, force=False):
1180 def pull(self, remote, heads=None, force=False, lock=None):
1181 l = self.lock()
1181 mylock = False
1182 if not lock:
1183 lock = self.lock()
1184 mylock = True
1182
1185
1183 fetch = self.findincoming(remote, force=force)
1186 try:
1184 if fetch == [nullid]:
1187 fetch = self.findincoming(remote, force=force)
1185 self.ui.status(_("requesting all changes\n"))
1188 if fetch == [nullid]:
1189 self.ui.status(_("requesting all changes\n"))
1186
1190
1187 if not fetch:
1191 if not fetch:
1188 self.ui.status(_("no changes found\n"))
1192 self.ui.status(_("no changes found\n"))
1189 return 0
1193 return 0
1190
1194
1191 if heads is None:
1195 if heads is None:
1192 cg = remote.changegroup(fetch, 'pull')
1196 cg = remote.changegroup(fetch, 'pull')
1193 else:
1197 else:
1194 cg = remote.changegroupsubset(fetch, heads, 'pull')
1198 cg = remote.changegroupsubset(fetch, heads, 'pull')
1195 return self.addchangegroup(cg, 'pull', remote.url())
1199 return self.addchangegroup(cg, 'pull', remote.url())
1200 finally:
1201 if mylock:
1202 lock.release()
1196
1203
1197 def push(self, remote, force=False, revs=None):
1204 def push(self, remote, force=False, revs=None):
1198 # there are two ways to push to remote repo:
1205 # there are two ways to push to remote repo:
@@ -1,6 +1,3 b''
1 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
2 removing b
2 removing b
3 this update spans a branch affecting the following files:
3 abort: update spans branches, use 'hg merge' or 'hg update -C' to lose changes
4 b
5 aborting update spanning branches!
6 (use 'hg merge' to merge across branches or 'hg update -C' to lose changes)
@@ -22,7 +22,7 b' added 1 changesets with 1 changes to 1 f'
22 (run 'hg heads' to see heads, 'hg merge' to merge)
22 (run 'hg heads' to see heads, 'hg merge' to merge)
23 merge: warning: conflicts during merge
23 merge: warning: conflicts during merge
24 resolving manifests
24 resolving manifests
25 force False allow True moddirstate True linear False
25 overwrite None branchmerge True partial False linear False
26 ancestor 055d847dd401 local 2eded9ab0a5c remote 84cf5750dd20
26 ancestor 055d847dd401 local 2eded9ab0a5c remote 84cf5750dd20
27 test.txt versions differ, resolve
27 test.txt versions differ, resolve
28 merging test.txt
28 merging test.txt
@@ -30,6 +30,7 b' list of commands (use "hg help -v mq" to'
30 qdelete remove a patch from the series file
30 qdelete remove a patch from the series file
31 qdiff diff of the current patch
31 qdiff diff of the current patch
32 qfold fold the named patches into the current patch
32 qfold fold the named patches into the current patch
33 qguard set or print guards for a patch
33 qheader Print the header of the topmost or specified patch
34 qheader Print the header of the topmost or specified patch
34 qimport import a patch
35 qimport import a patch
35 qinit init a new queue repository
36 qinit init a new queue repository
@@ -42,10 +43,10 b' list of commands (use "hg help -v mq" to'
42 qrename rename a patch
43 qrename rename a patch
43 qrestore restore the queue state saved by a rev
44 qrestore restore the queue state saved by a rev
44 qsave save current queue state
45 qsave save current queue state
46 qselect set or print guarded patches to push
45 qseries print the entire series file
47 qseries print the entire series file
46 qtop print the name of the current patch
48 qtop print the name of the current patch
47 qunapplied print the patches not yet applied
49 qunapplied print the patches not yet applied
48 qversion print the version number of the mq extension
49 strip strip a revision and all later revs on the same branch
50 strip strip a revision and all later revs on the same branch
50 adding a
51 adding a
51 adding b/z
52 adding b/z
@@ -17,7 +17,7 b' date: Mon Jan 12 13:46:40 1970 +0'
17 summary: 1
17 summary: 1
18
18
19 resolving manifests
19 resolving manifests
20 force False allow False moddirstate True linear True
20 overwrite False branchmerge False partial False linear True
21 ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e
21 ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e
22 a versions differ, resolve
22 a versions differ, resolve
23 remote created b
23 remote created b
@@ -33,7 +33,7 b' date: Mon Jan 12 13:46:40 1970 +0'
33 summary: 2
33 summary: 2
34
34
35 resolving manifests
35 resolving manifests
36 force False allow False moddirstate True linear True
36 overwrite False branchmerge False partial False linear True
37 ancestor a0c8bcbbb45c local 1165e8bd193e remote a0c8bcbbb45c
37 ancestor a0c8bcbbb45c local 1165e8bd193e remote a0c8bcbbb45c
38 remote deleted b
38 remote deleted b
39 removing b
39 removing b
@@ -51,7 +51,7 b' date: Mon Jan 12 13:46:40 1970 +0'
51 summary: 1
51 summary: 1
52
52
53 resolving manifests
53 resolving manifests
54 force False allow False moddirstate True linear True
54 overwrite False branchmerge False partial False linear True
55 ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e
55 ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e
56 a versions differ, resolve
56 a versions differ, resolve
57 remote created b
57 remote created b
@@ -98,21 +98,12 b' user: test'
98 date: Mon Jan 12 13:46:40 1970 +0000
98 date: Mon Jan 12 13:46:40 1970 +0000
99 summary: 2
99 summary: 2
100
100
101 resolving manifests
101 abort: update spans branches, use 'hg merge' or 'hg update -C' to lose changes
102 force False allow False moddirstate True linear False
103 ancestor a0c8bcbbb45c local 1165e8bd193e remote 4096f2872392
104 a versions differ, resolve
105 b versions differ, resolve
106 this update spans a branch affecting the following files:
107 a (resolve)
108 b (resolve)
109 aborting update spanning branches!
110 (use 'hg merge' to merge across branches or 'hg update -C' to lose changes)
111 failed
102 failed
112 abort: outstanding uncommitted changes
103 abort: outstanding uncommitted changes
113 failed
104 failed
114 resolving manifests
105 resolving manifests
115 force False allow True moddirstate True linear False
106 overwrite False branchmerge True partial False linear False
116 ancestor a0c8bcbbb45c local 1165e8bd193e remote 4096f2872392
107 ancestor a0c8bcbbb45c local 1165e8bd193e remote 4096f2872392
117 a versions differ, resolve
108 a versions differ, resolve
118 b versions differ, resolve
109 b versions differ, resolve
@@ -40,7 +40,7 b' a'
40 side1
40 side1
41 side2
41 side2
42 resolving manifests
42 resolving manifests
43 force True allow False moddirstate True linear False
43 overwrite True branchmerge False partial False linear False
44 ancestor 8515d4bfda76 local 1c0f48f8ece6 remote 0594b9004bae
44 ancestor 8515d4bfda76 local 1c0f48f8ece6 remote 0594b9004bae
45 remote deleted side2, clobbering
45 remote deleted side2, clobbering
46 remote deleted side1, clobbering
46 remote deleted side1, clobbering
General Comments 0
You need to be logged in to leave comments. Login now