##// END OF EJS Templates
merge with stable
Matt Mackall -
r23200:48a2eefd merge default
parent child Browse files
Show More
@@ -1,442 +1,442 b''
1 # Mercurial bookmark support code
1 # Mercurial bookmark support code
2 #
2 #
3 # Copyright 2008 David Soria Parra <dsp@php.net>
3 # Copyright 2008 David Soria Parra <dsp@php.net>
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 mercurial.i18n import _
8 from mercurial.i18n import _
9 from mercurial.node import hex, bin
9 from mercurial.node import hex, bin
10 from mercurial import encoding, error, util, obsolete, lock as lockmod
10 from mercurial import encoding, error, util, obsolete, lock as lockmod
11 import errno
11 import errno
12
12
13 class bmstore(dict):
13 class bmstore(dict):
14 """Storage for bookmarks.
14 """Storage for bookmarks.
15
15
16 This object should do all bookmark reads and writes, so that it's
16 This object should do all bookmark reads and writes, so that it's
17 fairly simple to replace the storage underlying bookmarks without
17 fairly simple to replace the storage underlying bookmarks without
18 having to clone the logic surrounding bookmarks.
18 having to clone the logic surrounding bookmarks.
19
19
20 This particular bmstore implementation stores bookmarks as
20 This particular bmstore implementation stores bookmarks as
21 {hash}\s{name}\n (the same format as localtags) in
21 {hash}\s{name}\n (the same format as localtags) in
22 .hg/bookmarks. The mapping is stored as {name: nodeid}.
22 .hg/bookmarks. The mapping is stored as {name: nodeid}.
23
23
24 This class does NOT handle the "current" bookmark state at this
24 This class does NOT handle the "current" bookmark state at this
25 time.
25 time.
26 """
26 """
27
27
28 def __init__(self, repo):
28 def __init__(self, repo):
29 dict.__init__(self)
29 dict.__init__(self)
30 self._repo = repo
30 self._repo = repo
31 try:
31 try:
32 for line in repo.vfs('bookmarks'):
32 for line in repo.vfs('bookmarks'):
33 line = line.strip()
33 line = line.strip()
34 if not line:
34 if not line:
35 continue
35 continue
36 if ' ' not in line:
36 if ' ' not in line:
37 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n')
37 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n')
38 % line)
38 % line)
39 continue
39 continue
40 sha, refspec = line.split(' ', 1)
40 sha, refspec = line.split(' ', 1)
41 refspec = encoding.tolocal(refspec)
41 refspec = encoding.tolocal(refspec)
42 try:
42 try:
43 self[refspec] = repo.changelog.lookup(sha)
43 self[refspec] = repo.changelog.lookup(sha)
44 except LookupError:
44 except LookupError:
45 pass
45 pass
46 except IOError, inst:
46 except IOError, inst:
47 if inst.errno != errno.ENOENT:
47 if inst.errno != errno.ENOENT:
48 raise
48 raise
49
49
50 def recordchange(self, tr):
50 def recordchange(self, tr):
51 """record that bookmarks have been changed in a transaction
51 """record that bookmarks have been changed in a transaction
52
52
53 The transaction is then responsible for updating the file content."""
53 The transaction is then responsible for updating the file content."""
54 tr.addfilegenerator('bookmarks', ('bookmarks',), self._write,
54 tr.addfilegenerator('bookmarks', ('bookmarks',), self._write,
55 vfs=self._repo.vfs)
55 vfs=self._repo.vfs)
56 tr.hookargs['bookmark_moved'] = '1'
56 tr.hookargs['bookmark_moved'] = '1'
57
57
58 def write(self):
58 def write(self):
59 '''Write bookmarks
59 '''Write bookmarks
60
60
61 Write the given bookmark => hash dictionary to the .hg/bookmarks file
61 Write the given bookmark => hash dictionary to the .hg/bookmarks file
62 in a format equal to those of localtags.
62 in a format equal to those of localtags.
63
63
64 We also store a backup of the previous state in undo.bookmarks that
64 We also store a backup of the previous state in undo.bookmarks that
65 can be copied back on rollback.
65 can be copied back on rollback.
66 '''
66 '''
67 repo = self._repo
67 repo = self._repo
68 if repo._bookmarkcurrent not in self:
68 if repo._bookmarkcurrent not in self:
69 unsetcurrent(repo)
69 unsetcurrent(repo)
70
70
71 wlock = repo.wlock()
71 wlock = repo.wlock()
72 try:
72 try:
73
73
74 file = repo.vfs('bookmarks', 'w', atomictemp=True)
74 file = repo.vfs('bookmarks', 'w', atomictemp=True)
75 self._write(file)
75 self._write(file)
76 file.close()
76 file.close()
77
77
78 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
78 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
79 try:
79 try:
80 repo.svfs.utime('00changelog.i', None)
80 repo.svfs.utime('00changelog.i', None)
81 except OSError:
81 except OSError:
82 pass
82 pass
83
83
84 finally:
84 finally:
85 wlock.release()
85 wlock.release()
86
86
87 def _write(self, fp):
87 def _write(self, fp):
88 for name, node in self.iteritems():
88 for name, node in self.iteritems():
89 fp.write("%s %s\n" % (hex(node), encoding.fromlocal(name)))
89 fp.write("%s %s\n" % (hex(node), encoding.fromlocal(name)))
90
90
91 def readcurrent(repo):
91 def readcurrent(repo):
92 '''Get the current bookmark
92 '''Get the current bookmark
93
93
94 If we use gittish branches we have a current bookmark that
94 If we use gittish branches we have a current bookmark that
95 we are on. This function returns the name of the bookmark. It
95 we are on. This function returns the name of the bookmark. It
96 is stored in .hg/bookmarks.current
96 is stored in .hg/bookmarks.current
97 '''
97 '''
98 mark = None
98 mark = None
99 try:
99 try:
100 file = repo.opener('bookmarks.current')
100 file = repo.opener('bookmarks.current')
101 except IOError, inst:
101 except IOError, inst:
102 if inst.errno != errno.ENOENT:
102 if inst.errno != errno.ENOENT:
103 raise
103 raise
104 return None
104 return None
105 try:
105 try:
106 # No readline() in osutil.posixfile, reading everything is cheap
106 # No readline() in osutil.posixfile, reading everything is cheap
107 mark = encoding.tolocal((file.readlines() or [''])[0])
107 mark = encoding.tolocal((file.readlines() or [''])[0])
108 if mark == '' or mark not in repo._bookmarks:
108 if mark == '' or mark not in repo._bookmarks:
109 mark = None
109 mark = None
110 finally:
110 finally:
111 file.close()
111 file.close()
112 return mark
112 return mark
113
113
114 def setcurrent(repo, mark):
114 def setcurrent(repo, mark):
115 '''Set the name of the bookmark that we are currently on
115 '''Set the name of the bookmark that we are currently on
116
116
117 Set the name of the bookmark that we are on (hg update <bookmark>).
117 Set the name of the bookmark that we are on (hg update <bookmark>).
118 The name is recorded in .hg/bookmarks.current
118 The name is recorded in .hg/bookmarks.current
119 '''
119 '''
120 if mark not in repo._bookmarks:
120 if mark not in repo._bookmarks:
121 raise AssertionError('bookmark %s does not exist!' % mark)
121 raise AssertionError('bookmark %s does not exist!' % mark)
122
122
123 current = repo._bookmarkcurrent
123 current = repo._bookmarkcurrent
124 if current == mark:
124 if current == mark:
125 return
125 return
126
126
127 wlock = repo.wlock()
127 wlock = repo.wlock()
128 try:
128 try:
129 file = repo.opener('bookmarks.current', 'w', atomictemp=True)
129 file = repo.opener('bookmarks.current', 'w', atomictemp=True)
130 file.write(encoding.fromlocal(mark))
130 file.write(encoding.fromlocal(mark))
131 file.close()
131 file.close()
132 finally:
132 finally:
133 wlock.release()
133 wlock.release()
134 repo._bookmarkcurrent = mark
134 repo._bookmarkcurrent = mark
135
135
136 def unsetcurrent(repo):
136 def unsetcurrent(repo):
137 wlock = repo.wlock()
137 wlock = repo.wlock()
138 try:
138 try:
139 try:
139 try:
140 repo.vfs.unlink('bookmarks.current')
140 repo.vfs.unlink('bookmarks.current')
141 repo._bookmarkcurrent = None
141 repo._bookmarkcurrent = None
142 except OSError, inst:
142 except OSError, inst:
143 if inst.errno != errno.ENOENT:
143 if inst.errno != errno.ENOENT:
144 raise
144 raise
145 finally:
145 finally:
146 wlock.release()
146 wlock.release()
147
147
148 def iscurrent(repo, mark=None, parents=None):
148 def iscurrent(repo, mark=None, parents=None):
149 '''Tell whether the current bookmark is also active
149 '''Tell whether the current bookmark is also active
150
150
151 I.e., the bookmark listed in .hg/bookmarks.current also points to a
151 I.e., the bookmark listed in .hg/bookmarks.current also points to a
152 parent of the working directory.
152 parent of the working directory.
153 '''
153 '''
154 if not mark:
154 if not mark:
155 mark = repo._bookmarkcurrent
155 mark = repo._bookmarkcurrent
156 if not parents:
156 if not parents:
157 parents = [p.node() for p in repo[None].parents()]
157 parents = [p.node() for p in repo[None].parents()]
158 marks = repo._bookmarks
158 marks = repo._bookmarks
159 return (mark in marks and marks[mark] in parents)
159 return (mark in marks and marks[mark] in parents)
160
160
161 def updatecurrentbookmark(repo, oldnode, curbranch):
161 def updatecurrentbookmark(repo, oldnode, curbranch):
162 try:
162 try:
163 return update(repo, oldnode, repo.branchtip(curbranch))
163 return update(repo, oldnode, repo.branchtip(curbranch))
164 except error.RepoLookupError:
164 except error.RepoLookupError:
165 if curbranch == "default": # no default branch!
165 if curbranch == "default": # no default branch!
166 return update(repo, oldnode, repo.lookup("tip"))
166 return update(repo, oldnode, repo.lookup("tip"))
167 else:
167 else:
168 raise util.Abort(_("branch %s not found") % curbranch)
168 raise util.Abort(_("branch %s not found") % curbranch)
169
169
170 def deletedivergent(repo, deletefrom, bm):
170 def deletedivergent(repo, deletefrom, bm):
171 '''Delete divergent versions of bm on nodes in deletefrom.
171 '''Delete divergent versions of bm on nodes in deletefrom.
172
172
173 Return True if at least one bookmark was deleted, False otherwise.'''
173 Return True if at least one bookmark was deleted, False otherwise.'''
174 deleted = False
174 deleted = False
175 marks = repo._bookmarks
175 marks = repo._bookmarks
176 divergent = [b for b in marks if b.split('@', 1)[0] == bm.split('@', 1)[0]]
176 divergent = [b for b in marks if b.split('@', 1)[0] == bm.split('@', 1)[0]]
177 for mark in divergent:
177 for mark in divergent:
178 if mark == '@' or '@' not in mark:
178 if mark == '@' or '@' not in mark:
179 # can't be divergent by definition
179 # can't be divergent by definition
180 continue
180 continue
181 if mark and marks[mark] in deletefrom:
181 if mark and marks[mark] in deletefrom:
182 if mark != bm:
182 if mark != bm:
183 del marks[mark]
183 del marks[mark]
184 deleted = True
184 deleted = True
185 return deleted
185 return deleted
186
186
187 def calculateupdate(ui, repo, checkout):
187 def calculateupdate(ui, repo, checkout):
188 '''Return a tuple (targetrev, movemarkfrom) indicating the rev to
188 '''Return a tuple (targetrev, movemarkfrom) indicating the rev to
189 check out and where to move the active bookmark from, if needed.'''
189 check out and where to move the active bookmark from, if needed.'''
190 movemarkfrom = None
190 movemarkfrom = None
191 if checkout is None:
191 if checkout is None:
192 curmark = repo._bookmarkcurrent
192 curmark = repo._bookmarkcurrent
193 if iscurrent(repo):
193 if iscurrent(repo):
194 movemarkfrom = repo['.'].node()
194 movemarkfrom = repo['.'].node()
195 elif curmark:
195 elif curmark:
196 ui.status(_("updating to active bookmark %s\n") % curmark)
196 ui.status(_("updating to active bookmark %s\n") % curmark)
197 checkout = curmark
197 checkout = curmark
198 return (checkout, movemarkfrom)
198 return (checkout, movemarkfrom)
199
199
200 def update(repo, parents, node):
200 def update(repo, parents, node):
201 deletefrom = parents
201 deletefrom = parents
202 marks = repo._bookmarks
202 marks = repo._bookmarks
203 update = False
203 update = False
204 cur = repo._bookmarkcurrent
204 cur = repo._bookmarkcurrent
205 if not cur:
205 if not cur:
206 return False
206 return False
207
207
208 if marks[cur] in parents:
208 if marks[cur] in parents:
209 new = repo[node]
209 new = repo[node]
210 divs = [repo[b] for b in marks
210 divs = [repo[b] for b in marks
211 if b.split('@', 1)[0] == cur.split('@', 1)[0]]
211 if b.split('@', 1)[0] == cur.split('@', 1)[0]]
212 anc = repo.changelog.ancestors([new.rev()])
212 anc = repo.changelog.ancestors([new.rev()])
213 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
213 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
214 if validdest(repo, repo[marks[cur]], new):
214 if validdest(repo, repo[marks[cur]], new):
215 marks[cur] = new.node()
215 marks[cur] = new.node()
216 update = True
216 update = True
217
217
218 if deletedivergent(repo, deletefrom, cur):
218 if deletedivergent(repo, deletefrom, cur):
219 update = True
219 update = True
220
220
221 if update:
221 if update:
222 marks.write()
222 marks.write()
223 return update
223 return update
224
224
225 def listbookmarks(repo):
225 def listbookmarks(repo):
226 # We may try to list bookmarks on a repo type that does not
226 # We may try to list bookmarks on a repo type that does not
227 # support it (e.g., statichttprepository).
227 # support it (e.g., statichttprepository).
228 marks = getattr(repo, '_bookmarks', {})
228 marks = getattr(repo, '_bookmarks', {})
229
229
230 d = {}
230 d = {}
231 hasnode = repo.changelog.hasnode
231 hasnode = repo.changelog.hasnode
232 for k, v in marks.iteritems():
232 for k, v in marks.iteritems():
233 # don't expose local divergent bookmarks
233 # don't expose local divergent bookmarks
234 if hasnode(v) and ('@' not in k or k.endswith('@')):
234 if hasnode(v) and ('@' not in k or k.endswith('@')):
235 d[k] = hex(v)
235 d[k] = hex(v)
236 return d
236 return d
237
237
238 def pushbookmark(repo, key, old, new):
238 def pushbookmark(repo, key, old, new):
239 w = l = tr = None
239 w = l = tr = None
240 try:
240 try:
241 w = repo.wlock()
241 w = repo.wlock()
242 l = repo.lock()
242 l = repo.lock()
243 tr = repo.transaction('bookmarks')
243 tr = repo.transaction('bookmarks')
244 marks = repo._bookmarks
244 marks = repo._bookmarks
245 existing = hex(marks.get(key, ''))
245 existing = hex(marks.get(key, ''))
246 if existing != old and existing != new:
246 if existing != old and existing != new:
247 return False
247 return False
248 if new == '':
248 if new == '':
249 del marks[key]
249 del marks[key]
250 else:
250 else:
251 if new not in repo:
251 if new not in repo:
252 return False
252 return False
253 marks[key] = repo[new].node()
253 marks[key] = repo[new].node()
254 marks.recordchange(tr)
254 marks.recordchange(tr)
255 tr.close()
255 tr.close()
256 return True
256 return True
257 finally:
257 finally:
258 lockmod.release(tr, l, w)
258 lockmod.release(tr, l, w)
259
259
260 def compare(repo, srcmarks, dstmarks,
260 def compare(repo, srcmarks, dstmarks,
261 srchex=None, dsthex=None, targets=None):
261 srchex=None, dsthex=None, targets=None):
262 '''Compare bookmarks between srcmarks and dstmarks
262 '''Compare bookmarks between srcmarks and dstmarks
263
263
264 This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
264 This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
265 differ, invalid)", each are list of bookmarks below:
265 differ, invalid)", each are list of bookmarks below:
266
266
267 :addsrc: added on src side (removed on dst side, perhaps)
267 :addsrc: added on src side (removed on dst side, perhaps)
268 :adddst: added on dst side (removed on src side, perhaps)
268 :adddst: added on dst side (removed on src side, perhaps)
269 :advsrc: advanced on src side
269 :advsrc: advanced on src side
270 :advdst: advanced on dst side
270 :advdst: advanced on dst side
271 :diverge: diverge
271 :diverge: diverge
272 :differ: changed, but changeset referred on src is unknown on dst
272 :differ: changed, but changeset referred on src is unknown on dst
273 :invalid: unknown on both side
273 :invalid: unknown on both side
274 :same: same on both side
274 :same: same on both side
275
275
276 Each elements of lists in result tuple is tuple "(bookmark name,
276 Each elements of lists in result tuple is tuple "(bookmark name,
277 changeset ID on source side, changeset ID on destination
277 changeset ID on source side, changeset ID on destination
278 side)". Each changeset IDs are 40 hexadecimal digit string or
278 side)". Each changeset IDs are 40 hexadecimal digit string or
279 None.
279 None.
280
280
281 Changeset IDs of tuples in "addsrc", "adddst", "differ" or
281 Changeset IDs of tuples in "addsrc", "adddst", "differ" or
282 "invalid" list may be unknown for repo.
282 "invalid" list may be unknown for repo.
283
283
284 This function expects that "srcmarks" and "dstmarks" return
284 This function expects that "srcmarks" and "dstmarks" return
285 changeset ID in 40 hexadecimal digit string for specified
285 changeset ID in 40 hexadecimal digit string for specified
286 bookmark. If not so (e.g. bmstore "repo._bookmarks" returning
286 bookmark. If not so (e.g. bmstore "repo._bookmarks" returning
287 binary value), "srchex" or "dsthex" should be specified to convert
287 binary value), "srchex" or "dsthex" should be specified to convert
288 into such form.
288 into such form.
289
289
290 If "targets" is specified, only bookmarks listed in it are
290 If "targets" is specified, only bookmarks listed in it are
291 examined.
291 examined.
292 '''
292 '''
293 if not srchex:
293 if not srchex:
294 srchex = lambda x: x
294 srchex = lambda x: x
295 if not dsthex:
295 if not dsthex:
296 dsthex = lambda x: x
296 dsthex = lambda x: x
297
297
298 if targets:
298 if targets:
299 bset = set(targets)
299 bset = set(targets)
300 else:
300 else:
301 srcmarkset = set(srcmarks)
301 srcmarkset = set(srcmarks)
302 dstmarkset = set(dstmarks)
302 dstmarkset = set(dstmarks)
303 bset = srcmarkset | dstmarkset
303 bset = srcmarkset | dstmarkset
304
304
305 results = ([], [], [], [], [], [], [], [])
305 results = ([], [], [], [], [], [], [], [])
306 addsrc = results[0].append
306 addsrc = results[0].append
307 adddst = results[1].append
307 adddst = results[1].append
308 advsrc = results[2].append
308 advsrc = results[2].append
309 advdst = results[3].append
309 advdst = results[3].append
310 diverge = results[4].append
310 diverge = results[4].append
311 differ = results[5].append
311 differ = results[5].append
312 invalid = results[6].append
312 invalid = results[6].append
313 same = results[7].append
313 same = results[7].append
314
314
315 for b in sorted(bset):
315 for b in sorted(bset):
316 if b not in srcmarks:
316 if b not in srcmarks:
317 if b in dstmarks:
317 if b in dstmarks:
318 adddst((b, None, dsthex(dstmarks[b])))
318 adddst((b, None, dsthex(dstmarks[b])))
319 else:
319 else:
320 invalid((b, None, None))
320 invalid((b, None, None))
321 elif b not in dstmarks:
321 elif b not in dstmarks:
322 addsrc((b, srchex(srcmarks[b]), None))
322 addsrc((b, srchex(srcmarks[b]), None))
323 else:
323 else:
324 scid = srchex(srcmarks[b])
324 scid = srchex(srcmarks[b])
325 dcid = dsthex(dstmarks[b])
325 dcid = dsthex(dstmarks[b])
326 if scid == dcid:
326 if scid == dcid:
327 same((b, scid, dcid))
327 same((b, scid, dcid))
328 elif scid in repo and dcid in repo:
328 elif scid in repo and dcid in repo:
329 sctx = repo[scid]
329 sctx = repo[scid]
330 dctx = repo[dcid]
330 dctx = repo[dcid]
331 if sctx.rev() < dctx.rev():
331 if sctx.rev() < dctx.rev():
332 if validdest(repo, sctx, dctx):
332 if validdest(repo, sctx, dctx):
333 advdst((b, scid, dcid))
333 advdst((b, scid, dcid))
334 else:
334 else:
335 diverge((b, scid, dcid))
335 diverge((b, scid, dcid))
336 else:
336 else:
337 if validdest(repo, dctx, sctx):
337 if validdest(repo, dctx, sctx):
338 advsrc((b, scid, dcid))
338 advsrc((b, scid, dcid))
339 else:
339 else:
340 diverge((b, scid, dcid))
340 diverge((b, scid, dcid))
341 else:
341 else:
342 # it is too expensive to examine in detail, in this case
342 # it is too expensive to examine in detail, in this case
343 differ((b, scid, dcid))
343 differ((b, scid, dcid))
344
344
345 return results
345 return results
346
346
347 def _diverge(ui, b, path, localmarks):
347 def _diverge(ui, b, path, localmarks):
348 if b == '@':
348 if b == '@':
349 b = ''
349 b = ''
350 # find a unique @ suffix
350 # find a unique @ suffix
351 for x in range(1, 100):
351 for x in range(1, 100):
352 n = '%s@%d' % (b, x)
352 n = '%s@%d' % (b, x)
353 if n not in localmarks:
353 if n not in localmarks:
354 break
354 break
355 # try to use an @pathalias suffix
355 # try to use an @pathalias suffix
356 # if an @pathalias already exists, we overwrite (update) it
356 # if an @pathalias already exists, we overwrite (update) it
357 if path.startswith("file:"):
357 if path.startswith("file:"):
358 path = util.url(path).path
358 path = util.url(path).path
359 for p, u in ui.configitems("paths"):
359 for p, u in ui.configitems("paths"):
360 if u.startswith("file:"):
360 if u.startswith("file:"):
361 u = util.url(u).path
361 u = util.url(u).path
362 if path == u:
362 if path == u:
363 n = '%s@%s' % (b, p)
363 n = '%s@%s' % (b, p)
364 return n
364 return n
365
365
366 def updatefromremote(ui, repo, remotemarks, path, trfunc, explicit=()):
366 def updatefromremote(ui, repo, remotemarks, path, trfunc, explicit=()):
367 ui.debug("checking for updated bookmarks\n")
367 ui.debug("checking for updated bookmarks\n")
368 localmarks = repo._bookmarks
368 localmarks = repo._bookmarks
369 (addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same
369 (addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same
370 ) = compare(repo, remotemarks, localmarks, dsthex=hex)
370 ) = compare(repo, remotemarks, localmarks, dsthex=hex)
371
371
372 status = ui.status
372 status = ui.status
373 warn = ui.warn
373 warn = ui.warn
374 if ui.configbool('ui', 'quietbookmarkmove', False):
374 if ui.configbool('ui', 'quietbookmarkmove', False):
375 status = warn = ui.debug
375 status = warn = ui.debug
376
376
377 explicit = set(explicit)
377 explicit = set(explicit)
378 changed = []
378 changed = []
379 for b, scid, dcid in addsrc:
379 for b, scid, dcid in addsrc:
380 if scid in repo: # add remote bookmarks for changes we already have
380 if scid in repo: # add remote bookmarks for changes we already have
381 changed.append((b, bin(scid), status,
381 changed.append((b, bin(scid), status,
382 _("adding remote bookmark %s\n") % (b)))
382 _("adding remote bookmark %s\n") % (b)))
383 for b, scid, dcid in advsrc:
383 for b, scid, dcid in advsrc:
384 changed.append((b, bin(scid), status,
384 changed.append((b, bin(scid), status,
385 _("updating bookmark %s\n") % (b)))
385 _("updating bookmark %s\n") % (b)))
386 # remove normal movement from explicit set
386 # remove normal movement from explicit set
387 explicit.difference_update(d[0] for d in changed)
387 explicit.difference_update(d[0] for d in changed)
388
388
389 for b, scid, dcid in diverge:
389 for b, scid, dcid in diverge:
390 if b in explicit:
390 if b in explicit:
391 explicit.discard(b)
391 explicit.discard(b)
392 changed.append((b, bin(scid), status,
392 changed.append((b, bin(scid), status,
393 _("importing bookmark %s\n") % (b, b)))
393 _("importing bookmark %s\n") % (b)))
394 else:
394 else:
395 db = _diverge(ui, b, path, localmarks)
395 db = _diverge(ui, b, path, localmarks)
396 changed.append((db, bin(scid), warn,
396 changed.append((db, bin(scid), warn,
397 _("divergent bookmark %s stored as %s\n")
397 _("divergent bookmark %s stored as %s\n")
398 % (b, db)))
398 % (b, db)))
399 for b, scid, dcid in adddst + advdst:
399 for b, scid, dcid in adddst + advdst:
400 if b in explicit:
400 if b in explicit:
401 explicit.discard(b)
401 explicit.discard(b)
402 changed.append((b, bin(scid), status,
402 changed.append((b, bin(scid), status,
403 _("importing bookmark %s\n") % (b, b)))
403 _("importing bookmark %s\n") % (b)))
404
404
405 if changed:
405 if changed:
406 tr = trfunc()
406 tr = trfunc()
407 for b, node, writer, msg in sorted(changed):
407 for b, node, writer, msg in sorted(changed):
408 localmarks[b] = node
408 localmarks[b] = node
409 writer(msg)
409 writer(msg)
410 localmarks.recordchange(tr)
410 localmarks.recordchange(tr)
411
411
412 def diff(ui, dst, src):
412 def diff(ui, dst, src):
413 ui.status(_("searching for changed bookmarks\n"))
413 ui.status(_("searching for changed bookmarks\n"))
414
414
415 smarks = src.listkeys('bookmarks')
415 smarks = src.listkeys('bookmarks')
416 dmarks = dst.listkeys('bookmarks')
416 dmarks = dst.listkeys('bookmarks')
417
417
418 diff = sorted(set(smarks) - set(dmarks))
418 diff = sorted(set(smarks) - set(dmarks))
419 for k in diff:
419 for k in diff:
420 mark = ui.debugflag and smarks[k] or smarks[k][:12]
420 mark = ui.debugflag and smarks[k] or smarks[k][:12]
421 ui.write(" %-25s %s\n" % (k, mark))
421 ui.write(" %-25s %s\n" % (k, mark))
422
422
423 if len(diff) <= 0:
423 if len(diff) <= 0:
424 ui.status(_("no changed bookmarks found\n"))
424 ui.status(_("no changed bookmarks found\n"))
425 return 1
425 return 1
426 return 0
426 return 0
427
427
428 def validdest(repo, old, new):
428 def validdest(repo, old, new):
429 """Is the new bookmark destination a valid update from the old one"""
429 """Is the new bookmark destination a valid update from the old one"""
430 repo = repo.unfiltered()
430 repo = repo.unfiltered()
431 if old == new:
431 if old == new:
432 # Old == new -> nothing to update.
432 # Old == new -> nothing to update.
433 return False
433 return False
434 elif not old:
434 elif not old:
435 # old is nullrev, anything is valid.
435 # old is nullrev, anything is valid.
436 # (new != nullrev has been excluded by the previous check)
436 # (new != nullrev has been excluded by the previous check)
437 return True
437 return True
438 elif repo.obsstore:
438 elif repo.obsstore:
439 return new.node() in obsolete.foreground(repo, [old.node()])
439 return new.node() in obsolete.foreground(repo, [old.node()])
440 else:
440 else:
441 # still an independent clause as it is lazyer (and therefore faster)
441 # still an independent clause as it is lazyer (and therefore faster)
442 return old.descendant(new)
442 return old.descendant(new)
@@ -1,466 +1,489 b''
1 #require serve
1 #require serve
2
2
3 $ cat << EOF >> $HGRCPATH
3 $ cat << EOF >> $HGRCPATH
4 > [ui]
4 > [ui]
5 > logtemplate={rev}:{node|short} {desc|firstline}
5 > logtemplate={rev}:{node|short} {desc|firstline}
6 > [phases]
6 > [phases]
7 > publish=False
7 > publish=False
8 > [experimental]
8 > [experimental]
9 > evolution=createmarkers,exchange
9 > evolution=createmarkers,exchange
10 > EOF
10 > EOF
11
11
12 initialize
12 initialize
13
13
14 $ hg init a
14 $ hg init a
15 $ cd a
15 $ cd a
16 $ echo 'test' > test
16 $ echo 'test' > test
17 $ hg commit -Am'test'
17 $ hg commit -Am'test'
18 adding test
18 adding test
19
19
20 set bookmarks
20 set bookmarks
21
21
22 $ hg bookmark X
22 $ hg bookmark X
23 $ hg bookmark Y
23 $ hg bookmark Y
24 $ hg bookmark Z
24 $ hg bookmark Z
25
25
26 import bookmark by name
26 import bookmark by name
27
27
28 $ hg init ../b
28 $ hg init ../b
29 $ cd ../b
29 $ cd ../b
30 $ hg book Y
30 $ hg book Y
31 $ hg book
31 $ hg book
32 * Y -1:000000000000
32 * Y -1:000000000000
33 $ hg pull ../a
33 $ hg pull ../a
34 pulling from ../a
34 pulling from ../a
35 requesting all changes
35 requesting all changes
36 adding changesets
36 adding changesets
37 adding manifests
37 adding manifests
38 adding file changes
38 adding file changes
39 added 1 changesets with 1 changes to 1 files
39 added 1 changesets with 1 changes to 1 files
40 adding remote bookmark X
40 adding remote bookmark X
41 updating bookmark Y
41 updating bookmark Y
42 adding remote bookmark Z
42 adding remote bookmark Z
43 (run 'hg update' to get a working copy)
43 (run 'hg update' to get a working copy)
44 $ hg bookmarks
44 $ hg bookmarks
45 X 0:4e3505fd9583
45 X 0:4e3505fd9583
46 * Y 0:4e3505fd9583
46 * Y 0:4e3505fd9583
47 Z 0:4e3505fd9583
47 Z 0:4e3505fd9583
48 $ hg debugpushkey ../a namespaces
48 $ hg debugpushkey ../a namespaces
49 bookmarks
49 bookmarks
50 namespaces
50 namespaces
51 obsolete
51 obsolete
52 phases
52 phases
53 $ hg debugpushkey ../a bookmarks
53 $ hg debugpushkey ../a bookmarks
54 X 4e3505fd95835d721066b76e75dbb8cc554d7f77
54 X 4e3505fd95835d721066b76e75dbb8cc554d7f77
55 Y 4e3505fd95835d721066b76e75dbb8cc554d7f77
55 Y 4e3505fd95835d721066b76e75dbb8cc554d7f77
56 Z 4e3505fd95835d721066b76e75dbb8cc554d7f77
56 Z 4e3505fd95835d721066b76e75dbb8cc554d7f77
57
58 delete the bookmark to repull it
59
60 $ hg book -d X
61 $ hg pull -B X ../a
62 pulling from ../a
63 no changes found
64 adding remote bookmark X
65
66 finally no-op pull
67
57 $ hg pull -B X ../a
68 $ hg pull -B X ../a
58 pulling from ../a
69 pulling from ../a
59 no changes found
70 no changes found
60 $ hg bookmark
71 $ hg bookmark
61 X 0:4e3505fd9583
72 X 0:4e3505fd9583
62 * Y 0:4e3505fd9583
73 * Y 0:4e3505fd9583
63 Z 0:4e3505fd9583
74 Z 0:4e3505fd9583
64
75
65 export bookmark by name
76 export bookmark by name
66
77
67 $ hg bookmark W
78 $ hg bookmark W
68 $ hg bookmark foo
79 $ hg bookmark foo
69 $ hg bookmark foobar
80 $ hg bookmark foobar
70 $ hg push -B W ../a
81 $ hg push -B W ../a
71 pushing to ../a
82 pushing to ../a
72 searching for changes
83 searching for changes
73 no changes found
84 no changes found
74 exporting bookmark W
85 exporting bookmark W
75 [1]
86 [1]
76 $ hg -R ../a bookmarks
87 $ hg -R ../a bookmarks
77 W -1:000000000000
88 W -1:000000000000
78 X 0:4e3505fd9583
89 X 0:4e3505fd9583
79 Y 0:4e3505fd9583
90 Y 0:4e3505fd9583
80 * Z 0:4e3505fd9583
91 * Z 0:4e3505fd9583
81
92
82 delete a remote bookmark
93 delete a remote bookmark
83
94
84 $ hg book -d W
95 $ hg book -d W
85 $ hg push -B W ../a
96 $ hg push -B W ../a
86 pushing to ../a
97 pushing to ../a
87 searching for changes
98 searching for changes
88 no changes found
99 no changes found
89 deleting remote bookmark W
100 deleting remote bookmark W
90 [1]
101 [1]
91
102
92 push/pull name that doesn't exist
103 push/pull name that doesn't exist
93
104
94 $ hg push -B badname ../a
105 $ hg push -B badname ../a
95 pushing to ../a
106 pushing to ../a
96 searching for changes
107 searching for changes
97 bookmark badname does not exist on the local or remote repository!
108 bookmark badname does not exist on the local or remote repository!
98 no changes found
109 no changes found
99 [2]
110 [2]
100 $ hg pull -B anotherbadname ../a
111 $ hg pull -B anotherbadname ../a
101 pulling from ../a
112 pulling from ../a
102 abort: remote bookmark anotherbadname not found!
113 abort: remote bookmark anotherbadname not found!
103 [255]
114 [255]
104
115
105 divergent bookmarks
116 divergent bookmarks
106
117
107 $ cd ../a
118 $ cd ../a
108 $ echo c1 > f1
119 $ echo c1 > f1
109 $ hg ci -Am1
120 $ hg ci -Am1
110 adding f1
121 adding f1
111 $ hg book -f @
122 $ hg book -f @
112 $ hg book -f X
123 $ hg book -f X
113 $ hg book
124 $ hg book
114 @ 1:0d2164f0ce0d
125 @ 1:0d2164f0ce0d
115 * X 1:0d2164f0ce0d
126 * X 1:0d2164f0ce0d
116 Y 0:4e3505fd9583
127 Y 0:4e3505fd9583
117 Z 1:0d2164f0ce0d
128 Z 1:0d2164f0ce0d
118
129
119 $ cd ../b
130 $ cd ../b
120 $ hg up
131 $ hg up
121 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
132 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
122 updating bookmark foobar
133 updating bookmark foobar
123 $ echo c2 > f2
134 $ echo c2 > f2
124 $ hg ci -Am2
135 $ hg ci -Am2
125 adding f2
136 adding f2
126 $ hg book -if @
137 $ hg book -if @
127 $ hg book -if X
138 $ hg book -if X
128 $ hg book
139 $ hg book
129 @ 1:9b140be10808
140 @ 1:9b140be10808
130 X 1:9b140be10808
141 X 1:9b140be10808
131 Y 0:4e3505fd9583
142 Y 0:4e3505fd9583
132 Z 0:4e3505fd9583
143 Z 0:4e3505fd9583
133 foo -1:000000000000
144 foo -1:000000000000
134 * foobar 1:9b140be10808
145 * foobar 1:9b140be10808
135
146
136 $ hg pull --config paths.foo=../a foo
147 $ hg pull --config paths.foo=../a foo
137 pulling from $TESTTMP/a (glob)
148 pulling from $TESTTMP/a (glob)
138 searching for changes
149 searching for changes
139 adding changesets
150 adding changesets
140 adding manifests
151 adding manifests
141 adding file changes
152 adding file changes
142 added 1 changesets with 1 changes to 1 files (+1 heads)
153 added 1 changesets with 1 changes to 1 files (+1 heads)
143 divergent bookmark @ stored as @foo
154 divergent bookmark @ stored as @foo
144 divergent bookmark X stored as X@foo
155 divergent bookmark X stored as X@foo
145 updating bookmark Z
156 updating bookmark Z
146 (run 'hg heads' to see heads, 'hg merge' to merge)
157 (run 'hg heads' to see heads, 'hg merge' to merge)
147 $ hg book
158 $ hg book
148 @ 1:9b140be10808
159 @ 1:9b140be10808
149 @foo 2:0d2164f0ce0d
160 @foo 2:0d2164f0ce0d
150 X 1:9b140be10808
161 X 1:9b140be10808
151 X@foo 2:0d2164f0ce0d
162 X@foo 2:0d2164f0ce0d
152 Y 0:4e3505fd9583
163 Y 0:4e3505fd9583
153 Z 2:0d2164f0ce0d
164 Z 2:0d2164f0ce0d
154 foo -1:000000000000
165 foo -1:000000000000
155 * foobar 1:9b140be10808
166 * foobar 1:9b140be10808
156 $ hg push -f ../a
167 $ hg push -f ../a
157 pushing to ../a
168 pushing to ../a
158 searching for changes
169 searching for changes
159 adding changesets
170 adding changesets
160 adding manifests
171 adding manifests
161 adding file changes
172 adding file changes
162 added 1 changesets with 1 changes to 1 files (+1 heads)
173 added 1 changesets with 1 changes to 1 files (+1 heads)
163 $ hg -R ../a book
174 $ hg -R ../a book
164 @ 1:0d2164f0ce0d
175 @ 1:0d2164f0ce0d
165 * X 1:0d2164f0ce0d
176 * X 1:0d2164f0ce0d
166 Y 0:4e3505fd9583
177 Y 0:4e3505fd9583
167 Z 1:0d2164f0ce0d
178 Z 1:0d2164f0ce0d
168
179
180 explicite pull should overwrite the local version (issue4439)
181
182 $ hg pull --config paths.foo=../a foo -B X
183 pulling from $TESTTMP/a (glob)
184 no changes found
185 divergent bookmark @ stored as @foo
186 importing bookmark X
187
188 reinstall state for further testing:
189
190 $ hg book -fr 9b140be10808 X
191
169 revsets should not ignore divergent bookmarks
192 revsets should not ignore divergent bookmarks
170
193
171 $ hg bookmark -fr 1 Z
194 $ hg bookmark -fr 1 Z
172 $ hg log -r 'bookmark()' --template '{rev}:{node|short} {bookmarks}\n'
195 $ hg log -r 'bookmark()' --template '{rev}:{node|short} {bookmarks}\n'
173 0:4e3505fd9583 Y
196 0:4e3505fd9583 Y
174 1:9b140be10808 @ X Z foobar
197 1:9b140be10808 @ X Z foobar
175 2:0d2164f0ce0d @foo X@foo
198 2:0d2164f0ce0d @foo X@foo
176 $ hg log -r 'bookmark("X@foo")' --template '{rev}:{node|short} {bookmarks}\n'
199 $ hg log -r 'bookmark("X@foo")' --template '{rev}:{node|short} {bookmarks}\n'
177 2:0d2164f0ce0d @foo X@foo
200 2:0d2164f0ce0d @foo X@foo
178 $ hg log -r 'bookmark("re:X@foo")' --template '{rev}:{node|short} {bookmarks}\n'
201 $ hg log -r 'bookmark("re:X@foo")' --template '{rev}:{node|short} {bookmarks}\n'
179 2:0d2164f0ce0d @foo X@foo
202 2:0d2164f0ce0d @foo X@foo
180
203
181 update a remote bookmark from a non-head to a head
204 update a remote bookmark from a non-head to a head
182
205
183 $ hg up -q Y
206 $ hg up -q Y
184 $ echo c3 > f2
207 $ echo c3 > f2
185 $ hg ci -Am3
208 $ hg ci -Am3
186 adding f2
209 adding f2
187 created new head
210 created new head
188 $ hg push ../a
211 $ hg push ../a
189 pushing to ../a
212 pushing to ../a
190 searching for changes
213 searching for changes
191 adding changesets
214 adding changesets
192 adding manifests
215 adding manifests
193 adding file changes
216 adding file changes
194 added 1 changesets with 1 changes to 1 files (+1 heads)
217 added 1 changesets with 1 changes to 1 files (+1 heads)
195 updating bookmark Y
218 updating bookmark Y
196 $ hg -R ../a book
219 $ hg -R ../a book
197 @ 1:0d2164f0ce0d
220 @ 1:0d2164f0ce0d
198 * X 1:0d2164f0ce0d
221 * X 1:0d2164f0ce0d
199 Y 3:f6fc62dde3c0
222 Y 3:f6fc62dde3c0
200 Z 1:0d2164f0ce0d
223 Z 1:0d2164f0ce0d
201
224
202 update a bookmark in the middle of a client pulling changes
225 update a bookmark in the middle of a client pulling changes
203
226
204 $ cd ..
227 $ cd ..
205 $ hg clone -q a pull-race
228 $ hg clone -q a pull-race
206 $ hg clone -q pull-race pull-race2
229 $ hg clone -q pull-race pull-race2
207 $ cd pull-race
230 $ cd pull-race
208 $ hg up -q Y
231 $ hg up -q Y
209 $ echo c4 > f2
232 $ echo c4 > f2
210 $ hg ci -Am4
233 $ hg ci -Am4
211 $ echo c5 > f3
234 $ echo c5 > f3
212 $ cat <<EOF > .hg/hgrc
235 $ cat <<EOF > .hg/hgrc
213 > [hooks]
236 > [hooks]
214 > outgoing.makecommit = hg ci -Am5; echo committed in pull-race
237 > outgoing.makecommit = hg ci -Am5; echo committed in pull-race
215 > EOF
238 > EOF
216 $ cd ../pull-race2
239 $ cd ../pull-race2
217 $ hg pull
240 $ hg pull
218 pulling from $TESTTMP/pull-race (glob)
241 pulling from $TESTTMP/pull-race (glob)
219 searching for changes
242 searching for changes
220 adding changesets
243 adding changesets
221 adding f3
244 adding f3
222 committed in pull-race
245 committed in pull-race
223 adding manifests
246 adding manifests
224 adding file changes
247 adding file changes
225 added 1 changesets with 1 changes to 1 files
248 added 1 changesets with 1 changes to 1 files
226 updating bookmark Y
249 updating bookmark Y
227 (run 'hg update' to get a working copy)
250 (run 'hg update' to get a working copy)
228 $ hg book
251 $ hg book
229 * @ 1:0d2164f0ce0d
252 * @ 1:0d2164f0ce0d
230 X 1:0d2164f0ce0d
253 X 1:0d2164f0ce0d
231 Y 4:b0a5eff05604
254 Y 4:b0a5eff05604
232 Z 1:0d2164f0ce0d
255 Z 1:0d2164f0ce0d
233 $ cd ../b
256 $ cd ../b
234
257
235 diverging a remote bookmark fails
258 diverging a remote bookmark fails
236
259
237 $ hg up -q 4e3505fd9583
260 $ hg up -q 4e3505fd9583
238 $ echo c4 > f2
261 $ echo c4 > f2
239 $ hg ci -Am4
262 $ hg ci -Am4
240 adding f2
263 adding f2
241 created new head
264 created new head
242 $ echo c5 > f2
265 $ echo c5 > f2
243 $ hg ci -Am5
266 $ hg ci -Am5
244 $ hg log -G
267 $ hg log -G
245 @ 5:c922c0139ca0 5
268 @ 5:c922c0139ca0 5
246 |
269 |
247 o 4:4efff6d98829 4
270 o 4:4efff6d98829 4
248 |
271 |
249 | o 3:f6fc62dde3c0 3
272 | o 3:f6fc62dde3c0 3
250 |/
273 |/
251 | o 2:0d2164f0ce0d 1
274 | o 2:0d2164f0ce0d 1
252 |/
275 |/
253 | o 1:9b140be10808 2
276 | o 1:9b140be10808 2
254 |/
277 |/
255 o 0:4e3505fd9583 test
278 o 0:4e3505fd9583 test
256
279
257
280
258 $ hg book -f Y
281 $ hg book -f Y
259
282
260 $ cat <<EOF > ../a/.hg/hgrc
283 $ cat <<EOF > ../a/.hg/hgrc
261 > [web]
284 > [web]
262 > push_ssl = false
285 > push_ssl = false
263 > allow_push = *
286 > allow_push = *
264 > EOF
287 > EOF
265
288
266 $ hg -R ../a serve -p $HGPORT2 -d --pid-file=../hg2.pid
289 $ hg -R ../a serve -p $HGPORT2 -d --pid-file=../hg2.pid
267 $ cat ../hg2.pid >> $DAEMON_PIDS
290 $ cat ../hg2.pid >> $DAEMON_PIDS
268
291
269 $ hg push http://localhost:$HGPORT2/
292 $ hg push http://localhost:$HGPORT2/
270 pushing to http://localhost:$HGPORT2/
293 pushing to http://localhost:$HGPORT2/
271 searching for changes
294 searching for changes
272 abort: push creates new remote head c922c0139ca0 with bookmark 'Y'!
295 abort: push creates new remote head c922c0139ca0 with bookmark 'Y'!
273 (merge or see "hg help push" for details about pushing new heads)
296 (merge or see "hg help push" for details about pushing new heads)
274 [255]
297 [255]
275 $ hg -R ../a book
298 $ hg -R ../a book
276 @ 1:0d2164f0ce0d
299 @ 1:0d2164f0ce0d
277 * X 1:0d2164f0ce0d
300 * X 1:0d2164f0ce0d
278 Y 3:f6fc62dde3c0
301 Y 3:f6fc62dde3c0
279 Z 1:0d2164f0ce0d
302 Z 1:0d2164f0ce0d
280
303
281
304
282 Unrelated marker does not alter the decision
305 Unrelated marker does not alter the decision
283
306
284 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
307 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
285 $ hg push http://localhost:$HGPORT2/
308 $ hg push http://localhost:$HGPORT2/
286 pushing to http://localhost:$HGPORT2/
309 pushing to http://localhost:$HGPORT2/
287 searching for changes
310 searching for changes
288 abort: push creates new remote head c922c0139ca0 with bookmark 'Y'!
311 abort: push creates new remote head c922c0139ca0 with bookmark 'Y'!
289 (merge or see "hg help push" for details about pushing new heads)
312 (merge or see "hg help push" for details about pushing new heads)
290 [255]
313 [255]
291 $ hg -R ../a book
314 $ hg -R ../a book
292 @ 1:0d2164f0ce0d
315 @ 1:0d2164f0ce0d
293 * X 1:0d2164f0ce0d
316 * X 1:0d2164f0ce0d
294 Y 3:f6fc62dde3c0
317 Y 3:f6fc62dde3c0
295 Z 1:0d2164f0ce0d
318 Z 1:0d2164f0ce0d
296
319
297 Update to a successor works
320 Update to a successor works
298
321
299 $ hg id --debug -r 3
322 $ hg id --debug -r 3
300 f6fc62dde3c0771e29704af56ba4d8af77abcc2f
323 f6fc62dde3c0771e29704af56ba4d8af77abcc2f
301 $ hg id --debug -r 4
324 $ hg id --debug -r 4
302 4efff6d98829d9c824c621afd6e3f01865f5439f
325 4efff6d98829d9c824c621afd6e3f01865f5439f
303 $ hg id --debug -r 5
326 $ hg id --debug -r 5
304 c922c0139ca03858f655e4a2af4dd02796a63969 tip Y
327 c922c0139ca03858f655e4a2af4dd02796a63969 tip Y
305 $ hg debugobsolete f6fc62dde3c0771e29704af56ba4d8af77abcc2f cccccccccccccccccccccccccccccccccccccccc
328 $ hg debugobsolete f6fc62dde3c0771e29704af56ba4d8af77abcc2f cccccccccccccccccccccccccccccccccccccccc
306 $ hg debugobsolete cccccccccccccccccccccccccccccccccccccccc 4efff6d98829d9c824c621afd6e3f01865f5439f
329 $ hg debugobsolete cccccccccccccccccccccccccccccccccccccccc 4efff6d98829d9c824c621afd6e3f01865f5439f
307 $ hg push http://localhost:$HGPORT2/
330 $ hg push http://localhost:$HGPORT2/
308 pushing to http://localhost:$HGPORT2/
331 pushing to http://localhost:$HGPORT2/
309 searching for changes
332 searching for changes
310 remote: adding changesets
333 remote: adding changesets
311 remote: adding manifests
334 remote: adding manifests
312 remote: adding file changes
335 remote: adding file changes
313 remote: added 2 changesets with 2 changes to 1 files (+1 heads)
336 remote: added 2 changesets with 2 changes to 1 files (+1 heads)
314 updating bookmark Y
337 updating bookmark Y
315 $ hg -R ../a book
338 $ hg -R ../a book
316 @ 1:0d2164f0ce0d
339 @ 1:0d2164f0ce0d
317 * X 1:0d2164f0ce0d
340 * X 1:0d2164f0ce0d
318 Y 5:c922c0139ca0
341 Y 5:c922c0139ca0
319 Z 1:0d2164f0ce0d
342 Z 1:0d2164f0ce0d
320
343
321 hgweb
344 hgweb
322
345
323 $ cat <<EOF > .hg/hgrc
346 $ cat <<EOF > .hg/hgrc
324 > [web]
347 > [web]
325 > push_ssl = false
348 > push_ssl = false
326 > allow_push = *
349 > allow_push = *
327 > EOF
350 > EOF
328
351
329 $ hg serve -p $HGPORT -d --pid-file=../hg.pid -E errors.log
352 $ hg serve -p $HGPORT -d --pid-file=../hg.pid -E errors.log
330 $ cat ../hg.pid >> $DAEMON_PIDS
353 $ cat ../hg.pid >> $DAEMON_PIDS
331 $ cd ../a
354 $ cd ../a
332
355
333 $ hg debugpushkey http://localhost:$HGPORT/ namespaces
356 $ hg debugpushkey http://localhost:$HGPORT/ namespaces
334 bookmarks
357 bookmarks
335 namespaces
358 namespaces
336 obsolete
359 obsolete
337 phases
360 phases
338 $ hg debugpushkey http://localhost:$HGPORT/ bookmarks
361 $ hg debugpushkey http://localhost:$HGPORT/ bookmarks
339 @ 9b140be1080824d768c5a4691a564088eede71f9
362 @ 9b140be1080824d768c5a4691a564088eede71f9
340 X 9b140be1080824d768c5a4691a564088eede71f9
363 X 9b140be1080824d768c5a4691a564088eede71f9
341 Y c922c0139ca03858f655e4a2af4dd02796a63969
364 Y c922c0139ca03858f655e4a2af4dd02796a63969
342 Z 9b140be1080824d768c5a4691a564088eede71f9
365 Z 9b140be1080824d768c5a4691a564088eede71f9
343 foo 0000000000000000000000000000000000000000
366 foo 0000000000000000000000000000000000000000
344 foobar 9b140be1080824d768c5a4691a564088eede71f9
367 foobar 9b140be1080824d768c5a4691a564088eede71f9
345 $ hg out -B http://localhost:$HGPORT/
368 $ hg out -B http://localhost:$HGPORT/
346 comparing with http://localhost:$HGPORT/
369 comparing with http://localhost:$HGPORT/
347 searching for changed bookmarks
370 searching for changed bookmarks
348 no changed bookmarks found
371 no changed bookmarks found
349 [1]
372 [1]
350 $ hg push -B Z http://localhost:$HGPORT/
373 $ hg push -B Z http://localhost:$HGPORT/
351 pushing to http://localhost:$HGPORT/
374 pushing to http://localhost:$HGPORT/
352 searching for changes
375 searching for changes
353 no changes found
376 no changes found
354 updating bookmark Z
377 updating bookmark Z
355 [1]
378 [1]
356 $ hg book -d Z
379 $ hg book -d Z
357 $ hg in -B http://localhost:$HGPORT/
380 $ hg in -B http://localhost:$HGPORT/
358 comparing with http://localhost:$HGPORT/
381 comparing with http://localhost:$HGPORT/
359 searching for changed bookmarks
382 searching for changed bookmarks
360 Z 0d2164f0ce0d
383 Z 0d2164f0ce0d
361 foo 000000000000
384 foo 000000000000
362 foobar 9b140be10808
385 foobar 9b140be10808
363 $ hg pull -B Z http://localhost:$HGPORT/
386 $ hg pull -B Z http://localhost:$HGPORT/
364 pulling from http://localhost:$HGPORT/
387 pulling from http://localhost:$HGPORT/
365 no changes found
388 no changes found
366 divergent bookmark @ stored as @1
389 divergent bookmark @ stored as @1
367 divergent bookmark X stored as X@1
390 divergent bookmark X stored as X@1
368 adding remote bookmark Z
391 adding remote bookmark Z
369 adding remote bookmark foo
392 adding remote bookmark foo
370 adding remote bookmark foobar
393 adding remote bookmark foobar
371 $ hg clone http://localhost:$HGPORT/ cloned-bookmarks
394 $ hg clone http://localhost:$HGPORT/ cloned-bookmarks
372 requesting all changes
395 requesting all changes
373 adding changesets
396 adding changesets
374 adding manifests
397 adding manifests
375 adding file changes
398 adding file changes
376 added 5 changesets with 5 changes to 3 files (+2 heads)
399 added 5 changesets with 5 changes to 3 files (+2 heads)
377 updating to bookmark @
400 updating to bookmark @
378 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
401 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
379 $ hg -R cloned-bookmarks bookmarks
402 $ hg -R cloned-bookmarks bookmarks
380 * @ 1:9b140be10808
403 * @ 1:9b140be10808
381 X 1:9b140be10808
404 X 1:9b140be10808
382 Y 4:c922c0139ca0
405 Y 4:c922c0139ca0
383 Z 2:0d2164f0ce0d
406 Z 2:0d2164f0ce0d
384 foo -1:000000000000
407 foo -1:000000000000
385 foobar 1:9b140be10808
408 foobar 1:9b140be10808
386
409
387 $ cd ..
410 $ cd ..
388
411
389 Pushing a bookmark should only push the changes required by that
412 Pushing a bookmark should only push the changes required by that
390 bookmark, not all outgoing changes:
413 bookmark, not all outgoing changes:
391 $ hg clone http://localhost:$HGPORT/ addmarks
414 $ hg clone http://localhost:$HGPORT/ addmarks
392 requesting all changes
415 requesting all changes
393 adding changesets
416 adding changesets
394 adding manifests
417 adding manifests
395 adding file changes
418 adding file changes
396 added 5 changesets with 5 changes to 3 files (+2 heads)
419 added 5 changesets with 5 changes to 3 files (+2 heads)
397 updating to bookmark @
420 updating to bookmark @
398 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
421 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
399 $ cd addmarks
422 $ cd addmarks
400 $ echo foo > foo
423 $ echo foo > foo
401 $ hg add foo
424 $ hg add foo
402 $ hg commit -m 'add foo'
425 $ hg commit -m 'add foo'
403 $ echo bar > bar
426 $ echo bar > bar
404 $ hg add bar
427 $ hg add bar
405 $ hg commit -m 'add bar'
428 $ hg commit -m 'add bar'
406 $ hg co "tip^"
429 $ hg co "tip^"
407 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
430 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
408 (leaving bookmark @)
431 (leaving bookmark @)
409 $ hg book add-foo
432 $ hg book add-foo
410 $ hg book -r tip add-bar
433 $ hg book -r tip add-bar
411 Note: this push *must* push only a single changeset, as that's the point
434 Note: this push *must* push only a single changeset, as that's the point
412 of this test.
435 of this test.
413 $ hg push -B add-foo --traceback
436 $ hg push -B add-foo --traceback
414 pushing to http://localhost:$HGPORT/
437 pushing to http://localhost:$HGPORT/
415 searching for changes
438 searching for changes
416 remote: adding changesets
439 remote: adding changesets
417 remote: adding manifests
440 remote: adding manifests
418 remote: adding file changes
441 remote: adding file changes
419 remote: added 1 changesets with 1 changes to 1 files
442 remote: added 1 changesets with 1 changes to 1 files
420 exporting bookmark add-foo
443 exporting bookmark add-foo
421
444
422 pushing a new bookmark on a new head does not require -f if -B is specified
445 pushing a new bookmark on a new head does not require -f if -B is specified
423
446
424 $ hg up -q X
447 $ hg up -q X
425 $ hg book W
448 $ hg book W
426 $ echo c5 > f2
449 $ echo c5 > f2
427 $ hg ci -Am5
450 $ hg ci -Am5
428 created new head
451 created new head
429 $ hg push -B W
452 $ hg push -B W
430 pushing to http://localhost:$HGPORT/
453 pushing to http://localhost:$HGPORT/
431 searching for changes
454 searching for changes
432 remote: adding changesets
455 remote: adding changesets
433 remote: adding manifests
456 remote: adding manifests
434 remote: adding file changes
457 remote: adding file changes
435 remote: added 1 changesets with 1 changes to 1 files (+1 heads)
458 remote: added 1 changesets with 1 changes to 1 files (+1 heads)
436 exporting bookmark W
459 exporting bookmark W
437 $ hg -R ../b id -r W
460 $ hg -R ../b id -r W
438 cc978a373a53 tip W
461 cc978a373a53 tip W
439
462
440 $ cd ..
463 $ cd ..
441
464
442 pushing an unchanged bookmark should result in no changes
465 pushing an unchanged bookmark should result in no changes
443
466
444 $ hg init unchanged-a
467 $ hg init unchanged-a
445 $ hg init unchanged-b
468 $ hg init unchanged-b
446 $ cd unchanged-a
469 $ cd unchanged-a
447 $ echo initial > foo
470 $ echo initial > foo
448 $ hg commit -A -m initial
471 $ hg commit -A -m initial
449 adding foo
472 adding foo
450 $ hg bookmark @
473 $ hg bookmark @
451 $ hg push -B @ ../unchanged-b
474 $ hg push -B @ ../unchanged-b
452 pushing to ../unchanged-b
475 pushing to ../unchanged-b
453 searching for changes
476 searching for changes
454 adding changesets
477 adding changesets
455 adding manifests
478 adding manifests
456 adding file changes
479 adding file changes
457 added 1 changesets with 1 changes to 1 files
480 added 1 changesets with 1 changes to 1 files
458 exporting bookmark @
481 exporting bookmark @
459
482
460 $ hg push -B @ ../unchanged-b
483 $ hg push -B @ ../unchanged-b
461 pushing to ../unchanged-b
484 pushing to ../unchanged-b
462 searching for changes
485 searching for changes
463 no changes found
486 no changes found
464 [1]
487 [1]
465
488
466 $ cd ..
489 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now