##// END OF EJS Templates
bookmarks: check HG_PENDING strictly...
FUJIWARA Katsunori -
r31052:0332b8fa default
parent child Browse files
Show More
@@ -1,194 +1,216 b''
1 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
1 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
2 #
2 #
3 # This software may be used and distributed according to the terms of the
3 # This software may be used and distributed according to the terms of the
4 # GNU General Public License version 2 or any later version.
4 # GNU General Public License version 2 or any later version.
5
5
6 '''share a common history between several working directories
6 '''share a common history between several working directories
7
7
8 Automatic Pooled Storage for Clones
8 Automatic Pooled Storage for Clones
9 -----------------------------------
9 -----------------------------------
10
10
11 When this extension is active, :hg:`clone` can be configured to
11 When this extension is active, :hg:`clone` can be configured to
12 automatically share/pool storage across multiple clones. This
12 automatically share/pool storage across multiple clones. This
13 mode effectively converts :hg:`clone` to :hg:`clone` + :hg:`share`.
13 mode effectively converts :hg:`clone` to :hg:`clone` + :hg:`share`.
14 The benefit of using this mode is the automatic management of
14 The benefit of using this mode is the automatic management of
15 store paths and intelligent pooling of related repositories.
15 store paths and intelligent pooling of related repositories.
16
16
17 The following ``share.`` config options influence this feature:
17 The following ``share.`` config options influence this feature:
18
18
19 ``share.pool``
19 ``share.pool``
20 Filesystem path where shared repository data will be stored. When
20 Filesystem path where shared repository data will be stored. When
21 defined, :hg:`clone` will automatically use shared repository
21 defined, :hg:`clone` will automatically use shared repository
22 storage instead of creating a store inside each clone.
22 storage instead of creating a store inside each clone.
23
23
24 ``share.poolnaming``
24 ``share.poolnaming``
25 How directory names in ``share.pool`` are constructed.
25 How directory names in ``share.pool`` are constructed.
26
26
27 "identity" means the name is derived from the first changeset in the
27 "identity" means the name is derived from the first changeset in the
28 repository. In this mode, different remotes share storage if their
28 repository. In this mode, different remotes share storage if their
29 root/initial changeset is identical. In this mode, the local shared
29 root/initial changeset is identical. In this mode, the local shared
30 repository is an aggregate of all encountered remote repositories.
30 repository is an aggregate of all encountered remote repositories.
31
31
32 "remote" means the name is derived from the source repository's
32 "remote" means the name is derived from the source repository's
33 path or URL. In this mode, storage is only shared if the path or URL
33 path or URL. In this mode, storage is only shared if the path or URL
34 requested in the :hg:`clone` command matches exactly to a repository
34 requested in the :hg:`clone` command matches exactly to a repository
35 that was cloned before.
35 that was cloned before.
36
36
37 The default naming mode is "identity."
37 The default naming mode is "identity."
38 '''
38 '''
39
39
40 from __future__ import absolute_import
40 from __future__ import absolute_import
41
41
42 import errno
42 import errno
43 from mercurial.i18n import _
43 from mercurial.i18n import _
44 from mercurial import (
44 from mercurial import (
45 bookmarks,
45 bookmarks,
46 cmdutil,
46 cmdutil,
47 commands,
47 commands,
48 error,
48 error,
49 extensions,
49 extensions,
50 hg,
50 hg,
51 txnutil,
51 util,
52 util,
52 )
53 )
53
54
54 repository = hg.repository
55 repository = hg.repository
55 parseurl = hg.parseurl
56 parseurl = hg.parseurl
56
57
57 cmdtable = {}
58 cmdtable = {}
58 command = cmdutil.command(cmdtable)
59 command = cmdutil.command(cmdtable)
59 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
60 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
60 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
61 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
61 # be specifying the version(s) of Mercurial they are tested with, or
62 # be specifying the version(s) of Mercurial they are tested with, or
62 # leave the attribute unspecified.
63 # leave the attribute unspecified.
63 testedwith = 'ships-with-hg-core'
64 testedwith = 'ships-with-hg-core'
64
65
65 @command('share',
66 @command('share',
66 [('U', 'noupdate', None, _('do not create a working directory')),
67 [('U', 'noupdate', None, _('do not create a working directory')),
67 ('B', 'bookmarks', None, _('also share bookmarks'))],
68 ('B', 'bookmarks', None, _('also share bookmarks'))],
68 _('[-U] [-B] SOURCE [DEST]'),
69 _('[-U] [-B] SOURCE [DEST]'),
69 norepo=True)
70 norepo=True)
70 def share(ui, source, dest=None, noupdate=False, bookmarks=False):
71 def share(ui, source, dest=None, noupdate=False, bookmarks=False):
71 """create a new shared repository
72 """create a new shared repository
72
73
73 Initialize a new repository and working directory that shares its
74 Initialize a new repository and working directory that shares its
74 history (and optionally bookmarks) with another repository.
75 history (and optionally bookmarks) with another repository.
75
76
76 .. note::
77 .. note::
77
78
78 using rollback or extensions that destroy/modify history (mq,
79 using rollback or extensions that destroy/modify history (mq,
79 rebase, etc.) can cause considerable confusion with shared
80 rebase, etc.) can cause considerable confusion with shared
80 clones. In particular, if two shared clones are both updated to
81 clones. In particular, if two shared clones are both updated to
81 the same changeset, and one of them destroys that changeset
82 the same changeset, and one of them destroys that changeset
82 with rollback, the other clone will suddenly stop working: all
83 with rollback, the other clone will suddenly stop working: all
83 operations will fail with "abort: working directory has unknown
84 operations will fail with "abort: working directory has unknown
84 parent". The only known workaround is to use debugsetparents on
85 parent". The only known workaround is to use debugsetparents on
85 the broken clone to reset it to a changeset that still exists.
86 the broken clone to reset it to a changeset that still exists.
86 """
87 """
87
88
88 return hg.share(ui, source, dest=dest, update=not noupdate,
89 return hg.share(ui, source, dest=dest, update=not noupdate,
89 bookmarks=bookmarks)
90 bookmarks=bookmarks)
90
91
91 @command('unshare', [], '')
92 @command('unshare', [], '')
92 def unshare(ui, repo):
93 def unshare(ui, repo):
93 """convert a shared repository to a normal one
94 """convert a shared repository to a normal one
94
95
95 Copy the store data to the repo and remove the sharedpath data.
96 Copy the store data to the repo and remove the sharedpath data.
96 """
97 """
97
98
98 if not repo.shared():
99 if not repo.shared():
99 raise error.Abort(_("this is not a shared repo"))
100 raise error.Abort(_("this is not a shared repo"))
100
101
101 destlock = lock = None
102 destlock = lock = None
102 lock = repo.lock()
103 lock = repo.lock()
103 try:
104 try:
104 # we use locks here because if we race with commit, we
105 # we use locks here because if we race with commit, we
105 # can end up with extra data in the cloned revlogs that's
106 # can end up with extra data in the cloned revlogs that's
106 # not pointed to by changesets, thus causing verify to
107 # not pointed to by changesets, thus causing verify to
107 # fail
108 # fail
108
109
109 destlock = hg.copystore(ui, repo, repo.path)
110 destlock = hg.copystore(ui, repo, repo.path)
110
111
111 sharefile = repo.join('sharedpath')
112 sharefile = repo.join('sharedpath')
112 util.rename(sharefile, sharefile + '.old')
113 util.rename(sharefile, sharefile + '.old')
113
114
114 repo.requirements.discard('sharedpath')
115 repo.requirements.discard('sharedpath')
115 repo._writerequirements()
116 repo._writerequirements()
116 finally:
117 finally:
117 destlock and destlock.release()
118 destlock and destlock.release()
118 lock and lock.release()
119 lock and lock.release()
119
120
120 # update store, spath, svfs and sjoin of repo
121 # update store, spath, svfs and sjoin of repo
121 repo.unfiltered().__init__(repo.baseui, repo.root)
122 repo.unfiltered().__init__(repo.baseui, repo.root)
122
123
123 # Wrap clone command to pass auto share options.
124 # Wrap clone command to pass auto share options.
124 def clone(orig, ui, source, *args, **opts):
125 def clone(orig, ui, source, *args, **opts):
125 pool = ui.config('share', 'pool', None)
126 pool = ui.config('share', 'pool', None)
126 if pool:
127 if pool:
127 pool = util.expandpath(pool)
128 pool = util.expandpath(pool)
128
129
129 opts['shareopts'] = dict(
130 opts['shareopts'] = dict(
130 pool=pool,
131 pool=pool,
131 mode=ui.config('share', 'poolnaming', 'identity'),
132 mode=ui.config('share', 'poolnaming', 'identity'),
132 )
133 )
133
134
134 return orig(ui, source, *args, **opts)
135 return orig(ui, source, *args, **opts)
135
136
136 def extsetup(ui):
137 def extsetup(ui):
137 extensions.wrapfunction(bookmarks, '_getbkfile', getbkfile)
138 extensions.wrapfunction(bookmarks, '_getbkfile', getbkfile)
138 extensions.wrapfunction(bookmarks.bmstore, 'recordchange', recordchange)
139 extensions.wrapfunction(bookmarks.bmstore, 'recordchange', recordchange)
139 extensions.wrapfunction(bookmarks.bmstore, '_writerepo', writerepo)
140 extensions.wrapfunction(bookmarks.bmstore, '_writerepo', writerepo)
140 extensions.wrapcommand(commands.table, 'clone', clone)
141 extensions.wrapcommand(commands.table, 'clone', clone)
141
142
142 def _hassharedbookmarks(repo):
143 def _hassharedbookmarks(repo):
143 """Returns whether this repo has shared bookmarks"""
144 """Returns whether this repo has shared bookmarks"""
144 try:
145 try:
145 shared = repo.vfs.read('shared').splitlines()
146 shared = repo.vfs.read('shared').splitlines()
146 except IOError as inst:
147 except IOError as inst:
147 if inst.errno != errno.ENOENT:
148 if inst.errno != errno.ENOENT:
148 raise
149 raise
149 return False
150 return False
150 return hg.sharedbookmarks in shared
151 return hg.sharedbookmarks in shared
151
152
152 def _getsrcrepo(repo):
153 def _getsrcrepo(repo):
153 """
154 """
154 Returns the source repository object for a given shared repository.
155 Returns the source repository object for a given shared repository.
155 If repo is not a shared repository, return None.
156 If repo is not a shared repository, return None.
156 """
157 """
157 if repo.sharedpath == repo.path:
158 if repo.sharedpath == repo.path:
158 return None
159 return None
159
160
160 if util.safehasattr(repo, 'srcrepo') and repo.srcrepo:
161 if util.safehasattr(repo, 'srcrepo') and repo.srcrepo:
161 return repo.srcrepo
162 return repo.srcrepo
162
163
163 # the sharedpath always ends in the .hg; we want the path to the repo
164 # the sharedpath always ends in the .hg; we want the path to the repo
164 source = repo.vfs.split(repo.sharedpath)[0]
165 source = repo.vfs.split(repo.sharedpath)[0]
165 srcurl, branches = parseurl(source)
166 srcurl, branches = parseurl(source)
166 srcrepo = repository(repo.ui, srcurl)
167 srcrepo = repository(repo.ui, srcurl)
167 repo.srcrepo = srcrepo
168 repo.srcrepo = srcrepo
168 return srcrepo
169 return srcrepo
169
170
170 def getbkfile(orig, repo):
171 def getbkfile(orig, repo):
171 if _hassharedbookmarks(repo):
172 if _hassharedbookmarks(repo):
172 srcrepo = _getsrcrepo(repo)
173 srcrepo = _getsrcrepo(repo)
173 if srcrepo is not None:
174 if srcrepo is not None:
175 # just orig(srcrepo) doesn't work as expected, because
176 # HG_PENDING refers repo.root.
177 try:
178 fp, pending = txnutil.trypending(repo.root, repo.vfs,
179 'bookmarks')
180 if pending:
181 # only in this case, bookmark information in repo
182 # is up-to-date.
183 return fp
184 fp.close()
185 except IOError as inst:
186 if inst.errno != errno.ENOENT:
187 raise
188
189 # otherwise, we should read bookmarks from srcrepo,
190 # because .hg/bookmarks in srcrepo might be already
191 # changed via another sharing repo
174 repo = srcrepo
192 repo = srcrepo
193
194 # TODO: Pending changes in repo are still invisible in
195 # srcrepo, because bookmarks.pending is written only into repo.
196 # See also https://www.mercurial-scm.org/wiki/SharedRepository
175 return orig(repo)
197 return orig(repo)
176
198
177 def recordchange(orig, self, tr):
199 def recordchange(orig, self, tr):
178 # Continue with write to local bookmarks file as usual
200 # Continue with write to local bookmarks file as usual
179 orig(self, tr)
201 orig(self, tr)
180
202
181 if _hassharedbookmarks(self._repo):
203 if _hassharedbookmarks(self._repo):
182 srcrepo = _getsrcrepo(self._repo)
204 srcrepo = _getsrcrepo(self._repo)
183 if srcrepo is not None:
205 if srcrepo is not None:
184 category = 'share-bookmarks'
206 category = 'share-bookmarks'
185 tr.addpostclose(category, lambda tr: self._writerepo(srcrepo))
207 tr.addpostclose(category, lambda tr: self._writerepo(srcrepo))
186
208
187 def writerepo(orig, self, repo):
209 def writerepo(orig, self, repo):
188 # First write local bookmarks file in case we ever unshare
210 # First write local bookmarks file in case we ever unshare
189 orig(self, repo)
211 orig(self, repo)
190
212
191 if _hassharedbookmarks(self._repo):
213 if _hassharedbookmarks(self._repo):
192 srcrepo = _getsrcrepo(self._repo)
214 srcrepo = _getsrcrepo(self._repo)
193 if srcrepo is not None:
215 if srcrepo is not None:
194 orig(self, srcrepo)
216 orig(self, srcrepo)
@@ -1,607 +1,599 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 __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11
11
12 from .i18n import _
12 from .i18n import _
13 from .node import (
13 from .node import (
14 bin,
14 bin,
15 hex,
15 hex,
16 )
16 )
17 from . import (
17 from . import (
18 encoding,
18 encoding,
19 error,
19 error,
20 lock as lockmod,
20 lock as lockmod,
21 obsolete,
21 obsolete,
22 txnutil,
22 util,
23 util,
23 )
24 )
24
25
25 def _getbkfile(repo):
26 def _getbkfile(repo):
26 """Hook so that extensions that mess with the store can hook bm storage.
27 """Hook so that extensions that mess with the store can hook bm storage.
27
28
28 For core, this just handles wether we should see pending
29 For core, this just handles wether we should see pending
29 bookmarks or the committed ones. Other extensions (like share)
30 bookmarks or the committed ones. Other extensions (like share)
30 may need to tweak this behavior further.
31 may need to tweak this behavior further.
31 """
32 """
32 bkfile = None
33 fp, pending = txnutil.trypending(repo.root, repo.vfs, 'bookmarks')
33 if 'HG_PENDING' in encoding.environ:
34 return fp
34 try:
35 bkfile = repo.vfs('bookmarks.pending')
36 except IOError as inst:
37 if inst.errno != errno.ENOENT:
38 raise
39 if bkfile is None:
40 bkfile = repo.vfs('bookmarks')
41 return bkfile
42
43
35
44 class bmstore(dict):
36 class bmstore(dict):
45 """Storage for bookmarks.
37 """Storage for bookmarks.
46
38
47 This object should do all bookmark-related reads and writes, so
39 This object should do all bookmark-related reads and writes, so
48 that it's fairly simple to replace the storage underlying
40 that it's fairly simple to replace the storage underlying
49 bookmarks without having to clone the logic surrounding
41 bookmarks without having to clone the logic surrounding
50 bookmarks. This type also should manage the active bookmark, if
42 bookmarks. This type also should manage the active bookmark, if
51 any.
43 any.
52
44
53 This particular bmstore implementation stores bookmarks as
45 This particular bmstore implementation stores bookmarks as
54 {hash}\s{name}\n (the same format as localtags) in
46 {hash}\s{name}\n (the same format as localtags) in
55 .hg/bookmarks. The mapping is stored as {name: nodeid}.
47 .hg/bookmarks. The mapping is stored as {name: nodeid}.
56 """
48 """
57
49
58 def __init__(self, repo):
50 def __init__(self, repo):
59 dict.__init__(self)
51 dict.__init__(self)
60 self._repo = repo
52 self._repo = repo
61 try:
53 try:
62 bkfile = _getbkfile(repo)
54 bkfile = _getbkfile(repo)
63 for line in bkfile:
55 for line in bkfile:
64 line = line.strip()
56 line = line.strip()
65 if not line:
57 if not line:
66 continue
58 continue
67 if ' ' not in line:
59 if ' ' not in line:
68 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n')
60 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n')
69 % line)
61 % line)
70 continue
62 continue
71 sha, refspec = line.split(' ', 1)
63 sha, refspec = line.split(' ', 1)
72 refspec = encoding.tolocal(refspec)
64 refspec = encoding.tolocal(refspec)
73 try:
65 try:
74 self[refspec] = repo.changelog.lookup(sha)
66 self[refspec] = repo.changelog.lookup(sha)
75 except LookupError:
67 except LookupError:
76 pass
68 pass
77 except IOError as inst:
69 except IOError as inst:
78 if inst.errno != errno.ENOENT:
70 if inst.errno != errno.ENOENT:
79 raise
71 raise
80 self._clean = True
72 self._clean = True
81 self._active = _readactive(repo, self)
73 self._active = _readactive(repo, self)
82 self._aclean = True
74 self._aclean = True
83
75
84 @property
76 @property
85 def active(self):
77 def active(self):
86 return self._active
78 return self._active
87
79
88 @active.setter
80 @active.setter
89 def active(self, mark):
81 def active(self, mark):
90 if mark is not None and mark not in self:
82 if mark is not None and mark not in self:
91 raise AssertionError('bookmark %s does not exist!' % mark)
83 raise AssertionError('bookmark %s does not exist!' % mark)
92
84
93 self._active = mark
85 self._active = mark
94 self._aclean = False
86 self._aclean = False
95
87
96 def __setitem__(self, *args, **kwargs):
88 def __setitem__(self, *args, **kwargs):
97 self._clean = False
89 self._clean = False
98 return dict.__setitem__(self, *args, **kwargs)
90 return dict.__setitem__(self, *args, **kwargs)
99
91
100 def __delitem__(self, key):
92 def __delitem__(self, key):
101 self._clean = False
93 self._clean = False
102 return dict.__delitem__(self, key)
94 return dict.__delitem__(self, key)
103
95
104 def recordchange(self, tr):
96 def recordchange(self, tr):
105 """record that bookmarks have been changed in a transaction
97 """record that bookmarks have been changed in a transaction
106
98
107 The transaction is then responsible for updating the file content."""
99 The transaction is then responsible for updating the file content."""
108 tr.addfilegenerator('bookmarks', ('bookmarks',), self._write,
100 tr.addfilegenerator('bookmarks', ('bookmarks',), self._write,
109 location='plain')
101 location='plain')
110 tr.hookargs['bookmark_moved'] = '1'
102 tr.hookargs['bookmark_moved'] = '1'
111
103
112 def _writerepo(self, repo):
104 def _writerepo(self, repo):
113 """Factored out for extensibility"""
105 """Factored out for extensibility"""
114 rbm = repo._bookmarks
106 rbm = repo._bookmarks
115 if rbm.active not in self:
107 if rbm.active not in self:
116 rbm.active = None
108 rbm.active = None
117 rbm._writeactive()
109 rbm._writeactive()
118
110
119 with repo.wlock():
111 with repo.wlock():
120 file_ = repo.vfs('bookmarks', 'w', atomictemp=True,
112 file_ = repo.vfs('bookmarks', 'w', atomictemp=True,
121 checkambig=True)
113 checkambig=True)
122 try:
114 try:
123 self._write(file_)
115 self._write(file_)
124 except: # re-raises
116 except: # re-raises
125 file_.discard()
117 file_.discard()
126 raise
118 raise
127 finally:
119 finally:
128 file_.close()
120 file_.close()
129
121
130 def _writeactive(self):
122 def _writeactive(self):
131 if self._aclean:
123 if self._aclean:
132 return
124 return
133 with self._repo.wlock():
125 with self._repo.wlock():
134 if self._active is not None:
126 if self._active is not None:
135 f = self._repo.vfs('bookmarks.current', 'w', atomictemp=True,
127 f = self._repo.vfs('bookmarks.current', 'w', atomictemp=True,
136 checkambig=True)
128 checkambig=True)
137 try:
129 try:
138 f.write(encoding.fromlocal(self._active))
130 f.write(encoding.fromlocal(self._active))
139 finally:
131 finally:
140 f.close()
132 f.close()
141 else:
133 else:
142 try:
134 try:
143 self._repo.vfs.unlink('bookmarks.current')
135 self._repo.vfs.unlink('bookmarks.current')
144 except OSError as inst:
136 except OSError as inst:
145 if inst.errno != errno.ENOENT:
137 if inst.errno != errno.ENOENT:
146 raise
138 raise
147 self._aclean = True
139 self._aclean = True
148
140
149 def _write(self, fp):
141 def _write(self, fp):
150 for name, node in self.iteritems():
142 for name, node in self.iteritems():
151 fp.write("%s %s\n" % (hex(node), encoding.fromlocal(name)))
143 fp.write("%s %s\n" % (hex(node), encoding.fromlocal(name)))
152 self._clean = True
144 self._clean = True
153 self._repo.invalidatevolatilesets()
145 self._repo.invalidatevolatilesets()
154
146
155 def expandname(self, bname):
147 def expandname(self, bname):
156 if bname == '.':
148 if bname == '.':
157 if self.active:
149 if self.active:
158 return self.active
150 return self.active
159 else:
151 else:
160 raise error.Abort(_("no active bookmark"))
152 raise error.Abort(_("no active bookmark"))
161 return bname
153 return bname
162
154
163 def _readactive(repo, marks):
155 def _readactive(repo, marks):
164 """
156 """
165 Get the active bookmark. We can have an active bookmark that updates
157 Get the active bookmark. We can have an active bookmark that updates
166 itself as we commit. This function returns the name of that bookmark.
158 itself as we commit. This function returns the name of that bookmark.
167 It is stored in .hg/bookmarks.current
159 It is stored in .hg/bookmarks.current
168 """
160 """
169 mark = None
161 mark = None
170 try:
162 try:
171 file = repo.vfs('bookmarks.current')
163 file = repo.vfs('bookmarks.current')
172 except IOError as inst:
164 except IOError as inst:
173 if inst.errno != errno.ENOENT:
165 if inst.errno != errno.ENOENT:
174 raise
166 raise
175 return None
167 return None
176 try:
168 try:
177 # No readline() in osutil.posixfile, reading everything is
169 # No readline() in osutil.posixfile, reading everything is
178 # cheap.
170 # cheap.
179 # Note that it's possible for readlines() here to raise
171 # Note that it's possible for readlines() here to raise
180 # IOError, since we might be reading the active mark over
172 # IOError, since we might be reading the active mark over
181 # static-http which only tries to load the file when we try
173 # static-http which only tries to load the file when we try
182 # to read from it.
174 # to read from it.
183 mark = encoding.tolocal((file.readlines() or [''])[0])
175 mark = encoding.tolocal((file.readlines() or [''])[0])
184 if mark == '' or mark not in marks:
176 if mark == '' or mark not in marks:
185 mark = None
177 mark = None
186 except IOError as inst:
178 except IOError as inst:
187 if inst.errno != errno.ENOENT:
179 if inst.errno != errno.ENOENT:
188 raise
180 raise
189 return None
181 return None
190 finally:
182 finally:
191 file.close()
183 file.close()
192 return mark
184 return mark
193
185
194 def activate(repo, mark):
186 def activate(repo, mark):
195 """
187 """
196 Set the given bookmark to be 'active', meaning that this bookmark will
188 Set the given bookmark to be 'active', meaning that this bookmark will
197 follow new commits that are made.
189 follow new commits that are made.
198 The name is recorded in .hg/bookmarks.current
190 The name is recorded in .hg/bookmarks.current
199 """
191 """
200 repo._bookmarks.active = mark
192 repo._bookmarks.active = mark
201 repo._bookmarks._writeactive()
193 repo._bookmarks._writeactive()
202
194
203 def deactivate(repo):
195 def deactivate(repo):
204 """
196 """
205 Unset the active bookmark in this repository.
197 Unset the active bookmark in this repository.
206 """
198 """
207 repo._bookmarks.active = None
199 repo._bookmarks.active = None
208 repo._bookmarks._writeactive()
200 repo._bookmarks._writeactive()
209
201
210 def isactivewdirparent(repo):
202 def isactivewdirparent(repo):
211 """
203 """
212 Tell whether the 'active' bookmark (the one that follows new commits)
204 Tell whether the 'active' bookmark (the one that follows new commits)
213 points to one of the parents of the current working directory (wdir).
205 points to one of the parents of the current working directory (wdir).
214
206
215 While this is normally the case, it can on occasion be false; for example,
207 While this is normally the case, it can on occasion be false; for example,
216 immediately after a pull, the active bookmark can be moved to point
208 immediately after a pull, the active bookmark can be moved to point
217 to a place different than the wdir. This is solved by running `hg update`.
209 to a place different than the wdir. This is solved by running `hg update`.
218 """
210 """
219 mark = repo._activebookmark
211 mark = repo._activebookmark
220 marks = repo._bookmarks
212 marks = repo._bookmarks
221 parents = [p.node() for p in repo[None].parents()]
213 parents = [p.node() for p in repo[None].parents()]
222 return (mark in marks and marks[mark] in parents)
214 return (mark in marks and marks[mark] in parents)
223
215
224 def deletedivergent(repo, deletefrom, bm):
216 def deletedivergent(repo, deletefrom, bm):
225 '''Delete divergent versions of bm on nodes in deletefrom.
217 '''Delete divergent versions of bm on nodes in deletefrom.
226
218
227 Return True if at least one bookmark was deleted, False otherwise.'''
219 Return True if at least one bookmark was deleted, False otherwise.'''
228 deleted = False
220 deleted = False
229 marks = repo._bookmarks
221 marks = repo._bookmarks
230 divergent = [b for b in marks if b.split('@', 1)[0] == bm.split('@', 1)[0]]
222 divergent = [b for b in marks if b.split('@', 1)[0] == bm.split('@', 1)[0]]
231 for mark in divergent:
223 for mark in divergent:
232 if mark == '@' or '@' not in mark:
224 if mark == '@' or '@' not in mark:
233 # can't be divergent by definition
225 # can't be divergent by definition
234 continue
226 continue
235 if mark and marks[mark] in deletefrom:
227 if mark and marks[mark] in deletefrom:
236 if mark != bm:
228 if mark != bm:
237 del marks[mark]
229 del marks[mark]
238 deleted = True
230 deleted = True
239 return deleted
231 return deleted
240
232
241 def calculateupdate(ui, repo, checkout):
233 def calculateupdate(ui, repo, checkout):
242 '''Return a tuple (targetrev, movemarkfrom) indicating the rev to
234 '''Return a tuple (targetrev, movemarkfrom) indicating the rev to
243 check out and where to move the active bookmark from, if needed.'''
235 check out and where to move the active bookmark from, if needed.'''
244 movemarkfrom = None
236 movemarkfrom = None
245 if checkout is None:
237 if checkout is None:
246 activemark = repo._activebookmark
238 activemark = repo._activebookmark
247 if isactivewdirparent(repo):
239 if isactivewdirparent(repo):
248 movemarkfrom = repo['.'].node()
240 movemarkfrom = repo['.'].node()
249 elif activemark:
241 elif activemark:
250 ui.status(_("updating to active bookmark %s\n") % activemark)
242 ui.status(_("updating to active bookmark %s\n") % activemark)
251 checkout = activemark
243 checkout = activemark
252 return (checkout, movemarkfrom)
244 return (checkout, movemarkfrom)
253
245
254 def update(repo, parents, node):
246 def update(repo, parents, node):
255 deletefrom = parents
247 deletefrom = parents
256 marks = repo._bookmarks
248 marks = repo._bookmarks
257 update = False
249 update = False
258 active = marks.active
250 active = marks.active
259 if not active:
251 if not active:
260 return False
252 return False
261
253
262 if marks[active] in parents:
254 if marks[active] in parents:
263 new = repo[node]
255 new = repo[node]
264 divs = [repo[b] for b in marks
256 divs = [repo[b] for b in marks
265 if b.split('@', 1)[0] == active.split('@', 1)[0]]
257 if b.split('@', 1)[0] == active.split('@', 1)[0]]
266 anc = repo.changelog.ancestors([new.rev()])
258 anc = repo.changelog.ancestors([new.rev()])
267 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
259 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
268 if validdest(repo, repo[marks[active]], new):
260 if validdest(repo, repo[marks[active]], new):
269 marks[active] = new.node()
261 marks[active] = new.node()
270 update = True
262 update = True
271
263
272 if deletedivergent(repo, deletefrom, active):
264 if deletedivergent(repo, deletefrom, active):
273 update = True
265 update = True
274
266
275 if update:
267 if update:
276 lock = tr = None
268 lock = tr = None
277 try:
269 try:
278 lock = repo.lock()
270 lock = repo.lock()
279 tr = repo.transaction('bookmark')
271 tr = repo.transaction('bookmark')
280 marks.recordchange(tr)
272 marks.recordchange(tr)
281 tr.close()
273 tr.close()
282 finally:
274 finally:
283 lockmod.release(tr, lock)
275 lockmod.release(tr, lock)
284 return update
276 return update
285
277
286 def listbinbookmarks(repo):
278 def listbinbookmarks(repo):
287 # We may try to list bookmarks on a repo type that does not
279 # We may try to list bookmarks on a repo type that does not
288 # support it (e.g., statichttprepository).
280 # support it (e.g., statichttprepository).
289 marks = getattr(repo, '_bookmarks', {})
281 marks = getattr(repo, '_bookmarks', {})
290
282
291 hasnode = repo.changelog.hasnode
283 hasnode = repo.changelog.hasnode
292 for k, v in marks.iteritems():
284 for k, v in marks.iteritems():
293 # don't expose local divergent bookmarks
285 # don't expose local divergent bookmarks
294 if hasnode(v) and ('@' not in k or k.endswith('@')):
286 if hasnode(v) and ('@' not in k or k.endswith('@')):
295 yield k, v
287 yield k, v
296
288
297 def listbookmarks(repo):
289 def listbookmarks(repo):
298 d = {}
290 d = {}
299 for book, node in listbinbookmarks(repo):
291 for book, node in listbinbookmarks(repo):
300 d[book] = hex(node)
292 d[book] = hex(node)
301 return d
293 return d
302
294
303 def pushbookmark(repo, key, old, new):
295 def pushbookmark(repo, key, old, new):
304 w = l = tr = None
296 w = l = tr = None
305 try:
297 try:
306 w = repo.wlock()
298 w = repo.wlock()
307 l = repo.lock()
299 l = repo.lock()
308 tr = repo.transaction('bookmarks')
300 tr = repo.transaction('bookmarks')
309 marks = repo._bookmarks
301 marks = repo._bookmarks
310 existing = hex(marks.get(key, ''))
302 existing = hex(marks.get(key, ''))
311 if existing != old and existing != new:
303 if existing != old and existing != new:
312 return False
304 return False
313 if new == '':
305 if new == '':
314 del marks[key]
306 del marks[key]
315 else:
307 else:
316 if new not in repo:
308 if new not in repo:
317 return False
309 return False
318 marks[key] = repo[new].node()
310 marks[key] = repo[new].node()
319 marks.recordchange(tr)
311 marks.recordchange(tr)
320 tr.close()
312 tr.close()
321 return True
313 return True
322 finally:
314 finally:
323 lockmod.release(tr, l, w)
315 lockmod.release(tr, l, w)
324
316
325 def comparebookmarks(repo, srcmarks, dstmarks, targets=None):
317 def comparebookmarks(repo, srcmarks, dstmarks, targets=None):
326 '''Compare bookmarks between srcmarks and dstmarks
318 '''Compare bookmarks between srcmarks and dstmarks
327
319
328 This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
320 This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
329 differ, invalid)", each are list of bookmarks below:
321 differ, invalid)", each are list of bookmarks below:
330
322
331 :addsrc: added on src side (removed on dst side, perhaps)
323 :addsrc: added on src side (removed on dst side, perhaps)
332 :adddst: added on dst side (removed on src side, perhaps)
324 :adddst: added on dst side (removed on src side, perhaps)
333 :advsrc: advanced on src side
325 :advsrc: advanced on src side
334 :advdst: advanced on dst side
326 :advdst: advanced on dst side
335 :diverge: diverge
327 :diverge: diverge
336 :differ: changed, but changeset referred on src is unknown on dst
328 :differ: changed, but changeset referred on src is unknown on dst
337 :invalid: unknown on both side
329 :invalid: unknown on both side
338 :same: same on both side
330 :same: same on both side
339
331
340 Each elements of lists in result tuple is tuple "(bookmark name,
332 Each elements of lists in result tuple is tuple "(bookmark name,
341 changeset ID on source side, changeset ID on destination
333 changeset ID on source side, changeset ID on destination
342 side)". Each changeset IDs are 40 hexadecimal digit string or
334 side)". Each changeset IDs are 40 hexadecimal digit string or
343 None.
335 None.
344
336
345 Changeset IDs of tuples in "addsrc", "adddst", "differ" or
337 Changeset IDs of tuples in "addsrc", "adddst", "differ" or
346 "invalid" list may be unknown for repo.
338 "invalid" list may be unknown for repo.
347
339
348 If "targets" is specified, only bookmarks listed in it are
340 If "targets" is specified, only bookmarks listed in it are
349 examined.
341 examined.
350 '''
342 '''
351
343
352 if targets:
344 if targets:
353 bset = set(targets)
345 bset = set(targets)
354 else:
346 else:
355 srcmarkset = set(srcmarks)
347 srcmarkset = set(srcmarks)
356 dstmarkset = set(dstmarks)
348 dstmarkset = set(dstmarks)
357 bset = srcmarkset | dstmarkset
349 bset = srcmarkset | dstmarkset
358
350
359 results = ([], [], [], [], [], [], [], [])
351 results = ([], [], [], [], [], [], [], [])
360 addsrc = results[0].append
352 addsrc = results[0].append
361 adddst = results[1].append
353 adddst = results[1].append
362 advsrc = results[2].append
354 advsrc = results[2].append
363 advdst = results[3].append
355 advdst = results[3].append
364 diverge = results[4].append
356 diverge = results[4].append
365 differ = results[5].append
357 differ = results[5].append
366 invalid = results[6].append
358 invalid = results[6].append
367 same = results[7].append
359 same = results[7].append
368
360
369 for b in sorted(bset):
361 for b in sorted(bset):
370 if b not in srcmarks:
362 if b not in srcmarks:
371 if b in dstmarks:
363 if b in dstmarks:
372 adddst((b, None, dstmarks[b]))
364 adddst((b, None, dstmarks[b]))
373 else:
365 else:
374 invalid((b, None, None))
366 invalid((b, None, None))
375 elif b not in dstmarks:
367 elif b not in dstmarks:
376 addsrc((b, srcmarks[b], None))
368 addsrc((b, srcmarks[b], None))
377 else:
369 else:
378 scid = srcmarks[b]
370 scid = srcmarks[b]
379 dcid = dstmarks[b]
371 dcid = dstmarks[b]
380 if scid == dcid:
372 if scid == dcid:
381 same((b, scid, dcid))
373 same((b, scid, dcid))
382 elif scid in repo and dcid in repo:
374 elif scid in repo and dcid in repo:
383 sctx = repo[scid]
375 sctx = repo[scid]
384 dctx = repo[dcid]
376 dctx = repo[dcid]
385 if sctx.rev() < dctx.rev():
377 if sctx.rev() < dctx.rev():
386 if validdest(repo, sctx, dctx):
378 if validdest(repo, sctx, dctx):
387 advdst((b, scid, dcid))
379 advdst((b, scid, dcid))
388 else:
380 else:
389 diverge((b, scid, dcid))
381 diverge((b, scid, dcid))
390 else:
382 else:
391 if validdest(repo, dctx, sctx):
383 if validdest(repo, dctx, sctx):
392 advsrc((b, scid, dcid))
384 advsrc((b, scid, dcid))
393 else:
385 else:
394 diverge((b, scid, dcid))
386 diverge((b, scid, dcid))
395 else:
387 else:
396 # it is too expensive to examine in detail, in this case
388 # it is too expensive to examine in detail, in this case
397 differ((b, scid, dcid))
389 differ((b, scid, dcid))
398
390
399 return results
391 return results
400
392
401 def _diverge(ui, b, path, localmarks, remotenode):
393 def _diverge(ui, b, path, localmarks, remotenode):
402 '''Return appropriate diverged bookmark for specified ``path``
394 '''Return appropriate diverged bookmark for specified ``path``
403
395
404 This returns None, if it is failed to assign any divergent
396 This returns None, if it is failed to assign any divergent
405 bookmark name.
397 bookmark name.
406
398
407 This reuses already existing one with "@number" suffix, if it
399 This reuses already existing one with "@number" suffix, if it
408 refers ``remotenode``.
400 refers ``remotenode``.
409 '''
401 '''
410 if b == '@':
402 if b == '@':
411 b = ''
403 b = ''
412 # try to use an @pathalias suffix
404 # try to use an @pathalias suffix
413 # if an @pathalias already exists, we overwrite (update) it
405 # if an @pathalias already exists, we overwrite (update) it
414 if path.startswith("file:"):
406 if path.startswith("file:"):
415 path = util.url(path).path
407 path = util.url(path).path
416 for p, u in ui.configitems("paths"):
408 for p, u in ui.configitems("paths"):
417 if u.startswith("file:"):
409 if u.startswith("file:"):
418 u = util.url(u).path
410 u = util.url(u).path
419 if path == u:
411 if path == u:
420 return '%s@%s' % (b, p)
412 return '%s@%s' % (b, p)
421
413
422 # assign a unique "@number" suffix newly
414 # assign a unique "@number" suffix newly
423 for x in range(1, 100):
415 for x in range(1, 100):
424 n = '%s@%d' % (b, x)
416 n = '%s@%d' % (b, x)
425 if n not in localmarks or localmarks[n] == remotenode:
417 if n not in localmarks or localmarks[n] == remotenode:
426 return n
418 return n
427
419
428 return None
420 return None
429
421
430 def unhexlifybookmarks(marks):
422 def unhexlifybookmarks(marks):
431 binremotemarks = {}
423 binremotemarks = {}
432 for name, node in marks.items():
424 for name, node in marks.items():
433 binremotemarks[name] = bin(node)
425 binremotemarks[name] = bin(node)
434 return binremotemarks
426 return binremotemarks
435
427
436 def updatefromremote(ui, repo, remotemarks, path, trfunc, explicit=()):
428 def updatefromremote(ui, repo, remotemarks, path, trfunc, explicit=()):
437 ui.debug("checking for updated bookmarks\n")
429 ui.debug("checking for updated bookmarks\n")
438 localmarks = repo._bookmarks
430 localmarks = repo._bookmarks
439 (addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same
431 (addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same
440 ) = comparebookmarks(repo, remotemarks, localmarks)
432 ) = comparebookmarks(repo, remotemarks, localmarks)
441
433
442 status = ui.status
434 status = ui.status
443 warn = ui.warn
435 warn = ui.warn
444 if ui.configbool('ui', 'quietbookmarkmove', False):
436 if ui.configbool('ui', 'quietbookmarkmove', False):
445 status = warn = ui.debug
437 status = warn = ui.debug
446
438
447 explicit = set(explicit)
439 explicit = set(explicit)
448 changed = []
440 changed = []
449 for b, scid, dcid in addsrc:
441 for b, scid, dcid in addsrc:
450 if scid in repo: # add remote bookmarks for changes we already have
442 if scid in repo: # add remote bookmarks for changes we already have
451 changed.append((b, scid, status,
443 changed.append((b, scid, status,
452 _("adding remote bookmark %s\n") % (b)))
444 _("adding remote bookmark %s\n") % (b)))
453 elif b in explicit:
445 elif b in explicit:
454 explicit.remove(b)
446 explicit.remove(b)
455 ui.warn(_("remote bookmark %s points to locally missing %s\n")
447 ui.warn(_("remote bookmark %s points to locally missing %s\n")
456 % (b, hex(scid)[:12]))
448 % (b, hex(scid)[:12]))
457
449
458 for b, scid, dcid in advsrc:
450 for b, scid, dcid in advsrc:
459 changed.append((b, scid, status,
451 changed.append((b, scid, status,
460 _("updating bookmark %s\n") % (b)))
452 _("updating bookmark %s\n") % (b)))
461 # remove normal movement from explicit set
453 # remove normal movement from explicit set
462 explicit.difference_update(d[0] for d in changed)
454 explicit.difference_update(d[0] for d in changed)
463
455
464 for b, scid, dcid in diverge:
456 for b, scid, dcid in diverge:
465 if b in explicit:
457 if b in explicit:
466 explicit.discard(b)
458 explicit.discard(b)
467 changed.append((b, scid, status,
459 changed.append((b, scid, status,
468 _("importing bookmark %s\n") % (b)))
460 _("importing bookmark %s\n") % (b)))
469 else:
461 else:
470 db = _diverge(ui, b, path, localmarks, scid)
462 db = _diverge(ui, b, path, localmarks, scid)
471 if db:
463 if db:
472 changed.append((db, scid, warn,
464 changed.append((db, scid, warn,
473 _("divergent bookmark %s stored as %s\n") %
465 _("divergent bookmark %s stored as %s\n") %
474 (b, db)))
466 (b, db)))
475 else:
467 else:
476 warn(_("warning: failed to assign numbered name "
468 warn(_("warning: failed to assign numbered name "
477 "to divergent bookmark %s\n") % (b))
469 "to divergent bookmark %s\n") % (b))
478 for b, scid, dcid in adddst + advdst:
470 for b, scid, dcid in adddst + advdst:
479 if b in explicit:
471 if b in explicit:
480 explicit.discard(b)
472 explicit.discard(b)
481 changed.append((b, scid, status,
473 changed.append((b, scid, status,
482 _("importing bookmark %s\n") % (b)))
474 _("importing bookmark %s\n") % (b)))
483 for b, scid, dcid in differ:
475 for b, scid, dcid in differ:
484 if b in explicit:
476 if b in explicit:
485 explicit.remove(b)
477 explicit.remove(b)
486 ui.warn(_("remote bookmark %s points to locally missing %s\n")
478 ui.warn(_("remote bookmark %s points to locally missing %s\n")
487 % (b, hex(scid)[:12]))
479 % (b, hex(scid)[:12]))
488
480
489 if changed:
481 if changed:
490 tr = trfunc()
482 tr = trfunc()
491 for b, node, writer, msg in sorted(changed):
483 for b, node, writer, msg in sorted(changed):
492 localmarks[b] = node
484 localmarks[b] = node
493 writer(msg)
485 writer(msg)
494 localmarks.recordchange(tr)
486 localmarks.recordchange(tr)
495
487
496 def incoming(ui, repo, other):
488 def incoming(ui, repo, other):
497 '''Show bookmarks incoming from other to repo
489 '''Show bookmarks incoming from other to repo
498 '''
490 '''
499 ui.status(_("searching for changed bookmarks\n"))
491 ui.status(_("searching for changed bookmarks\n"))
500
492
501 remotemarks = unhexlifybookmarks(other.listkeys('bookmarks'))
493 remotemarks = unhexlifybookmarks(other.listkeys('bookmarks'))
502 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
494 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
503 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
495 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
504
496
505 incomings = []
497 incomings = []
506 if ui.debugflag:
498 if ui.debugflag:
507 getid = lambda id: id
499 getid = lambda id: id
508 else:
500 else:
509 getid = lambda id: id[:12]
501 getid = lambda id: id[:12]
510 if ui.verbose:
502 if ui.verbose:
511 def add(b, id, st):
503 def add(b, id, st):
512 incomings.append(" %-25s %s %s\n" % (b, getid(id), st))
504 incomings.append(" %-25s %s %s\n" % (b, getid(id), st))
513 else:
505 else:
514 def add(b, id, st):
506 def add(b, id, st):
515 incomings.append(" %-25s %s\n" % (b, getid(id)))
507 incomings.append(" %-25s %s\n" % (b, getid(id)))
516 for b, scid, dcid in addsrc:
508 for b, scid, dcid in addsrc:
517 # i18n: "added" refers to a bookmark
509 # i18n: "added" refers to a bookmark
518 add(b, hex(scid), _('added'))
510 add(b, hex(scid), _('added'))
519 for b, scid, dcid in advsrc:
511 for b, scid, dcid in advsrc:
520 # i18n: "advanced" refers to a bookmark
512 # i18n: "advanced" refers to a bookmark
521 add(b, hex(scid), _('advanced'))
513 add(b, hex(scid), _('advanced'))
522 for b, scid, dcid in diverge:
514 for b, scid, dcid in diverge:
523 # i18n: "diverged" refers to a bookmark
515 # i18n: "diverged" refers to a bookmark
524 add(b, hex(scid), _('diverged'))
516 add(b, hex(scid), _('diverged'))
525 for b, scid, dcid in differ:
517 for b, scid, dcid in differ:
526 # i18n: "changed" refers to a bookmark
518 # i18n: "changed" refers to a bookmark
527 add(b, hex(scid), _('changed'))
519 add(b, hex(scid), _('changed'))
528
520
529 if not incomings:
521 if not incomings:
530 ui.status(_("no changed bookmarks found\n"))
522 ui.status(_("no changed bookmarks found\n"))
531 return 1
523 return 1
532
524
533 for s in sorted(incomings):
525 for s in sorted(incomings):
534 ui.write(s)
526 ui.write(s)
535
527
536 return 0
528 return 0
537
529
538 def outgoing(ui, repo, other):
530 def outgoing(ui, repo, other):
539 '''Show bookmarks outgoing from repo to other
531 '''Show bookmarks outgoing from repo to other
540 '''
532 '''
541 ui.status(_("searching for changed bookmarks\n"))
533 ui.status(_("searching for changed bookmarks\n"))
542
534
543 remotemarks = unhexlifybookmarks(other.listkeys('bookmarks'))
535 remotemarks = unhexlifybookmarks(other.listkeys('bookmarks'))
544 r = comparebookmarks(repo, repo._bookmarks, remotemarks)
536 r = comparebookmarks(repo, repo._bookmarks, remotemarks)
545 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
537 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
546
538
547 outgoings = []
539 outgoings = []
548 if ui.debugflag:
540 if ui.debugflag:
549 getid = lambda id: id
541 getid = lambda id: id
550 else:
542 else:
551 getid = lambda id: id[:12]
543 getid = lambda id: id[:12]
552 if ui.verbose:
544 if ui.verbose:
553 def add(b, id, st):
545 def add(b, id, st):
554 outgoings.append(" %-25s %s %s\n" % (b, getid(id), st))
546 outgoings.append(" %-25s %s %s\n" % (b, getid(id), st))
555 else:
547 else:
556 def add(b, id, st):
548 def add(b, id, st):
557 outgoings.append(" %-25s %s\n" % (b, getid(id)))
549 outgoings.append(" %-25s %s\n" % (b, getid(id)))
558 for b, scid, dcid in addsrc:
550 for b, scid, dcid in addsrc:
559 # i18n: "added refers to a bookmark
551 # i18n: "added refers to a bookmark
560 add(b, hex(scid), _('added'))
552 add(b, hex(scid), _('added'))
561 for b, scid, dcid in adddst:
553 for b, scid, dcid in adddst:
562 # i18n: "deleted" refers to a bookmark
554 # i18n: "deleted" refers to a bookmark
563 add(b, ' ' * 40, _('deleted'))
555 add(b, ' ' * 40, _('deleted'))
564 for b, scid, dcid in advsrc:
556 for b, scid, dcid in advsrc:
565 # i18n: "advanced" refers to a bookmark
557 # i18n: "advanced" refers to a bookmark
566 add(b, hex(scid), _('advanced'))
558 add(b, hex(scid), _('advanced'))
567 for b, scid, dcid in diverge:
559 for b, scid, dcid in diverge:
568 # i18n: "diverged" refers to a bookmark
560 # i18n: "diverged" refers to a bookmark
569 add(b, hex(scid), _('diverged'))
561 add(b, hex(scid), _('diverged'))
570 for b, scid, dcid in differ:
562 for b, scid, dcid in differ:
571 # i18n: "changed" refers to a bookmark
563 # i18n: "changed" refers to a bookmark
572 add(b, hex(scid), _('changed'))
564 add(b, hex(scid), _('changed'))
573
565
574 if not outgoings:
566 if not outgoings:
575 ui.status(_("no changed bookmarks found\n"))
567 ui.status(_("no changed bookmarks found\n"))
576 return 1
568 return 1
577
569
578 for s in sorted(outgoings):
570 for s in sorted(outgoings):
579 ui.write(s)
571 ui.write(s)
580
572
581 return 0
573 return 0
582
574
583 def summary(repo, other):
575 def summary(repo, other):
584 '''Compare bookmarks between repo and other for "hg summary" output
576 '''Compare bookmarks between repo and other for "hg summary" output
585
577
586 This returns "(# of incoming, # of outgoing)" tuple.
578 This returns "(# of incoming, # of outgoing)" tuple.
587 '''
579 '''
588 remotemarks = unhexlifybookmarks(other.listkeys('bookmarks'))
580 remotemarks = unhexlifybookmarks(other.listkeys('bookmarks'))
589 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
581 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
590 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
582 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
591 return (len(addsrc), len(adddst))
583 return (len(addsrc), len(adddst))
592
584
593 def validdest(repo, old, new):
585 def validdest(repo, old, new):
594 """Is the new bookmark destination a valid update from the old one"""
586 """Is the new bookmark destination a valid update from the old one"""
595 repo = repo.unfiltered()
587 repo = repo.unfiltered()
596 if old == new:
588 if old == new:
597 # Old == new -> nothing to update.
589 # Old == new -> nothing to update.
598 return False
590 return False
599 elif not old:
591 elif not old:
600 # old is nullrev, anything is valid.
592 # old is nullrev, anything is valid.
601 # (new != nullrev has been excluded by the previous check)
593 # (new != nullrev has been excluded by the previous check)
602 return True
594 return True
603 elif repo.obsstore:
595 elif repo.obsstore:
604 return new.node() in obsolete.foreground(repo, [old.node()])
596 return new.node() in obsolete.foreground(repo, [old.node()])
605 else:
597 else:
606 # still an independent clause as it is lazier (and therefore faster)
598 # still an independent clause as it is lazier (and therefore faster)
607 return old.descendant(new)
599 return old.descendant(new)
@@ -1,898 +1,953 b''
1 $ hg init repo
1 $ hg init repo
2 $ cd repo
2 $ cd repo
3
3
4 no bookmarks
4 no bookmarks
5
5
6 $ hg bookmarks
6 $ hg bookmarks
7 no bookmarks set
7 no bookmarks set
8
8
9 $ hg bookmarks -Tjson
9 $ hg bookmarks -Tjson
10 [
10 [
11 ]
11 ]
12
12
13 bookmark rev -1
13 bookmark rev -1
14
14
15 $ hg bookmark X
15 $ hg bookmark X
16
16
17 list bookmarks
17 list bookmarks
18
18
19 $ hg bookmarks
19 $ hg bookmarks
20 * X -1:000000000000
20 * X -1:000000000000
21
21
22 list bookmarks with color
22 list bookmarks with color
23
23
24 $ hg --config extensions.color= --config color.mode=ansi \
24 $ hg --config extensions.color= --config color.mode=ansi \
25 > bookmarks --color=always
25 > bookmarks --color=always
26 \x1b[0;32m * \x1b[0m\x1b[0;32mX\x1b[0m\x1b[0;32m -1:000000000000\x1b[0m (esc)
26 \x1b[0;32m * \x1b[0m\x1b[0;32mX\x1b[0m\x1b[0;32m -1:000000000000\x1b[0m (esc)
27
27
28 $ echo a > a
28 $ echo a > a
29 $ hg add a
29 $ hg add a
30 $ hg commit -m 0
30 $ hg commit -m 0
31
31
32 bookmark X moved to rev 0
32 bookmark X moved to rev 0
33
33
34 $ hg bookmarks
34 $ hg bookmarks
35 * X 0:f7b1eb17ad24
35 * X 0:f7b1eb17ad24
36
36
37 look up bookmark
37 look up bookmark
38
38
39 $ hg log -r X
39 $ hg log -r X
40 changeset: 0:f7b1eb17ad24
40 changeset: 0:f7b1eb17ad24
41 bookmark: X
41 bookmark: X
42 tag: tip
42 tag: tip
43 user: test
43 user: test
44 date: Thu Jan 01 00:00:00 1970 +0000
44 date: Thu Jan 01 00:00:00 1970 +0000
45 summary: 0
45 summary: 0
46
46
47
47
48 second bookmark for rev 0, command should work even with ui.strict on
48 second bookmark for rev 0, command should work even with ui.strict on
49
49
50 $ hg --config ui.strict=1 bookmark X2
50 $ hg --config ui.strict=1 bookmark X2
51
51
52 bookmark rev -1 again
52 bookmark rev -1 again
53
53
54 $ hg bookmark -r null Y
54 $ hg bookmark -r null Y
55
55
56 list bookmarks
56 list bookmarks
57
57
58 $ hg bookmarks
58 $ hg bookmarks
59 X 0:f7b1eb17ad24
59 X 0:f7b1eb17ad24
60 * X2 0:f7b1eb17ad24
60 * X2 0:f7b1eb17ad24
61 Y -1:000000000000
61 Y -1:000000000000
62
62
63 $ echo b > b
63 $ echo b > b
64 $ hg add b
64 $ hg add b
65 $ hg commit -m 1
65 $ hg commit -m 1
66
66
67 $ hg bookmarks -Tjson
67 $ hg bookmarks -Tjson
68 [
68 [
69 {
69 {
70 "active": false,
70 "active": false,
71 "bookmark": "X",
71 "bookmark": "X",
72 "node": "f7b1eb17ad24730a1651fccd46c43826d1bbc2ac",
72 "node": "f7b1eb17ad24730a1651fccd46c43826d1bbc2ac",
73 "rev": 0
73 "rev": 0
74 },
74 },
75 {
75 {
76 "active": true,
76 "active": true,
77 "bookmark": "X2",
77 "bookmark": "X2",
78 "node": "925d80f479bb026b0fb3deb27503780b13f74123",
78 "node": "925d80f479bb026b0fb3deb27503780b13f74123",
79 "rev": 1
79 "rev": 1
80 },
80 },
81 {
81 {
82 "active": false,
82 "active": false,
83 "bookmark": "Y",
83 "bookmark": "Y",
84 "node": "0000000000000000000000000000000000000000",
84 "node": "0000000000000000000000000000000000000000",
85 "rev": -1
85 "rev": -1
86 }
86 }
87 ]
87 ]
88
88
89 bookmarks revset
89 bookmarks revset
90
90
91 $ hg log -r 'bookmark()'
91 $ hg log -r 'bookmark()'
92 changeset: 0:f7b1eb17ad24
92 changeset: 0:f7b1eb17ad24
93 bookmark: X
93 bookmark: X
94 user: test
94 user: test
95 date: Thu Jan 01 00:00:00 1970 +0000
95 date: Thu Jan 01 00:00:00 1970 +0000
96 summary: 0
96 summary: 0
97
97
98 changeset: 1:925d80f479bb
98 changeset: 1:925d80f479bb
99 bookmark: X2
99 bookmark: X2
100 tag: tip
100 tag: tip
101 user: test
101 user: test
102 date: Thu Jan 01 00:00:00 1970 +0000
102 date: Thu Jan 01 00:00:00 1970 +0000
103 summary: 1
103 summary: 1
104
104
105 $ hg log -r 'bookmark(Y)'
105 $ hg log -r 'bookmark(Y)'
106 $ hg log -r 'bookmark(X2)'
106 $ hg log -r 'bookmark(X2)'
107 changeset: 1:925d80f479bb
107 changeset: 1:925d80f479bb
108 bookmark: X2
108 bookmark: X2
109 tag: tip
109 tag: tip
110 user: test
110 user: test
111 date: Thu Jan 01 00:00:00 1970 +0000
111 date: Thu Jan 01 00:00:00 1970 +0000
112 summary: 1
112 summary: 1
113
113
114 $ hg log -r 'bookmark("re:X")'
114 $ hg log -r 'bookmark("re:X")'
115 changeset: 0:f7b1eb17ad24
115 changeset: 0:f7b1eb17ad24
116 bookmark: X
116 bookmark: X
117 user: test
117 user: test
118 date: Thu Jan 01 00:00:00 1970 +0000
118 date: Thu Jan 01 00:00:00 1970 +0000
119 summary: 0
119 summary: 0
120
120
121 changeset: 1:925d80f479bb
121 changeset: 1:925d80f479bb
122 bookmark: X2
122 bookmark: X2
123 tag: tip
123 tag: tip
124 user: test
124 user: test
125 date: Thu Jan 01 00:00:00 1970 +0000
125 date: Thu Jan 01 00:00:00 1970 +0000
126 summary: 1
126 summary: 1
127
127
128 $ hg log -r 'bookmark("literal:X")'
128 $ hg log -r 'bookmark("literal:X")'
129 changeset: 0:f7b1eb17ad24
129 changeset: 0:f7b1eb17ad24
130 bookmark: X
130 bookmark: X
131 user: test
131 user: test
132 date: Thu Jan 01 00:00:00 1970 +0000
132 date: Thu Jan 01 00:00:00 1970 +0000
133 summary: 0
133 summary: 0
134
134
135
135
136 $ hg log -r 'bookmark(unknown)'
136 $ hg log -r 'bookmark(unknown)'
137 abort: bookmark 'unknown' does not exist!
137 abort: bookmark 'unknown' does not exist!
138 [255]
138 [255]
139 $ hg log -r 'bookmark("literal:unknown")'
139 $ hg log -r 'bookmark("literal:unknown")'
140 abort: bookmark 'unknown' does not exist!
140 abort: bookmark 'unknown' does not exist!
141 [255]
141 [255]
142 $ hg log -r 'bookmark("re:unknown")'
142 $ hg log -r 'bookmark("re:unknown")'
143 abort: no bookmarks exist that match 'unknown'!
143 abort: no bookmarks exist that match 'unknown'!
144 [255]
144 [255]
145 $ hg log -r 'present(bookmark("literal:unknown"))'
145 $ hg log -r 'present(bookmark("literal:unknown"))'
146 $ hg log -r 'present(bookmark("re:unknown"))'
146 $ hg log -r 'present(bookmark("re:unknown"))'
147
147
148 $ hg help revsets | grep 'bookmark('
148 $ hg help revsets | grep 'bookmark('
149 "bookmark([name])"
149 "bookmark([name])"
150
150
151 bookmarks X and X2 moved to rev 1, Y at rev -1
151 bookmarks X and X2 moved to rev 1, Y at rev -1
152
152
153 $ hg bookmarks
153 $ hg bookmarks
154 X 0:f7b1eb17ad24
154 X 0:f7b1eb17ad24
155 * X2 1:925d80f479bb
155 * X2 1:925d80f479bb
156 Y -1:000000000000
156 Y -1:000000000000
157
157
158 bookmark rev 0 again
158 bookmark rev 0 again
159
159
160 $ hg bookmark -r 0 Z
160 $ hg bookmark -r 0 Z
161
161
162 $ hg update X
162 $ hg update X
163 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
163 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
164 (activating bookmark X)
164 (activating bookmark X)
165 $ echo c > c
165 $ echo c > c
166 $ hg add c
166 $ hg add c
167 $ hg commit -m 2
167 $ hg commit -m 2
168 created new head
168 created new head
169
169
170 bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
170 bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
171
171
172 $ hg bookmarks
172 $ hg bookmarks
173 * X 2:db815d6d32e6
173 * X 2:db815d6d32e6
174 X2 1:925d80f479bb
174 X2 1:925d80f479bb
175 Y -1:000000000000
175 Y -1:000000000000
176 Z 0:f7b1eb17ad24
176 Z 0:f7b1eb17ad24
177
177
178 rename nonexistent bookmark
178 rename nonexistent bookmark
179
179
180 $ hg bookmark -m A B
180 $ hg bookmark -m A B
181 abort: bookmark 'A' does not exist
181 abort: bookmark 'A' does not exist
182 [255]
182 [255]
183
183
184 rename to existent bookmark
184 rename to existent bookmark
185
185
186 $ hg bookmark -m X Y
186 $ hg bookmark -m X Y
187 abort: bookmark 'Y' already exists (use -f to force)
187 abort: bookmark 'Y' already exists (use -f to force)
188 [255]
188 [255]
189
189
190 force rename to existent bookmark
190 force rename to existent bookmark
191
191
192 $ hg bookmark -f -m X Y
192 $ hg bookmark -f -m X Y
193
193
194 list bookmarks
194 list bookmarks
195
195
196 $ hg bookmark
196 $ hg bookmark
197 X2 1:925d80f479bb
197 X2 1:925d80f479bb
198 * Y 2:db815d6d32e6
198 * Y 2:db815d6d32e6
199 Z 0:f7b1eb17ad24
199 Z 0:f7b1eb17ad24
200
200
201 bookmarks from a revset
201 bookmarks from a revset
202 $ hg bookmark -r '.^1' REVSET
202 $ hg bookmark -r '.^1' REVSET
203 $ hg bookmark -r ':tip' TIP
203 $ hg bookmark -r ':tip' TIP
204 $ hg up -q TIP
204 $ hg up -q TIP
205 $ hg bookmarks
205 $ hg bookmarks
206 REVSET 0:f7b1eb17ad24
206 REVSET 0:f7b1eb17ad24
207 * TIP 2:db815d6d32e6
207 * TIP 2:db815d6d32e6
208 X2 1:925d80f479bb
208 X2 1:925d80f479bb
209 Y 2:db815d6d32e6
209 Y 2:db815d6d32e6
210 Z 0:f7b1eb17ad24
210 Z 0:f7b1eb17ad24
211
211
212 $ hg bookmark -d REVSET
212 $ hg bookmark -d REVSET
213 $ hg bookmark -d TIP
213 $ hg bookmark -d TIP
214
214
215 rename without new name or multiple names
215 rename without new name or multiple names
216
216
217 $ hg bookmark -m Y
217 $ hg bookmark -m Y
218 abort: new bookmark name required
218 abort: new bookmark name required
219 [255]
219 [255]
220 $ hg bookmark -m Y Y2 Y3
220 $ hg bookmark -m Y Y2 Y3
221 abort: only one new bookmark name allowed
221 abort: only one new bookmark name allowed
222 [255]
222 [255]
223
223
224 delete without name
224 delete without name
225
225
226 $ hg bookmark -d
226 $ hg bookmark -d
227 abort: bookmark name required
227 abort: bookmark name required
228 [255]
228 [255]
229
229
230 delete nonexistent bookmark
230 delete nonexistent bookmark
231
231
232 $ hg bookmark -d A
232 $ hg bookmark -d A
233 abort: bookmark 'A' does not exist
233 abort: bookmark 'A' does not exist
234 [255]
234 [255]
235
235
236 bookmark name with spaces should be stripped
236 bookmark name with spaces should be stripped
237
237
238 $ hg bookmark ' x y '
238 $ hg bookmark ' x y '
239
239
240 list bookmarks
240 list bookmarks
241
241
242 $ hg bookmarks
242 $ hg bookmarks
243 X2 1:925d80f479bb
243 X2 1:925d80f479bb
244 Y 2:db815d6d32e6
244 Y 2:db815d6d32e6
245 Z 0:f7b1eb17ad24
245 Z 0:f7b1eb17ad24
246 * x y 2:db815d6d32e6
246 * x y 2:db815d6d32e6
247
247
248 look up stripped bookmark name
248 look up stripped bookmark name
249
249
250 $ hg log -r '"x y"'
250 $ hg log -r '"x y"'
251 changeset: 2:db815d6d32e6
251 changeset: 2:db815d6d32e6
252 bookmark: Y
252 bookmark: Y
253 bookmark: x y
253 bookmark: x y
254 tag: tip
254 tag: tip
255 parent: 0:f7b1eb17ad24
255 parent: 0:f7b1eb17ad24
256 user: test
256 user: test
257 date: Thu Jan 01 00:00:00 1970 +0000
257 date: Thu Jan 01 00:00:00 1970 +0000
258 summary: 2
258 summary: 2
259
259
260
260
261 reject bookmark name with newline
261 reject bookmark name with newline
262
262
263 $ hg bookmark '
263 $ hg bookmark '
264 > '
264 > '
265 abort: bookmark names cannot consist entirely of whitespace
265 abort: bookmark names cannot consist entirely of whitespace
266 [255]
266 [255]
267
267
268 $ hg bookmark -m Z '
268 $ hg bookmark -m Z '
269 > '
269 > '
270 abort: bookmark names cannot consist entirely of whitespace
270 abort: bookmark names cannot consist entirely of whitespace
271 [255]
271 [255]
272
272
273 bookmark with reserved name
273 bookmark with reserved name
274
274
275 $ hg bookmark tip
275 $ hg bookmark tip
276 abort: the name 'tip' is reserved
276 abort: the name 'tip' is reserved
277 [255]
277 [255]
278
278
279 $ hg bookmark .
279 $ hg bookmark .
280 abort: the name '.' is reserved
280 abort: the name '.' is reserved
281 [255]
281 [255]
282
282
283 $ hg bookmark null
283 $ hg bookmark null
284 abort: the name 'null' is reserved
284 abort: the name 'null' is reserved
285 [255]
285 [255]
286
286
287
287
288 bookmark with existing name
288 bookmark with existing name
289
289
290 $ hg bookmark X2
290 $ hg bookmark X2
291 abort: bookmark 'X2' already exists (use -f to force)
291 abort: bookmark 'X2' already exists (use -f to force)
292 [255]
292 [255]
293
293
294 $ hg bookmark -m Y Z
294 $ hg bookmark -m Y Z
295 abort: bookmark 'Z' already exists (use -f to force)
295 abort: bookmark 'Z' already exists (use -f to force)
296 [255]
296 [255]
297
297
298 bookmark with name of branch
298 bookmark with name of branch
299
299
300 $ hg bookmark default
300 $ hg bookmark default
301 abort: a bookmark cannot have the name of an existing branch
301 abort: a bookmark cannot have the name of an existing branch
302 [255]
302 [255]
303
303
304 $ hg bookmark -m Y default
304 $ hg bookmark -m Y default
305 abort: a bookmark cannot have the name of an existing branch
305 abort: a bookmark cannot have the name of an existing branch
306 [255]
306 [255]
307
307
308 bookmark with integer name
308 bookmark with integer name
309
309
310 $ hg bookmark 10
310 $ hg bookmark 10
311 abort: cannot use an integer as a name
311 abort: cannot use an integer as a name
312 [255]
312 [255]
313
313
314 incompatible options
314 incompatible options
315
315
316 $ hg bookmark -m Y -d Z
316 $ hg bookmark -m Y -d Z
317 abort: --delete and --rename are incompatible
317 abort: --delete and --rename are incompatible
318 [255]
318 [255]
319
319
320 $ hg bookmark -r 1 -d Z
320 $ hg bookmark -r 1 -d Z
321 abort: --rev is incompatible with --delete
321 abort: --rev is incompatible with --delete
322 [255]
322 [255]
323
323
324 $ hg bookmark -r 1 -m Z Y
324 $ hg bookmark -r 1 -m Z Y
325 abort: --rev is incompatible with --rename
325 abort: --rev is incompatible with --rename
326 [255]
326 [255]
327
327
328 force bookmark with existing name
328 force bookmark with existing name
329
329
330 $ hg bookmark -f X2
330 $ hg bookmark -f X2
331
331
332 force bookmark back to where it was, should deactivate it
332 force bookmark back to where it was, should deactivate it
333
333
334 $ hg bookmark -fr1 X2
334 $ hg bookmark -fr1 X2
335 $ hg bookmarks
335 $ hg bookmarks
336 X2 1:925d80f479bb
336 X2 1:925d80f479bb
337 Y 2:db815d6d32e6
337 Y 2:db815d6d32e6
338 Z 0:f7b1eb17ad24
338 Z 0:f7b1eb17ad24
339 x y 2:db815d6d32e6
339 x y 2:db815d6d32e6
340
340
341 forward bookmark to descendant without --force
341 forward bookmark to descendant without --force
342
342
343 $ hg bookmark Z
343 $ hg bookmark Z
344 moving bookmark 'Z' forward from f7b1eb17ad24
344 moving bookmark 'Z' forward from f7b1eb17ad24
345
345
346 list bookmarks
346 list bookmarks
347
347
348 $ hg bookmark
348 $ hg bookmark
349 X2 1:925d80f479bb
349 X2 1:925d80f479bb
350 Y 2:db815d6d32e6
350 Y 2:db815d6d32e6
351 * Z 2:db815d6d32e6
351 * Z 2:db815d6d32e6
352 x y 2:db815d6d32e6
352 x y 2:db815d6d32e6
353
353
354 revision but no bookmark name
354 revision but no bookmark name
355
355
356 $ hg bookmark -r .
356 $ hg bookmark -r .
357 abort: bookmark name required
357 abort: bookmark name required
358 [255]
358 [255]
359
359
360 bookmark name with whitespace only
360 bookmark name with whitespace only
361
361
362 $ hg bookmark ' '
362 $ hg bookmark ' '
363 abort: bookmark names cannot consist entirely of whitespace
363 abort: bookmark names cannot consist entirely of whitespace
364 [255]
364 [255]
365
365
366 $ hg bookmark -m Y ' '
366 $ hg bookmark -m Y ' '
367 abort: bookmark names cannot consist entirely of whitespace
367 abort: bookmark names cannot consist entirely of whitespace
368 [255]
368 [255]
369
369
370 invalid bookmark
370 invalid bookmark
371
371
372 $ hg bookmark 'foo:bar'
372 $ hg bookmark 'foo:bar'
373 abort: ':' cannot be used in a name
373 abort: ':' cannot be used in a name
374 [255]
374 [255]
375
375
376 $ hg bookmark 'foo
376 $ hg bookmark 'foo
377 > bar'
377 > bar'
378 abort: '\n' cannot be used in a name
378 abort: '\n' cannot be used in a name
379 [255]
379 [255]
380
380
381 the bookmark extension should be ignored now that it is part of core
381 the bookmark extension should be ignored now that it is part of core
382
382
383 $ echo "[extensions]" >> $HGRCPATH
383 $ echo "[extensions]" >> $HGRCPATH
384 $ echo "bookmarks=" >> $HGRCPATH
384 $ echo "bookmarks=" >> $HGRCPATH
385 $ hg bookmarks
385 $ hg bookmarks
386 X2 1:925d80f479bb
386 X2 1:925d80f479bb
387 Y 2:db815d6d32e6
387 Y 2:db815d6d32e6
388 * Z 2:db815d6d32e6
388 * Z 2:db815d6d32e6
389 x y 2:db815d6d32e6
389 x y 2:db815d6d32e6
390
390
391 test summary
391 test summary
392
392
393 $ hg summary
393 $ hg summary
394 parent: 2:db815d6d32e6 tip
394 parent: 2:db815d6d32e6 tip
395 2
395 2
396 branch: default
396 branch: default
397 bookmarks: *Z Y x y
397 bookmarks: *Z Y x y
398 commit: (clean)
398 commit: (clean)
399 update: 1 new changesets, 2 branch heads (merge)
399 update: 1 new changesets, 2 branch heads (merge)
400 phases: 3 draft
400 phases: 3 draft
401
401
402 test id
402 test id
403
403
404 $ hg id
404 $ hg id
405 db815d6d32e6 tip Y/Z/x y
405 db815d6d32e6 tip Y/Z/x y
406
406
407 test rollback
407 test rollback
408
408
409 $ echo foo > f1
409 $ echo foo > f1
410 $ hg bookmark tmp-rollback
410 $ hg bookmark tmp-rollback
411 $ hg ci -Amr
411 $ hg ci -Amr
412 adding f1
412 adding f1
413 $ hg bookmarks
413 $ hg bookmarks
414 X2 1:925d80f479bb
414 X2 1:925d80f479bb
415 Y 2:db815d6d32e6
415 Y 2:db815d6d32e6
416 Z 2:db815d6d32e6
416 Z 2:db815d6d32e6
417 * tmp-rollback 3:2bf5cfec5864
417 * tmp-rollback 3:2bf5cfec5864
418 x y 2:db815d6d32e6
418 x y 2:db815d6d32e6
419 $ hg rollback
419 $ hg rollback
420 repository tip rolled back to revision 2 (undo commit)
420 repository tip rolled back to revision 2 (undo commit)
421 working directory now based on revision 2
421 working directory now based on revision 2
422 $ hg bookmarks
422 $ hg bookmarks
423 X2 1:925d80f479bb
423 X2 1:925d80f479bb
424 Y 2:db815d6d32e6
424 Y 2:db815d6d32e6
425 Z 2:db815d6d32e6
425 Z 2:db815d6d32e6
426 * tmp-rollback 2:db815d6d32e6
426 * tmp-rollback 2:db815d6d32e6
427 x y 2:db815d6d32e6
427 x y 2:db815d6d32e6
428 $ hg bookmark -f Z -r 1
428 $ hg bookmark -f Z -r 1
429 $ hg rollback
429 $ hg rollback
430 repository tip rolled back to revision 2 (undo bookmark)
430 repository tip rolled back to revision 2 (undo bookmark)
431 $ hg bookmarks
431 $ hg bookmarks
432 X2 1:925d80f479bb
432 X2 1:925d80f479bb
433 Y 2:db815d6d32e6
433 Y 2:db815d6d32e6
434 Z 2:db815d6d32e6
434 Z 2:db815d6d32e6
435 * tmp-rollback 2:db815d6d32e6
435 * tmp-rollback 2:db815d6d32e6
436 x y 2:db815d6d32e6
436 x y 2:db815d6d32e6
437 $ hg bookmark -d tmp-rollback
437 $ hg bookmark -d tmp-rollback
438
438
439 activate bookmark on working dir parent without --force
439 activate bookmark on working dir parent without --force
440
440
441 $ hg bookmark --inactive Z
441 $ hg bookmark --inactive Z
442 $ hg bookmark Z
442 $ hg bookmark Z
443
443
444 test clone
444 test clone
445
445
446 $ hg bookmark -r 2 -i @
446 $ hg bookmark -r 2 -i @
447 $ hg bookmark -r 2 -i a@
447 $ hg bookmark -r 2 -i a@
448 $ hg bookmarks
448 $ hg bookmarks
449 @ 2:db815d6d32e6
449 @ 2:db815d6d32e6
450 X2 1:925d80f479bb
450 X2 1:925d80f479bb
451 Y 2:db815d6d32e6
451 Y 2:db815d6d32e6
452 * Z 2:db815d6d32e6
452 * Z 2:db815d6d32e6
453 a@ 2:db815d6d32e6
453 a@ 2:db815d6d32e6
454 x y 2:db815d6d32e6
454 x y 2:db815d6d32e6
455 $ hg clone . cloned-bookmarks
455 $ hg clone . cloned-bookmarks
456 updating to bookmark @
456 updating to bookmark @
457 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
457 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
458 $ hg -R cloned-bookmarks bookmarks
458 $ hg -R cloned-bookmarks bookmarks
459 * @ 2:db815d6d32e6
459 * @ 2:db815d6d32e6
460 X2 1:925d80f479bb
460 X2 1:925d80f479bb
461 Y 2:db815d6d32e6
461 Y 2:db815d6d32e6
462 Z 2:db815d6d32e6
462 Z 2:db815d6d32e6
463 a@ 2:db815d6d32e6
463 a@ 2:db815d6d32e6
464 x y 2:db815d6d32e6
464 x y 2:db815d6d32e6
465
465
466 test clone with pull protocol
466 test clone with pull protocol
467
467
468 $ hg clone --pull . cloned-bookmarks-pull
468 $ hg clone --pull . cloned-bookmarks-pull
469 requesting all changes
469 requesting all changes
470 adding changesets
470 adding changesets
471 adding manifests
471 adding manifests
472 adding file changes
472 adding file changes
473 added 3 changesets with 3 changes to 3 files (+1 heads)
473 added 3 changesets with 3 changes to 3 files (+1 heads)
474 updating to bookmark @
474 updating to bookmark @
475 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
475 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
476 $ hg -R cloned-bookmarks-pull bookmarks
476 $ hg -R cloned-bookmarks-pull bookmarks
477 * @ 2:db815d6d32e6
477 * @ 2:db815d6d32e6
478 X2 1:925d80f479bb
478 X2 1:925d80f479bb
479 Y 2:db815d6d32e6
479 Y 2:db815d6d32e6
480 Z 2:db815d6d32e6
480 Z 2:db815d6d32e6
481 a@ 2:db815d6d32e6
481 a@ 2:db815d6d32e6
482 x y 2:db815d6d32e6
482 x y 2:db815d6d32e6
483
483
484 delete multiple bookmarks at once
484 delete multiple bookmarks at once
485
485
486 $ hg bookmark -d @ a@
486 $ hg bookmark -d @ a@
487
487
488 test clone with a bookmark named "default" (issue3677)
488 test clone with a bookmark named "default" (issue3677)
489
489
490 $ hg bookmark -r 1 -f -i default
490 $ hg bookmark -r 1 -f -i default
491 $ hg clone . cloned-bookmark-default
491 $ hg clone . cloned-bookmark-default
492 updating to branch default
492 updating to branch default
493 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
493 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
494 $ hg -R cloned-bookmark-default bookmarks
494 $ hg -R cloned-bookmark-default bookmarks
495 X2 1:925d80f479bb
495 X2 1:925d80f479bb
496 Y 2:db815d6d32e6
496 Y 2:db815d6d32e6
497 Z 2:db815d6d32e6
497 Z 2:db815d6d32e6
498 default 1:925d80f479bb
498 default 1:925d80f479bb
499 x y 2:db815d6d32e6
499 x y 2:db815d6d32e6
500 $ hg -R cloned-bookmark-default parents -q
500 $ hg -R cloned-bookmark-default parents -q
501 2:db815d6d32e6
501 2:db815d6d32e6
502 $ hg bookmark -d default
502 $ hg bookmark -d default
503
503
504 test clone with a specific revision
504 test clone with a specific revision
505
505
506 $ hg clone -r 925d80 . cloned-bookmarks-rev
506 $ hg clone -r 925d80 . cloned-bookmarks-rev
507 adding changesets
507 adding changesets
508 adding manifests
508 adding manifests
509 adding file changes
509 adding file changes
510 added 2 changesets with 2 changes to 2 files
510 added 2 changesets with 2 changes to 2 files
511 updating to branch default
511 updating to branch default
512 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
512 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
513 $ hg -R cloned-bookmarks-rev bookmarks
513 $ hg -R cloned-bookmarks-rev bookmarks
514 X2 1:925d80f479bb
514 X2 1:925d80f479bb
515
515
516 test clone with update to a bookmark
516 test clone with update to a bookmark
517
517
518 $ hg clone -u Z . ../cloned-bookmarks-update
518 $ hg clone -u Z . ../cloned-bookmarks-update
519 updating to branch default
519 updating to branch default
520 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
520 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
521 $ hg -R ../cloned-bookmarks-update bookmarks
521 $ hg -R ../cloned-bookmarks-update bookmarks
522 X2 1:925d80f479bb
522 X2 1:925d80f479bb
523 Y 2:db815d6d32e6
523 Y 2:db815d6d32e6
524 * Z 2:db815d6d32e6
524 * Z 2:db815d6d32e6
525 x y 2:db815d6d32e6
525 x y 2:db815d6d32e6
526
526
527 create bundle with two heads
527 create bundle with two heads
528
528
529 $ hg clone . tobundle
529 $ hg clone . tobundle
530 updating to branch default
530 updating to branch default
531 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
531 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
532 $ echo x > tobundle/x
532 $ echo x > tobundle/x
533 $ hg -R tobundle add tobundle/x
533 $ hg -R tobundle add tobundle/x
534 $ hg -R tobundle commit -m'x'
534 $ hg -R tobundle commit -m'x'
535 $ hg -R tobundle update -r -2
535 $ hg -R tobundle update -r -2
536 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
536 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
537 $ echo y > tobundle/y
537 $ echo y > tobundle/y
538 $ hg -R tobundle branch test
538 $ hg -R tobundle branch test
539 marked working directory as branch test
539 marked working directory as branch test
540 (branches are permanent and global, did you want a bookmark?)
540 (branches are permanent and global, did you want a bookmark?)
541 $ hg -R tobundle add tobundle/y
541 $ hg -R tobundle add tobundle/y
542 $ hg -R tobundle commit -m'y'
542 $ hg -R tobundle commit -m'y'
543 $ hg -R tobundle bundle tobundle.hg
543 $ hg -R tobundle bundle tobundle.hg
544 searching for changes
544 searching for changes
545 2 changesets found
545 2 changesets found
546 $ hg unbundle tobundle.hg
546 $ hg unbundle tobundle.hg
547 adding changesets
547 adding changesets
548 adding manifests
548 adding manifests
549 adding file changes
549 adding file changes
550 added 2 changesets with 2 changes to 2 files (+1 heads)
550 added 2 changesets with 2 changes to 2 files (+1 heads)
551 (run 'hg heads' to see heads, 'hg merge' to merge)
551 (run 'hg heads' to see heads, 'hg merge' to merge)
552
552
553 update to active bookmark if it's not the parent
553 update to active bookmark if it's not the parent
554
554
555 $ hg summary
555 $ hg summary
556 parent: 2:db815d6d32e6
556 parent: 2:db815d6d32e6
557 2
557 2
558 branch: default
558 branch: default
559 bookmarks: *Z Y x y
559 bookmarks: *Z Y x y
560 commit: 1 added, 1 unknown (new branch head)
560 commit: 1 added, 1 unknown (new branch head)
561 update: 2 new changesets (update)
561 update: 2 new changesets (update)
562 phases: 5 draft
562 phases: 5 draft
563 $ hg update
563 $ hg update
564 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
564 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
565 updating bookmark Z
565 updating bookmark Z
566 $ hg bookmarks
566 $ hg bookmarks
567 X2 1:925d80f479bb
567 X2 1:925d80f479bb
568 Y 2:db815d6d32e6
568 Y 2:db815d6d32e6
569 * Z 3:125c9a1d6df6
569 * Z 3:125c9a1d6df6
570 x y 2:db815d6d32e6
570 x y 2:db815d6d32e6
571
571
572 pull --update works the same as pull && update
572 pull --update works the same as pull && update
573
573
574 $ hg bookmark -r3 Y
574 $ hg bookmark -r3 Y
575 moving bookmark 'Y' forward from db815d6d32e6
575 moving bookmark 'Y' forward from db815d6d32e6
576 $ cp -R ../cloned-bookmarks-update ../cloned-bookmarks-manual-update
576 $ cp -R ../cloned-bookmarks-update ../cloned-bookmarks-manual-update
577 $ cp -R ../cloned-bookmarks-update ../cloned-bookmarks-manual-update-with-divergence
577 $ cp -R ../cloned-bookmarks-update ../cloned-bookmarks-manual-update-with-divergence
578
578
579 (manual version)
579 (manual version)
580
580
581 $ hg -R ../cloned-bookmarks-manual-update update Y
581 $ hg -R ../cloned-bookmarks-manual-update update Y
582 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
582 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
583 (activating bookmark Y)
583 (activating bookmark Y)
584 $ hg -R ../cloned-bookmarks-manual-update pull .
584 $ hg -R ../cloned-bookmarks-manual-update pull .
585 pulling from .
585 pulling from .
586 searching for changes
586 searching for changes
587 adding changesets
587 adding changesets
588 adding manifests
588 adding manifests
589 adding file changes
589 adding file changes
590 added 2 changesets with 2 changes to 2 files (+1 heads)
590 added 2 changesets with 2 changes to 2 files (+1 heads)
591 updating bookmark Y
591 updating bookmark Y
592 updating bookmark Z
592 updating bookmark Z
593 (run 'hg heads' to see heads, 'hg merge' to merge)
593 (run 'hg heads' to see heads, 'hg merge' to merge)
594
594
595 (# tests strange but with --date crashing when bookmark have to move)
595 (# tests strange but with --date crashing when bookmark have to move)
596
596
597 $ hg -R ../cloned-bookmarks-manual-update update -d 1986
597 $ hg -R ../cloned-bookmarks-manual-update update -d 1986
598 abort: revision matching date not found
598 abort: revision matching date not found
599 [255]
599 [255]
600 $ hg -R ../cloned-bookmarks-manual-update update
600 $ hg -R ../cloned-bookmarks-manual-update update
601 updating to active bookmark Y
601 updating to active bookmark Y
602 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
602 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
603
603
604 (all in one version)
604 (all in one version)
605
605
606 $ hg -R ../cloned-bookmarks-update update Y
606 $ hg -R ../cloned-bookmarks-update update Y
607 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
607 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
608 (activating bookmark Y)
608 (activating bookmark Y)
609 $ hg -R ../cloned-bookmarks-update pull --update .
609 $ hg -R ../cloned-bookmarks-update pull --update .
610 pulling from .
610 pulling from .
611 searching for changes
611 searching for changes
612 adding changesets
612 adding changesets
613 adding manifests
613 adding manifests
614 adding file changes
614 adding file changes
615 added 2 changesets with 2 changes to 2 files (+1 heads)
615 added 2 changesets with 2 changes to 2 files (+1 heads)
616 updating bookmark Y
616 updating bookmark Y
617 updating bookmark Z
617 updating bookmark Z
618 updating to active bookmark Y
618 updating to active bookmark Y
619 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
619 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
620
620
621 We warn about divergent during bare update to the active bookmark
621 We warn about divergent during bare update to the active bookmark
622
622
623 $ hg -R ../cloned-bookmarks-manual-update-with-divergence update Y
623 $ hg -R ../cloned-bookmarks-manual-update-with-divergence update Y
624 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
624 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
625 (activating bookmark Y)
625 (activating bookmark Y)
626 $ hg -R ../cloned-bookmarks-manual-update-with-divergence bookmarks -r X2 Y@1
626 $ hg -R ../cloned-bookmarks-manual-update-with-divergence bookmarks -r X2 Y@1
627 $ hg -R ../cloned-bookmarks-manual-update-with-divergence bookmarks
627 $ hg -R ../cloned-bookmarks-manual-update-with-divergence bookmarks
628 X2 1:925d80f479bb
628 X2 1:925d80f479bb
629 * Y 2:db815d6d32e6
629 * Y 2:db815d6d32e6
630 Y@1 1:925d80f479bb
630 Y@1 1:925d80f479bb
631 Z 2:db815d6d32e6
631 Z 2:db815d6d32e6
632 x y 2:db815d6d32e6
632 x y 2:db815d6d32e6
633 $ hg -R ../cloned-bookmarks-manual-update-with-divergence pull
633 $ hg -R ../cloned-bookmarks-manual-update-with-divergence pull
634 pulling from $TESTTMP/repo (glob)
634 pulling from $TESTTMP/repo (glob)
635 searching for changes
635 searching for changes
636 adding changesets
636 adding changesets
637 adding manifests
637 adding manifests
638 adding file changes
638 adding file changes
639 added 2 changesets with 2 changes to 2 files (+1 heads)
639 added 2 changesets with 2 changes to 2 files (+1 heads)
640 updating bookmark Y
640 updating bookmark Y
641 updating bookmark Z
641 updating bookmark Z
642 (run 'hg heads' to see heads, 'hg merge' to merge)
642 (run 'hg heads' to see heads, 'hg merge' to merge)
643 $ hg -R ../cloned-bookmarks-manual-update-with-divergence update
643 $ hg -R ../cloned-bookmarks-manual-update-with-divergence update
644 updating to active bookmark Y
644 updating to active bookmark Y
645 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
645 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
646 1 other divergent bookmarks for "Y"
646 1 other divergent bookmarks for "Y"
647
647
648 test wrongly formated bookmark
648 test wrongly formated bookmark
649
649
650 $ echo '' >> .hg/bookmarks
650 $ echo '' >> .hg/bookmarks
651 $ hg bookmarks
651 $ hg bookmarks
652 X2 1:925d80f479bb
652 X2 1:925d80f479bb
653 Y 3:125c9a1d6df6
653 Y 3:125c9a1d6df6
654 * Z 3:125c9a1d6df6
654 * Z 3:125c9a1d6df6
655 x y 2:db815d6d32e6
655 x y 2:db815d6d32e6
656 $ echo "Ican'thasformatedlines" >> .hg/bookmarks
656 $ echo "Ican'thasformatedlines" >> .hg/bookmarks
657 $ hg bookmarks
657 $ hg bookmarks
658 malformed line in .hg/bookmarks: "Ican'thasformatedlines"
658 malformed line in .hg/bookmarks: "Ican'thasformatedlines"
659 X2 1:925d80f479bb
659 X2 1:925d80f479bb
660 Y 3:125c9a1d6df6
660 Y 3:125c9a1d6df6
661 * Z 3:125c9a1d6df6
661 * Z 3:125c9a1d6df6
662 x y 2:db815d6d32e6
662 x y 2:db815d6d32e6
663
663
664 test missing revisions
664 test missing revisions
665
665
666 $ echo "925d80f479bc z" > .hg/bookmarks
666 $ echo "925d80f479bc z" > .hg/bookmarks
667 $ hg book
667 $ hg book
668 no bookmarks set
668 no bookmarks set
669
669
670 test stripping a non-checked-out but bookmarked revision
670 test stripping a non-checked-out but bookmarked revision
671
671
672 $ hg log --graph
672 $ hg log --graph
673 o changeset: 4:9ba5f110a0b3
673 o changeset: 4:9ba5f110a0b3
674 | branch: test
674 | branch: test
675 | tag: tip
675 | tag: tip
676 | parent: 2:db815d6d32e6
676 | parent: 2:db815d6d32e6
677 | user: test
677 | user: test
678 | date: Thu Jan 01 00:00:00 1970 +0000
678 | date: Thu Jan 01 00:00:00 1970 +0000
679 | summary: y
679 | summary: y
680 |
680 |
681 | @ changeset: 3:125c9a1d6df6
681 | @ changeset: 3:125c9a1d6df6
682 |/ user: test
682 |/ user: test
683 | date: Thu Jan 01 00:00:00 1970 +0000
683 | date: Thu Jan 01 00:00:00 1970 +0000
684 | summary: x
684 | summary: x
685 |
685 |
686 o changeset: 2:db815d6d32e6
686 o changeset: 2:db815d6d32e6
687 | parent: 0:f7b1eb17ad24
687 | parent: 0:f7b1eb17ad24
688 | user: test
688 | user: test
689 | date: Thu Jan 01 00:00:00 1970 +0000
689 | date: Thu Jan 01 00:00:00 1970 +0000
690 | summary: 2
690 | summary: 2
691 |
691 |
692 | o changeset: 1:925d80f479bb
692 | o changeset: 1:925d80f479bb
693 |/ user: test
693 |/ user: test
694 | date: Thu Jan 01 00:00:00 1970 +0000
694 | date: Thu Jan 01 00:00:00 1970 +0000
695 | summary: 1
695 | summary: 1
696 |
696 |
697 o changeset: 0:f7b1eb17ad24
697 o changeset: 0:f7b1eb17ad24
698 user: test
698 user: test
699 date: Thu Jan 01 00:00:00 1970 +0000
699 date: Thu Jan 01 00:00:00 1970 +0000
700 summary: 0
700 summary: 0
701
701
702 $ hg book should-end-on-two
702 $ hg book should-end-on-two
703 $ hg co --clean 4
703 $ hg co --clean 4
704 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
704 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
705 (leaving bookmark should-end-on-two)
705 (leaving bookmark should-end-on-two)
706 $ hg book four
706 $ hg book four
707 $ hg --config extensions.mq= strip 3
707 $ hg --config extensions.mq= strip 3
708 saved backup bundle to * (glob)
708 saved backup bundle to * (glob)
709 should-end-on-two should end up pointing to revision 2, as that's the
709 should-end-on-two should end up pointing to revision 2, as that's the
710 tipmost surviving ancestor of the stripped revision.
710 tipmost surviving ancestor of the stripped revision.
711 $ hg log --graph
711 $ hg log --graph
712 @ changeset: 3:9ba5f110a0b3
712 @ changeset: 3:9ba5f110a0b3
713 | branch: test
713 | branch: test
714 | bookmark: four
714 | bookmark: four
715 | tag: tip
715 | tag: tip
716 | user: test
716 | user: test
717 | date: Thu Jan 01 00:00:00 1970 +0000
717 | date: Thu Jan 01 00:00:00 1970 +0000
718 | summary: y
718 | summary: y
719 |
719 |
720 o changeset: 2:db815d6d32e6
720 o changeset: 2:db815d6d32e6
721 | bookmark: should-end-on-two
721 | bookmark: should-end-on-two
722 | parent: 0:f7b1eb17ad24
722 | parent: 0:f7b1eb17ad24
723 | user: test
723 | user: test
724 | date: Thu Jan 01 00:00:00 1970 +0000
724 | date: Thu Jan 01 00:00:00 1970 +0000
725 | summary: 2
725 | summary: 2
726 |
726 |
727 | o changeset: 1:925d80f479bb
727 | o changeset: 1:925d80f479bb
728 |/ user: test
728 |/ user: test
729 | date: Thu Jan 01 00:00:00 1970 +0000
729 | date: Thu Jan 01 00:00:00 1970 +0000
730 | summary: 1
730 | summary: 1
731 |
731 |
732 o changeset: 0:f7b1eb17ad24
732 o changeset: 0:f7b1eb17ad24
733 user: test
733 user: test
734 date: Thu Jan 01 00:00:00 1970 +0000
734 date: Thu Jan 01 00:00:00 1970 +0000
735 summary: 0
735 summary: 0
736
736
737
737
738 no-op update doesn't deactivate bookmarks
738 no-op update doesn't deactivate bookmarks
739
739
740 $ hg bookmarks
740 $ hg bookmarks
741 * four 3:9ba5f110a0b3
741 * four 3:9ba5f110a0b3
742 should-end-on-two 2:db815d6d32e6
742 should-end-on-two 2:db815d6d32e6
743 $ hg up four
743 $ hg up four
744 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
744 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
745 $ hg up
745 $ hg up
746 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
746 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
747 $ hg sum
747 $ hg sum
748 parent: 3:9ba5f110a0b3 tip
748 parent: 3:9ba5f110a0b3 tip
749 y
749 y
750 branch: test
750 branch: test
751 bookmarks: *four
751 bookmarks: *four
752 commit: 2 unknown (clean)
752 commit: 2 unknown (clean)
753 update: (current)
753 update: (current)
754 phases: 4 draft
754 phases: 4 draft
755
755
756 test clearing divergent bookmarks of linear ancestors
756 test clearing divergent bookmarks of linear ancestors
757
757
758 $ hg bookmark Z -r 0
758 $ hg bookmark Z -r 0
759 $ hg bookmark Z@1 -r 1
759 $ hg bookmark Z@1 -r 1
760 $ hg bookmark Z@2 -r 2
760 $ hg bookmark Z@2 -r 2
761 $ hg bookmark Z@3 -r 3
761 $ hg bookmark Z@3 -r 3
762 $ hg book
762 $ hg book
763 Z 0:f7b1eb17ad24
763 Z 0:f7b1eb17ad24
764 Z@1 1:925d80f479bb
764 Z@1 1:925d80f479bb
765 Z@2 2:db815d6d32e6
765 Z@2 2:db815d6d32e6
766 Z@3 3:9ba5f110a0b3
766 Z@3 3:9ba5f110a0b3
767 * four 3:9ba5f110a0b3
767 * four 3:9ba5f110a0b3
768 should-end-on-two 2:db815d6d32e6
768 should-end-on-two 2:db815d6d32e6
769 $ hg bookmark Z
769 $ hg bookmark Z
770 moving bookmark 'Z' forward from f7b1eb17ad24
770 moving bookmark 'Z' forward from f7b1eb17ad24
771 $ hg book
771 $ hg book
772 * Z 3:9ba5f110a0b3
772 * Z 3:9ba5f110a0b3
773 Z@1 1:925d80f479bb
773 Z@1 1:925d80f479bb
774 four 3:9ba5f110a0b3
774 four 3:9ba5f110a0b3
775 should-end-on-two 2:db815d6d32e6
775 should-end-on-two 2:db815d6d32e6
776
776
777 test clearing only a single divergent bookmark across branches
777 test clearing only a single divergent bookmark across branches
778
778
779 $ hg book foo -r 1
779 $ hg book foo -r 1
780 $ hg book foo@1 -r 0
780 $ hg book foo@1 -r 0
781 $ hg book foo@2 -r 2
781 $ hg book foo@2 -r 2
782 $ hg book foo@3 -r 3
782 $ hg book foo@3 -r 3
783 $ hg book foo -r foo@3
783 $ hg book foo -r foo@3
784 $ hg book
784 $ hg book
785 * Z 3:9ba5f110a0b3
785 * Z 3:9ba5f110a0b3
786 Z@1 1:925d80f479bb
786 Z@1 1:925d80f479bb
787 foo 3:9ba5f110a0b3
787 foo 3:9ba5f110a0b3
788 foo@1 0:f7b1eb17ad24
788 foo@1 0:f7b1eb17ad24
789 foo@2 2:db815d6d32e6
789 foo@2 2:db815d6d32e6
790 four 3:9ba5f110a0b3
790 four 3:9ba5f110a0b3
791 should-end-on-two 2:db815d6d32e6
791 should-end-on-two 2:db815d6d32e6
792
792
793 pull --update works the same as pull && update (case #2)
793 pull --update works the same as pull && update (case #2)
794
794
795 It is assumed that "hg pull" itself doesn't update current active
795 It is assumed that "hg pull" itself doesn't update current active
796 bookmark ('Y' in tests below).
796 bookmark ('Y' in tests below).
797
797
798 $ hg pull -q ../cloned-bookmarks-update
798 $ hg pull -q ../cloned-bookmarks-update
799 divergent bookmark Z stored as Z@2
799 divergent bookmark Z stored as Z@2
800
800
801 (pulling revision on another named branch with --update updates
801 (pulling revision on another named branch with --update updates
802 neither the working directory nor current active bookmark: "no-op"
802 neither the working directory nor current active bookmark: "no-op"
803 case)
803 case)
804
804
805 $ echo yy >> y
805 $ echo yy >> y
806 $ hg commit -m yy
806 $ hg commit -m yy
807
807
808 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
808 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
809 * Y 3:125c9a1d6df6
809 * Y 3:125c9a1d6df6
810 $ hg -R ../cloned-bookmarks-update pull . --update
810 $ hg -R ../cloned-bookmarks-update pull . --update
811 pulling from .
811 pulling from .
812 searching for changes
812 searching for changes
813 adding changesets
813 adding changesets
814 adding manifests
814 adding manifests
815 adding file changes
815 adding file changes
816 added 1 changesets with 1 changes to 1 files
816 added 1 changesets with 1 changes to 1 files
817 divergent bookmark Z stored as Z@default
817 divergent bookmark Z stored as Z@default
818 adding remote bookmark foo
818 adding remote bookmark foo
819 adding remote bookmark four
819 adding remote bookmark four
820 adding remote bookmark should-end-on-two
820 adding remote bookmark should-end-on-two
821 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
821 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
822 $ hg -R ../cloned-bookmarks-update parents -T "{rev}:{node|short}\n"
822 $ hg -R ../cloned-bookmarks-update parents -T "{rev}:{node|short}\n"
823 3:125c9a1d6df6
823 3:125c9a1d6df6
824 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
824 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
825 * Y 3:125c9a1d6df6
825 * Y 3:125c9a1d6df6
826
826
827 (pulling revision on current named/topological branch with --update
827 (pulling revision on current named/topological branch with --update
828 updates the working directory and current active bookmark)
828 updates the working directory and current active bookmark)
829
829
830 $ hg update -C -q 125c9a1d6df6
830 $ hg update -C -q 125c9a1d6df6
831 $ echo xx >> x
831 $ echo xx >> x
832 $ hg commit -m xx
832 $ hg commit -m xx
833
833
834 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
834 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
835 * Y 3:125c9a1d6df6
835 * Y 3:125c9a1d6df6
836 $ hg -R ../cloned-bookmarks-update pull . --update
836 $ hg -R ../cloned-bookmarks-update pull . --update
837 pulling from .
837 pulling from .
838 searching for changes
838 searching for changes
839 adding changesets
839 adding changesets
840 adding manifests
840 adding manifests
841 adding file changes
841 adding file changes
842 added 1 changesets with 1 changes to 1 files
842 added 1 changesets with 1 changes to 1 files
843 divergent bookmark Z stored as Z@default
843 divergent bookmark Z stored as Z@default
844 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
844 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
845 updating bookmark Y
845 updating bookmark Y
846 $ hg -R ../cloned-bookmarks-update parents -T "{rev}:{node|short}\n"
846 $ hg -R ../cloned-bookmarks-update parents -T "{rev}:{node|short}\n"
847 6:81dcce76aa0b
847 6:81dcce76aa0b
848 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
848 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
849 * Y 6:81dcce76aa0b
849 * Y 6:81dcce76aa0b
850
850
851 $ cd ..
851 $ cd ..
852
852
853 ensure changelog is written before bookmarks
853 ensure changelog is written before bookmarks
854 $ hg init orderrepo
854 $ hg init orderrepo
855 $ cd orderrepo
855 $ cd orderrepo
856 $ touch a
856 $ touch a
857 $ hg commit -Aqm one
857 $ hg commit -Aqm one
858 $ hg book mybook
858 $ hg book mybook
859 $ echo a > a
859 $ echo a > a
860
860
861 $ cat > $TESTTMP/pausefinalize.py <<EOF
861 $ cat > $TESTTMP/pausefinalize.py <<EOF
862 > from mercurial import extensions, localrepo
862 > from mercurial import extensions, localrepo
863 > import os, time
863 > import os, time
864 > def transaction(orig, self, desc, report=None):
864 > def transaction(orig, self, desc, report=None):
865 > tr = orig(self, desc, report)
865 > tr = orig(self, desc, report)
866 > def sleep(*args, **kwargs):
866 > def sleep(*args, **kwargs):
867 > retry = 20
867 > retry = 20
868 > while retry > 0 and not os.path.exists("$TESTTMP/unpause"):
868 > while retry > 0 and not os.path.exists("$TESTTMP/unpause"):
869 > retry -= 1
869 > retry -= 1
870 > time.sleep(0.5)
870 > time.sleep(0.5)
871 > if os.path.exists("$TESTTMP/unpause"):
871 > if os.path.exists("$TESTTMP/unpause"):
872 > os.remove("$TESTTMP/unpause")
872 > os.remove("$TESTTMP/unpause")
873 > # It is important that this finalizer start with 'a', so it runs before
873 > # It is important that this finalizer start with 'a', so it runs before
874 > # the changelog finalizer appends to the changelog.
874 > # the changelog finalizer appends to the changelog.
875 > tr.addfinalize('a-sleep', sleep)
875 > tr.addfinalize('a-sleep', sleep)
876 > return tr
876 > return tr
877 >
877 >
878 > def extsetup(ui):
878 > def extsetup(ui):
879 > # This extension inserts an artifical pause during the transaction
879 > # This extension inserts an artifical pause during the transaction
880 > # finalizer, so we can run commands mid-transaction-close.
880 > # finalizer, so we can run commands mid-transaction-close.
881 > extensions.wrapfunction(localrepo.localrepository, 'transaction',
881 > extensions.wrapfunction(localrepo.localrepository, 'transaction',
882 > transaction)
882 > transaction)
883 > EOF
883 > EOF
884 $ hg commit -qm two --config extensions.pausefinalize=$TESTTMP/pausefinalize.py &
884 $ hg commit -qm two --config extensions.pausefinalize=$TESTTMP/pausefinalize.py &
885 $ sleep 2
885 $ sleep 2
886 $ hg log -r .
886 $ hg log -r .
887 changeset: 0:867bc5792c8c
887 changeset: 0:867bc5792c8c
888 bookmark: mybook
888 bookmark: mybook
889 tag: tip
889 tag: tip
890 user: test
890 user: test
891 date: Thu Jan 01 00:00:00 1970 +0000
891 date: Thu Jan 01 00:00:00 1970 +0000
892 summary: one
892 summary: one
893
893
894 $ hg bookmarks
894 $ hg bookmarks
895 * mybook 0:867bc5792c8c
895 * mybook 0:867bc5792c8c
896 $ touch $TESTTMP/unpause
896 $ touch $TESTTMP/unpause
897
897
898 $ cd ..
898 $ cd ..
899
900 check whether HG_PENDING makes pending changes only in related
901 repositories visible to an external hook.
902
903 (emulate a transaction running concurrently by copied
904 .hg/bookmarks.pending in subsequent test)
905
906 $ cat > $TESTTMP/savepending.sh <<EOF
907 > cp .hg/bookmarks.pending .hg/bookmarks.pending.saved
908 > exit 1 # to avoid adding new bookmark for subsequent tests
909 > EOF
910
911 $ hg init unrelated
912 $ cd unrelated
913 $ echo a > a
914 $ hg add a
915 $ hg commit -m '#0'
916 $ hg --config hooks.pretxnclose="sh $TESTTMP/savepending.sh" bookmarks INVISIBLE
917 transaction abort!
918 rollback completed
919 abort: pretxnclose hook exited with status 1
920 [255]
921 $ cp .hg/bookmarks.pending.saved .hg/bookmarks.pending
922
923 (check visible bookmarks while transaction running in repo)
924
925 $ cat > $TESTTMP/checkpending.sh <<EOF
926 > echo "@repo"
927 > hg -R $TESTTMP/repo bookmarks
928 > echo "@unrelated"
929 > hg -R $TESTTMP/unrelated bookmarks
930 > exit 1 # to avoid adding new bookmark for subsequent tests
931 > EOF
932
933 $ cd ../repo
934 $ hg --config hooks.pretxnclose="sh $TESTTMP/checkpending.sh" bookmarks NEW
935 @repo
936 * NEW 6:81dcce76aa0b
937 X2 1:925d80f479bb
938 Y 4:125c9a1d6df6
939 Z 5:5fb12f0f2d51
940 Z@1 1:925d80f479bb
941 Z@2 4:125c9a1d6df6
942 foo 3:9ba5f110a0b3
943 foo@1 0:f7b1eb17ad24
944 foo@2 2:db815d6d32e6
945 four 3:9ba5f110a0b3
946 should-end-on-two 2:db815d6d32e6
947 x y 2:db815d6d32e6
948 @unrelated
949 no bookmarks set
950 transaction abort!
951 rollback completed
952 abort: pretxnclose hook exited with status 1
953 [255]
@@ -1,303 +1,364 b''
1 #require killdaemons
1 #require killdaemons
2
2
3 $ echo "[extensions]" >> $HGRCPATH
3 $ echo "[extensions]" >> $HGRCPATH
4 $ echo "share = " >> $HGRCPATH
4 $ echo "share = " >> $HGRCPATH
5
5
6 prepare repo1
6 prepare repo1
7
7
8 $ hg init repo1
8 $ hg init repo1
9 $ cd repo1
9 $ cd repo1
10 $ echo a > a
10 $ echo a > a
11 $ hg commit -A -m'init'
11 $ hg commit -A -m'init'
12 adding a
12 adding a
13
13
14 share it
14 share it
15
15
16 $ cd ..
16 $ cd ..
17 $ hg share repo1 repo2
17 $ hg share repo1 repo2
18 updating working directory
18 updating working directory
19 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
19 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
20
20
21 share shouldn't have a store dir
21 share shouldn't have a store dir
22
22
23 $ cd repo2
23 $ cd repo2
24 $ test -d .hg/store
24 $ test -d .hg/store
25 [1]
25 [1]
26
26
27 Some sed versions appends newline, some don't, and some just fails
27 Some sed versions appends newline, some don't, and some just fails
28
28
29 $ cat .hg/sharedpath; echo
29 $ cat .hg/sharedpath; echo
30 $TESTTMP/repo1/.hg (glob)
30 $TESTTMP/repo1/.hg (glob)
31
31
32 trailing newline on .hg/sharedpath is ok
32 trailing newline on .hg/sharedpath is ok
33 $ hg tip -q
33 $ hg tip -q
34 0:d3873e73d99e
34 0:d3873e73d99e
35 $ echo '' >> .hg/sharedpath
35 $ echo '' >> .hg/sharedpath
36 $ cat .hg/sharedpath
36 $ cat .hg/sharedpath
37 $TESTTMP/repo1/.hg (glob)
37 $TESTTMP/repo1/.hg (glob)
38 $ hg tip -q
38 $ hg tip -q
39 0:d3873e73d99e
39 0:d3873e73d99e
40
40
41 commit in shared clone
41 commit in shared clone
42
42
43 $ echo a >> a
43 $ echo a >> a
44 $ hg commit -m'change in shared clone'
44 $ hg commit -m'change in shared clone'
45
45
46 check original
46 check original
47
47
48 $ cd ../repo1
48 $ cd ../repo1
49 $ hg log
49 $ hg log
50 changeset: 1:8af4dc49db9e
50 changeset: 1:8af4dc49db9e
51 tag: tip
51 tag: tip
52 user: test
52 user: test
53 date: Thu Jan 01 00:00:00 1970 +0000
53 date: Thu Jan 01 00:00:00 1970 +0000
54 summary: change in shared clone
54 summary: change in shared clone
55
55
56 changeset: 0:d3873e73d99e
56 changeset: 0:d3873e73d99e
57 user: test
57 user: test
58 date: Thu Jan 01 00:00:00 1970 +0000
58 date: Thu Jan 01 00:00:00 1970 +0000
59 summary: init
59 summary: init
60
60
61 $ hg update
61 $ hg update
62 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
62 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
63 $ cat a # should be two lines of "a"
63 $ cat a # should be two lines of "a"
64 a
64 a
65 a
65 a
66
66
67 commit in original
67 commit in original
68
68
69 $ echo b > b
69 $ echo b > b
70 $ hg commit -A -m'another file'
70 $ hg commit -A -m'another file'
71 adding b
71 adding b
72
72
73 check in shared clone
73 check in shared clone
74
74
75 $ cd ../repo2
75 $ cd ../repo2
76 $ hg log
76 $ hg log
77 changeset: 2:c2e0ac586386
77 changeset: 2:c2e0ac586386
78 tag: tip
78 tag: tip
79 user: test
79 user: test
80 date: Thu Jan 01 00:00:00 1970 +0000
80 date: Thu Jan 01 00:00:00 1970 +0000
81 summary: another file
81 summary: another file
82
82
83 changeset: 1:8af4dc49db9e
83 changeset: 1:8af4dc49db9e
84 user: test
84 user: test
85 date: Thu Jan 01 00:00:00 1970 +0000
85 date: Thu Jan 01 00:00:00 1970 +0000
86 summary: change in shared clone
86 summary: change in shared clone
87
87
88 changeset: 0:d3873e73d99e
88 changeset: 0:d3873e73d99e
89 user: test
89 user: test
90 date: Thu Jan 01 00:00:00 1970 +0000
90 date: Thu Jan 01 00:00:00 1970 +0000
91 summary: init
91 summary: init
92
92
93 $ hg update
93 $ hg update
94 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
94 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
95 $ cat b # should exist with one "b"
95 $ cat b # should exist with one "b"
96 b
96 b
97
97
98 hg serve shared clone
98 hg serve shared clone
99
99
100 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid
100 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid
101 $ cat hg.pid >> $DAEMON_PIDS
101 $ cat hg.pid >> $DAEMON_PIDS
102 $ get-with-headers.py localhost:$HGPORT 'raw-file/'
102 $ get-with-headers.py localhost:$HGPORT 'raw-file/'
103 200 Script output follows
103 200 Script output follows
104
104
105
105
106 -rw-r--r-- 4 a
106 -rw-r--r-- 4 a
107 -rw-r--r-- 2 b
107 -rw-r--r-- 2 b
108
108
109
109
110
110
111 test unshare command
111 test unshare command
112
112
113 $ hg unshare
113 $ hg unshare
114 $ test -d .hg/store
114 $ test -d .hg/store
115 $ test -f .hg/sharedpath
115 $ test -f .hg/sharedpath
116 [1]
116 [1]
117 $ hg unshare
117 $ hg unshare
118 abort: this is not a shared repo
118 abort: this is not a shared repo
119 [255]
119 [255]
120
120
121 check that a change does not propagate
121 check that a change does not propagate
122
122
123 $ echo b >> b
123 $ echo b >> b
124 $ hg commit -m'change in unshared'
124 $ hg commit -m'change in unshared'
125 $ cd ../repo1
125 $ cd ../repo1
126 $ hg id -r tip
126 $ hg id -r tip
127 c2e0ac586386 tip
127 c2e0ac586386 tip
128
128
129 $ cd ..
129 $ cd ..
130
130
131
131
132 test sharing bookmarks
132 test sharing bookmarks
133
133
134 $ hg share -B repo1 repo3
134 $ hg share -B repo1 repo3
135 updating working directory
135 updating working directory
136 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
136 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
137 $ cd repo1
137 $ cd repo1
138 $ hg bookmark bm1
138 $ hg bookmark bm1
139 $ hg bookmarks
139 $ hg bookmarks
140 * bm1 2:c2e0ac586386
140 * bm1 2:c2e0ac586386
141 $ cd ../repo2
141 $ cd ../repo2
142 $ hg book bm2
142 $ hg book bm2
143 $ hg bookmarks
143 $ hg bookmarks
144 * bm2 3:0e6e70d1d5f1
144 * bm2 3:0e6e70d1d5f1
145 $ cd ../repo3
145 $ cd ../repo3
146 $ hg bookmarks
146 $ hg bookmarks
147 bm1 2:c2e0ac586386
147 bm1 2:c2e0ac586386
148 $ hg book bm3
148 $ hg book bm3
149 $ hg bookmarks
149 $ hg bookmarks
150 bm1 2:c2e0ac586386
150 bm1 2:c2e0ac586386
151 * bm3 2:c2e0ac586386
151 * bm3 2:c2e0ac586386
152 $ cd ../repo1
152 $ cd ../repo1
153 $ hg bookmarks
153 $ hg bookmarks
154 * bm1 2:c2e0ac586386
154 * bm1 2:c2e0ac586386
155 bm3 2:c2e0ac586386
155 bm3 2:c2e0ac586386
156
156
157 check whether HG_PENDING makes pending changes only in relatd
158 repositories visible to an external hook.
159
160 In "hg share" case, another transaction can't run in other
161 repositories sharing same source repository, because starting
162 transaction requires locking store of source repository.
163
164 Therefore, this test scenario ignores checking visibility of
165 .hg/bookmakrs.pending in repo2, which shares repo1 without bookmarks.
166
167 $ cat > $TESTTMP/checkbookmarks.sh <<EOF
168 > echo "@repo1"
169 > hg -R $TESTTMP/repo1 bookmarks
170 > echo "@repo2"
171 > hg -R $TESTTMP/repo2 bookmarks
172 > echo "@repo3"
173 > hg -R $TESTTMP/repo3 bookmarks
174 > exit 1 # to avoid adding new bookmark for subsequent tests
175 > EOF
176
177 $ cd ../repo1
178 $ hg --config hooks.pretxnclose="sh $TESTTMP/checkbookmarks.sh" -q book bmX
179 @repo1
180 bm1 2:c2e0ac586386
181 bm3 2:c2e0ac586386
182 * bmX 2:c2e0ac586386
183 @repo2
184 * bm2 3:0e6e70d1d5f1
185 @repo3
186 bm1 2:c2e0ac586386
187 * bm3 2:c2e0ac586386
188 bmX 2:c2e0ac586386
189 transaction abort!
190 rollback completed
191 abort: pretxnclose hook exited with status 1
192 [255]
193 $ hg book bm1
194
195 FYI, in contrast to above test, bmX is invisible in repo1 (= shared
196 src), because (1) HG_PENDING refers only repo3 and (2)
197 "bookmarks.pending" is written only into repo3.
198
199 $ cd ../repo3
200 $ hg --config hooks.pretxnclose="sh $TESTTMP/checkbookmarks.sh" -q book bmX
201 @repo1
202 * bm1 2:c2e0ac586386
203 bm3 2:c2e0ac586386
204 @repo2
205 * bm2 3:0e6e70d1d5f1
206 @repo3
207 bm1 2:c2e0ac586386
208 bm3 2:c2e0ac586386
209 * bmX 2:c2e0ac586386
210 transaction abort!
211 rollback completed
212 abort: pretxnclose hook exited with status 1
213 [255]
214 $ hg book bm3
215
216 $ cd ../repo1
217
157 test that commits work
218 test that commits work
158
219
159 $ echo 'shared bookmarks' > a
220 $ echo 'shared bookmarks' > a
160 $ hg commit -m 'testing shared bookmarks'
221 $ hg commit -m 'testing shared bookmarks'
161 $ hg bookmarks
222 $ hg bookmarks
162 * bm1 3:b87954705719
223 * bm1 3:b87954705719
163 bm3 2:c2e0ac586386
224 bm3 2:c2e0ac586386
164 $ cd ../repo3
225 $ cd ../repo3
165 $ hg bookmarks
226 $ hg bookmarks
166 bm1 3:b87954705719
227 bm1 3:b87954705719
167 * bm3 2:c2e0ac586386
228 * bm3 2:c2e0ac586386
168 $ echo 'more shared bookmarks' > a
229 $ echo 'more shared bookmarks' > a
169 $ hg commit -m 'testing shared bookmarks'
230 $ hg commit -m 'testing shared bookmarks'
170 created new head
231 created new head
171 $ hg bookmarks
232 $ hg bookmarks
172 bm1 3:b87954705719
233 bm1 3:b87954705719
173 * bm3 4:62f4ded848e4
234 * bm3 4:62f4ded848e4
174 $ cd ../repo1
235 $ cd ../repo1
175 $ hg bookmarks
236 $ hg bookmarks
176 * bm1 3:b87954705719
237 * bm1 3:b87954705719
177 bm3 4:62f4ded848e4
238 bm3 4:62f4ded848e4
178 $ cd ..
239 $ cd ..
179
240
180 test pushing bookmarks works
241 test pushing bookmarks works
181
242
182 $ hg clone repo3 repo4
243 $ hg clone repo3 repo4
183 updating to branch default
244 updating to branch default
184 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
245 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
185 $ cd repo4
246 $ cd repo4
186 $ hg boo bm4
247 $ hg boo bm4
187 $ echo foo > b
248 $ echo foo > b
188 $ hg commit -m 'foo in b'
249 $ hg commit -m 'foo in b'
189 $ hg boo
250 $ hg boo
190 bm1 3:b87954705719
251 bm1 3:b87954705719
191 bm3 4:62f4ded848e4
252 bm3 4:62f4ded848e4
192 * bm4 5:92793bfc8cad
253 * bm4 5:92793bfc8cad
193 $ hg push -B bm4
254 $ hg push -B bm4
194 pushing to $TESTTMP/repo3 (glob)
255 pushing to $TESTTMP/repo3 (glob)
195 searching for changes
256 searching for changes
196 adding changesets
257 adding changesets
197 adding manifests
258 adding manifests
198 adding file changes
259 adding file changes
199 added 1 changesets with 1 changes to 1 files
260 added 1 changesets with 1 changes to 1 files
200 exporting bookmark bm4
261 exporting bookmark bm4
201 $ cd ../repo1
262 $ cd ../repo1
202 $ hg bookmarks
263 $ hg bookmarks
203 * bm1 3:b87954705719
264 * bm1 3:b87954705719
204 bm3 4:62f4ded848e4
265 bm3 4:62f4ded848e4
205 bm4 5:92793bfc8cad
266 bm4 5:92793bfc8cad
206 $ cd ../repo3
267 $ cd ../repo3
207 $ hg bookmarks
268 $ hg bookmarks
208 bm1 3:b87954705719
269 bm1 3:b87954705719
209 * bm3 4:62f4ded848e4
270 * bm3 4:62f4ded848e4
210 bm4 5:92793bfc8cad
271 bm4 5:92793bfc8cad
211 $ cd ..
272 $ cd ..
212
273
213 test behavior when sharing a shared repo
274 test behavior when sharing a shared repo
214
275
215 $ hg share -B repo3 repo5
276 $ hg share -B repo3 repo5
216 updating working directory
277 updating working directory
217 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
278 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
218 $ cd repo5
279 $ cd repo5
219 $ hg book
280 $ hg book
220 bm1 3:b87954705719
281 bm1 3:b87954705719
221 bm3 4:62f4ded848e4
282 bm3 4:62f4ded848e4
222 bm4 5:92793bfc8cad
283 bm4 5:92793bfc8cad
223 $ cd ..
284 $ cd ..
224
285
225 test what happens when an active bookmark is deleted
286 test what happens when an active bookmark is deleted
226
287
227 $ cd repo1
288 $ cd repo1
228 $ hg boo -d bm3
289 $ hg boo -d bm3
229 $ hg boo
290 $ hg boo
230 * bm1 3:b87954705719
291 * bm1 3:b87954705719
231 bm4 5:92793bfc8cad
292 bm4 5:92793bfc8cad
232 $ cd ../repo3
293 $ cd ../repo3
233 $ hg boo
294 $ hg boo
234 bm1 3:b87954705719
295 bm1 3:b87954705719
235 bm4 5:92793bfc8cad
296 bm4 5:92793bfc8cad
236 $ cd ..
297 $ cd ..
237
298
238 verify that bookmarks are not written on failed transaction
299 verify that bookmarks are not written on failed transaction
239
300
240 $ cat > failpullbookmarks.py << EOF
301 $ cat > failpullbookmarks.py << EOF
241 > """A small extension that makes bookmark pulls fail, for testing"""
302 > """A small extension that makes bookmark pulls fail, for testing"""
242 > from mercurial import extensions, exchange, error
303 > from mercurial import extensions, exchange, error
243 > def _pullbookmarks(orig, pullop):
304 > def _pullbookmarks(orig, pullop):
244 > orig(pullop)
305 > orig(pullop)
245 > raise error.HookAbort('forced failure by extension')
306 > raise error.HookAbort('forced failure by extension')
246 > def extsetup(ui):
307 > def extsetup(ui):
247 > extensions.wrapfunction(exchange, '_pullbookmarks', _pullbookmarks)
308 > extensions.wrapfunction(exchange, '_pullbookmarks', _pullbookmarks)
248 > EOF
309 > EOF
249 $ cd repo4
310 $ cd repo4
250 $ hg boo
311 $ hg boo
251 bm1 3:b87954705719
312 bm1 3:b87954705719
252 bm3 4:62f4ded848e4
313 bm3 4:62f4ded848e4
253 * bm4 5:92793bfc8cad
314 * bm4 5:92793bfc8cad
254 $ cd ../repo3
315 $ cd ../repo3
255 $ hg boo
316 $ hg boo
256 bm1 3:b87954705719
317 bm1 3:b87954705719
257 bm4 5:92793bfc8cad
318 bm4 5:92793bfc8cad
258 $ hg --config "extensions.failpullbookmarks=$TESTTMP/failpullbookmarks.py" pull $TESTTMP/repo4
319 $ hg --config "extensions.failpullbookmarks=$TESTTMP/failpullbookmarks.py" pull $TESTTMP/repo4
259 pulling from $TESTTMP/repo4 (glob)
320 pulling from $TESTTMP/repo4 (glob)
260 searching for changes
321 searching for changes
261 no changes found
322 no changes found
262 adding remote bookmark bm3
323 adding remote bookmark bm3
263 abort: forced failure by extension
324 abort: forced failure by extension
264 [255]
325 [255]
265 $ hg boo
326 $ hg boo
266 bm1 3:b87954705719
327 bm1 3:b87954705719
267 bm4 5:92793bfc8cad
328 bm4 5:92793bfc8cad
268 $ hg pull $TESTTMP/repo4
329 $ hg pull $TESTTMP/repo4
269 pulling from $TESTTMP/repo4 (glob)
330 pulling from $TESTTMP/repo4 (glob)
270 searching for changes
331 searching for changes
271 no changes found
332 no changes found
272 adding remote bookmark bm3
333 adding remote bookmark bm3
273 $ hg boo
334 $ hg boo
274 bm1 3:b87954705719
335 bm1 3:b87954705719
275 * bm3 4:62f4ded848e4
336 * bm3 4:62f4ded848e4
276 bm4 5:92793bfc8cad
337 bm4 5:92793bfc8cad
277 $ cd ..
338 $ cd ..
278
339
279 verify bookmark behavior after unshare
340 verify bookmark behavior after unshare
280
341
281 $ cd repo3
342 $ cd repo3
282 $ hg unshare
343 $ hg unshare
283 $ hg boo
344 $ hg boo
284 bm1 3:b87954705719
345 bm1 3:b87954705719
285 * bm3 4:62f4ded848e4
346 * bm3 4:62f4ded848e4
286 bm4 5:92793bfc8cad
347 bm4 5:92793bfc8cad
287 $ hg boo -d bm4
348 $ hg boo -d bm4
288 $ hg boo bm5
349 $ hg boo bm5
289 $ hg boo
350 $ hg boo
290 bm1 3:b87954705719
351 bm1 3:b87954705719
291 bm3 4:62f4ded848e4
352 bm3 4:62f4ded848e4
292 * bm5 4:62f4ded848e4
353 * bm5 4:62f4ded848e4
293 $ cd ../repo1
354 $ cd ../repo1
294 $ hg boo
355 $ hg boo
295 * bm1 3:b87954705719
356 * bm1 3:b87954705719
296 bm3 4:62f4ded848e4
357 bm3 4:62f4ded848e4
297 bm4 5:92793bfc8cad
358 bm4 5:92793bfc8cad
298 $ cd ..
359 $ cd ..
299
360
300 Explicitly kill daemons to let the test exit on Windows
361 Explicitly kill daemons to let the test exit on Windows
301
362
302 $ killdaemons.py
363 $ killdaemons.py
303
364
General Comments 0
You need to be logged in to leave comments. Login now