##// END OF EJS Templates
merge bookmarks
Benoit Boissinot -
r7318:95e1260b merge default
parent child Browse files
Show More
@@ -0,0 +1,38 b''
1 #!/bin/sh
2
3 echo "[extensions]" >> $HGRCPATH
4 echo "rebase=" >> $HGRCPATH
5 echo "bookmarks=" >> $HGRCPATH
6
7 cleanoutput () {
8 sed -e 's/\(Rebase status stored to\).*/\1/' \
9 -e 's/\(Rebase status restored from\).*/\1/' \
10 -e 's/\(saving bundle to \).*/\1/'
11 }
12
13 echo % initialize repository
14 hg init
15
16 echo 'a' > a
17 hg ci -A -d '0 0' -u test -m "0"
18
19 echo 'b' > b
20 hg ci -A -d '0 0' -u test -m "1"
21
22 hg up 0
23 echo 'c' > c
24 hg ci -A -d '0 0' -u test -m "2"
25
26 echo 'd' > d
27 hg ci -A -d '0 0' -u test -m "3"
28
29 hg bookmark -r 1 one
30 hg bookmark -r 3 two
31
32 echo % bookmark list
33 hg bookmark
34
35 echo % rebase
36 hg rebase -s two -d one 2>&1 | cleanoutput
37
38 hg log No newline at end of file
@@ -0,0 +1,42 b''
1 % initialize repository
2 adding a
3 adding b
4 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
5 adding c
6 created new head
7 adding d
8 % bookmark list
9 * two 3:2ae46b1d99a7
10 one 1:925d80f479bb
11 % rebase
12 saving bundle to
13 adding branch
14 adding changesets
15 adding manifests
16 adding file changes
17 added 1 changesets with 1 changes to 1 files (-1 heads)
18 rebase completed
19 changeset: 3:9163974d1cb5
20 tag: tip
21 parent: 1:925d80f479bb
22 parent: 2:db815d6d32e6
23 user: test
24 date: Thu Jan 01 00:00:00 1970 +0000
25 summary: 3
26
27 changeset: 2:db815d6d32e6
28 parent: 0:f7b1eb17ad24
29 user: test
30 date: Thu Jan 01 00:00:00 1970 +0000
31 summary: 2
32
33 changeset: 1:925d80f479bb
34 user: test
35 date: Thu Jan 01 00:00:00 1970 +0000
36 summary: 1
37
38 changeset: 0:f7b1eb17ad24
39 user: test
40 date: Thu Jan 01 00:00:00 1970 +0000
41 summary: 0
42
@@ -0,0 +1,44 b''
1 #!/bin/sh
2
3 echo "[extensions]" >> $HGRCPATH
4 echo "bookmarks=" >> $HGRCPATH
5 echo "mq=" >> $HGRCPATH
6
7 hg init
8
9 echo qqq>qqq.txt
10
11 echo % add file
12 hg add
13
14 echo % commit first revision
15 hg ci -m 1 -u user -d "1 0"
16
17 echo % set bookmark
18 hg book test
19
20 echo www>>qqq.txt
21
22 echo % commit second revision
23 hg ci -m 2 -u usr -d "1 0"
24
25 echo % set bookmark
26 hg book test2
27
28 echo % update to -2
29 hg update -r -2
30
31 echo eee>>qqq.txt
32
33 echo % commit new head
34 hg ci -m 3 -u user -d "1 0"
35
36 echo % bookmarks updated?
37 hg book
38
39 echo % strip to revision 1
40 hg strip 1 2>&1 | sed 's/\(saving bundle to \).*/\1/'
41
42 echo % list bookmarks
43 hg book
44
@@ -0,0 +1,24 b''
1 % add file
2 adding qqq.txt
3 % commit first revision
4 % set bookmark
5 % commit second revision
6 % set bookmark
7 % update to -2
8 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
9 % commit new head
10 created new head
11 % bookmarks updated?
12 test 1:16b24da7e457
13 test2 1:16b24da7e457
14 % strip to revision 1
15 saving bundle to
16 saving bundle to
17 adding branch
18 adding changesets
19 adding manifests
20 adding file changes
21 added 1 changesets with 1 changes to 1 files
22 % list bookmarks
23 * test 1:9f1b7e78eff8
24 * test2 1:9f1b7e78eff8
@@ -1,234 +1,231 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 nullid, 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 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
71 71 tip with the given name. If you specify a revision using -r REV
72 72 (where REV may be an existing bookmark), the bookmark is set to
73 73 that revision.
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 79 if rename:
80 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 86 marks[mark] = marks[rename]
87 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 "\n" in mark:
102 102 raise util.Abort(_("bookmark name cannot contain newlines"))
103 103 mark = mark.strip()
104 104 if mark in marks and not force:
105 105 raise util.Abort(_("a bookmark of the same name already exists"))
106 106 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
107 107 and not force):
108 108 raise util.Abort(
109 109 _("a bookmark cannot have the name of an existing branch"))
110 110 if rev:
111 111 marks[mark] = repo.lookup(rev)
112 112 else:
113 113 marks[mark] = repo.changectx('.').node()
114 114 write(repo, marks)
115 115 return
116 116
117 117 if mark == None:
118 118 if rev:
119 119 raise util.Abort(_("bookmark name required"))
120 120 if len(marks) == 0:
121 121 ui.status("no bookmarks set\n")
122 122 else:
123 123 for bmark, n in marks.iteritems():
124 124 prefix = (n == cur) and '*' or ' '
125 125 ui.write(" %s %-25s %d:%s\n" % (
126 126 prefix, bmark, repo.changelog.rev(n), hexfn(n)))
127 127 return
128 128
129 129 def _revstostrip(changelog, node):
130 130 srev = changelog.rev(node)
131 131 tostrip = [srev]
132 132 saveheads = []
133 133 for r in xrange(srev, len(changelog)):
134 134 parents = changelog.parentrevs(r)
135 135 if parents[0] in tostrip or parents[1] in tostrip:
136 136 tostrip.append(r)
137 137 if parents[1] != nullrev:
138 138 for p in parents:
139 139 if p not in tostrip and p > srev:
140 140 saveheads.append(p)
141 141 return [r for r in tostrip if r not in saveheads]
142 142
143 143 def strip(ui, repo, node, backup="all"):
144 144 """Strip bookmarks if revisions are stripped using
145 145 the mercurial.strip method. This usually happens during
146 146 qpush and qpop"""
147 147 revisions = _revstostrip(repo.changelog, node)
148 148 marks = parse(repo)
149 149 update = []
150 150 for mark, n in marks.items():
151 151 if repo.changelog.rev(n) in revisions:
152 152 update.append(mark)
153 153 oldstrip(ui, repo, node, backup)
154 154 if len(update) > 0:
155 155 for m in update:
156 156 marks[m] = repo.changectx('.').node()
157 157 write(repo, marks)
158 158
159 159 oldstrip = mercurial.repair.strip
160 160 mercurial.repair.strip = strip
161 161
162 162 def reposetup(ui, repo):
163 163 if not isinstance(repo, mercurial.localrepo.localrepository):
164 164 return
165 165
166 166 # init a bookmark cache as otherwise we would get a infinite reading
167 167 # in lookup()
168 168 repo._bookmarks = None
169 169
170 170 class bookmark_repo(repo.__class__):
171 171 def rollback(self):
172 172 if os.path.exists(self.join('undo.bookmarks')):
173 173 util.rename(self.join('undo.bookmarks'), self.join('bookmarks'))
174 174 return super(bookmark_repo, self).rollback()
175 175
176 176 def lookup(self, key):
177 177 if self._bookmarks is None:
178 178 self._bookmarks = parse(self)
179 179 if key in self._bookmarks:
180 180 key = self._bookmarks[key]
181 181 return super(bookmark_repo, self).lookup(key)
182 182
183 183 def commit(self, *k, **kw):
184 184 """Add a revision to the repository and
185 185 move the bookmark"""
186 186 node = super(bookmark_repo, self).commit(*k, **kw)
187 187 if node == None:
188 188 return None
189 189 parents = repo.changelog.parents(node)
190 190 if parents[1] == nullid:
191 191 parents = (parents[0],)
192 192 marks = parse(repo)
193 193 update = False
194 194 for mark, n in marks.items():
195 195 if n in parents:
196 196 marks[mark] = node
197 197 update = True
198 198 if update:
199 199 write(repo, marks)
200 200 return node
201 201
202 202 def addchangegroup(self, source, srctype, url, emptyok=False):
203 try:
204 onode = repo.changectx('.').node()
205 except RepoError, inst:
206 pass
203 parents = repo.dirstate.parents()
207 204
208 205 result = super(bookmark_repo, self).addchangegroup(
209 206 source, srctype, url, emptyok)
210 207 if result > 1:
211 208 # We have more heads than before
212 209 return result
213 210 node = repo.changelog.tip()
214 211 marks = parse(repo)
215 212 update = False
216 213 for mark, n in marks.items():
217 if n == onode:
214 if n in parents:
218 215 marks[mark] = node
219 216 update = True
220 217 if update:
221 218 write(repo, marks)
222 219 return result
223 220
224 221 repo.__class__ = bookmark_repo
225 222
226 223 cmdtable = {
227 224 "bookmarks":
228 225 (bookmark,
229 226 [('f', 'force', False, _('force')),
230 227 ('r', 'rev', '', _('revision')),
231 228 ('d', 'delete', False, _('delete a given bookmark')),
232 229 ('m', 'rename', '', _('rename a given bookmark'))],
233 230 _('hg bookmarks [-d] [-m NAME] [-r NAME] [NAME]')),
234 231 }
General Comments 0
You need to be logged in to leave comments. Login now