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