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