##// END OF EJS Templates
bookmarks: Rename --move to --rename...
Joel Rosdahl -
r7255:69e431ea default
parent child Browse files
Show More
@@ -1,227 +1,227 b''
1 1 # Mercurial extension to provide the 'hg bookmark' command
2 2 #
3 3 # Copyright 2008 David Soria Parra <dsp@php.net>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 '''mercurial bookmarks
9 9
10 10 Mercurial bookmarks are local moveable pointers to changesets. Every
11 11 bookmark points to a changeset identified by its hash. If you commit a
12 12 changeset that is based on a changeset that has a bookmark on it, the
13 13 bookmark is forwarded to the new changeset.
14 14
15 15 It is possible to use bookmark names in every revision lookup (e.g. hg
16 16 merge, hg update).
17 17 '''
18 18
19 19 from mercurial.commands import templateopts, hex, short
20 20 from mercurial.i18n import _
21 21 from mercurial import cmdutil, util, commands, changelog
22 22 from mercurial.node import nullrev
23 23 from mercurial.repo import RepoError
24 24 import mercurial, mercurial.localrepo, mercurial.repair, os
25 25
26 26 def parse(repo):
27 27 '''Parse .hg/bookmarks file and return a dictionary
28 28
29 29 Bookmarks are stored as {HASH}\s{NAME}\n (localtags format) values
30 30 in the .hg/bookmarks file. They are read by the parse() method and
31 31 returned as a dictionary with name => hash values.
32 32
33 33 The parsed dictionary is cached until a write() operation is done.
34 34 '''
35 35 try:
36 36 if repo._bookmarks:
37 37 return repo._bookmarks
38 38 repo._bookmarks = {}
39 39 for line in repo.opener('bookmarks'):
40 40 sha, refspec = line.strip().split(' ', 1)
41 41 repo._bookmarks[refspec] = repo.lookup(sha)
42 42 except:
43 43 pass
44 44 return repo._bookmarks
45 45
46 46 def write(repo, refs):
47 47 '''Write bookmarks
48 48
49 49 Write the given bookmark => hash dictionary to the .hg/bookmarks file
50 50 in a format equal to those of localtags.
51 51
52 52 We also store a backup of the previous state in undo.bookmarks that
53 53 can be copied back on rollback.
54 54 '''
55 55 if os.path.exists(repo.join('bookmarks')):
56 56 util.copyfile(repo.join('bookmarks'), repo.join('undo.bookmarks'))
57 57 file = repo.opener('bookmarks', 'w+')
58 58 for refspec, node in refs.items():
59 59 file.write("%s %s\n" % (hex(node), refspec))
60 60 file.close()
61 61
62 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, move=None):
62 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, rename=None):
63 63 '''mercurial bookmarks
64 64
65 65 Bookmarks are pointers to certain commits that move when
66 66 commiting. Bookmarks are local. They can be renamed, copied and
67 67 deleted. It is possible to use bookmark names in 'hg merge' and 'hg
68 68 update' to update to a given bookmark.
69 69
70 70 You can use 'hg bookmark [NAME]' to set a bookmark on the current tip
71 71 with the given name. If you specify a second [NAME] the bookmark is
72 72 set to the bookmark that has that name. You can also pass revision
73 73 identifiers to set bookmarks too.
74 74 '''
75 75 hexfn = ui.debugflag and hex or short
76 76 marks = parse(repo)
77 77 cur = repo.changectx('.').node()
78 78
79 if move:
80 if move not in marks:
79 if rename:
80 if rename not in marks:
81 81 raise util.Abort(_("a bookmark of this name does not exist"))
82 82 if mark in marks and not force:
83 83 raise util.Abort(_("a bookmark of the same name already exists"))
84 84 if mark is None:
85 85 raise util.Abort(_("new bookmark name required"))
86 marks[mark] = marks[move]
87 del marks[move]
86 marks[mark] = marks[rename]
87 del marks[rename]
88 88 write(repo, marks)
89 89 return
90 90
91 91 if delete:
92 92 if mark == None:
93 93 raise util.Abort(_("bookmark name required"))
94 94 if mark not in marks:
95 95 raise util.Abort(_("a bookmark of this name does not exist"))
96 96 del marks[mark]
97 97 write(repo, marks)
98 98 return
99 99
100 100 if mark != None:
101 101 if mark.strip().count("\n") > 0:
102 102 raise Exception("bookmark cannot contain newlines")
103 103 if mark in marks and not force:
104 104 raise util.Abort(_("a bookmark of the same name already exists"))
105 105 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
106 106 and not force):
107 107 raise util.Abort(
108 108 _("a bookmark cannot have the name of an existing branch"))
109 109 if rev:
110 110 marks[mark] = repo.lookup(rev)
111 111 else:
112 112 marks[mark] = repo.changectx('.').node()
113 113 write(repo, marks)
114 114 return
115 115
116 116 if mark == None:
117 117 if len(marks) == 0:
118 118 ui.status("no bookmarks set\n")
119 119 else:
120 120 for bmark, n in marks.iteritems():
121 121 prefix = (n == cur) and '*' or ' '
122 122 ui.write(" %s %-25s %d:%s\n" % (
123 123 prefix, bmark, repo.changelog.rev(n), hexfn(n)))
124 124 return
125 125
126 126 def _revstostrip(changelog, node):
127 127 srev = changelog.rev(node)
128 128 tostrip = [srev]
129 129 saveheads = []
130 130 for r in xrange(srev, changelog.rev(changelog.tip()) + 1):
131 131 parents = changelog.parentrevs(r)
132 132 if parents[0] in tostrip or parents[1] in tostrip:
133 133 tostrip.append(r)
134 134 if parents[1] != nullrev:
135 135 for p in parents:
136 136 if p not in tostrip and p > striprev:
137 137 saveheads.append(p)
138 138 return [r for r in tostrip if r not in saveheads]
139 139
140 140 def strip(ui, repo, node, backup="all"):
141 141 """Strip bookmarks if revisions are stripped using
142 142 the mercurial.strip method. This usually happens during
143 143 qpush and qpop"""
144 144 revisions = _revstostrip(repo.changelog, node)
145 145 marks = parse(repo)
146 146 update = []
147 147 for mark, n in marks.items():
148 148 if repo.changelog.rev(n) in revisions:
149 149 update.append(mark)
150 150 result = oldstrip(ui, repo, node, backup)
151 151 if len(update) > 0:
152 152 for m in update:
153 153 marks[m] = repo.changectx('.').node()
154 154 write(repo, marks)
155 155
156 156 oldstrip = mercurial.repair.strip
157 157 mercurial.repair.strip = strip
158 158
159 159 def reposetup(ui, repo):
160 160 if not isinstance(repo, mercurial.localrepo.localrepository):
161 161 return
162 162
163 163 # init a bookmark cache as otherwise we would get a infinite reading
164 164 # in lookup()
165 165 repo._bookmarks = None
166 166
167 167 class bookmark_repo(repo.__class__):
168 168 def rollback(self):
169 169 if os.path.exists(self.join('undo.bookmarks')):
170 170 util.rename(self.join('undo.bookmarks'), self.join('bookmarks'))
171 171 return super(bookmark_repo, self).rollback()
172 172
173 173 def lookup(self, key):
174 174 if self._bookmarks is None:
175 175 self._bookmarks = parse(self)
176 176 if key in self._bookmarks:
177 177 key = self._bookmarks[key]
178 178 return super(bookmark_repo, self).lookup(key)
179 179
180 180 def commit(self, *k, **kw):
181 181 """Add a revision to the repository and
182 182 move the bookmark"""
183 183 node = super(bookmark_repo, self).commit(*k, **kw)
184 184 parents = repo.changelog.parents(node)
185 185 marks = parse(repo)
186 186 update = False
187 187 for mark, n in marks.items():
188 188 if n in parents:
189 189 marks[mark] = node
190 190 update = True
191 191 if update:
192 192 write(repo, marks)
193 193 return node
194 194
195 195 def addchangegroup(self, source, srctype, url, emptyok=False):
196 196 try:
197 197 onode = repo.changectx('.').node()
198 198 except RepoError, inst:
199 199 pass
200 200
201 201 result = super(bookmark_repo, self).addchangegroup(
202 202 source, srctype, url, emptyok)
203 203 if result > 1:
204 204 # We have more heads than before
205 205 return result
206 206 node = repo.changelog.tip()
207 207 marks = parse(repo)
208 208 update = False
209 209 for mark, n in marks.items():
210 210 if n == onode:
211 211 marks[mark] = node
212 212 update = True
213 213 if update:
214 214 write(repo, marks)
215 215 return result
216 216
217 217 repo.__class__ = bookmark_repo
218 218
219 219 cmdtable = {
220 220 "bookmarks":
221 221 (bookmark,
222 222 [('f', 'force', False, _('force')),
223 223 ('r', 'rev', '', _('revision')),
224 224 ('d', 'delete', False, _('delete a given bookmark')),
225 ('m', 'move', '', _('move a given bookmark'))],
225 ('m', 'rename', '', _('rename a given bookmark'))],
226 226 _('hg bookmarks [-d] [-m NAME] [-r NAME] [NAME]')),
227 227 }
General Comments 0
You need to be logged in to leave comments. Login now