##// END OF EJS Templates
checkheads: take future obsoleted heads into account...
Pierre-Yves David -
r17214:738ad56d default
parent child Browse files
Show More
@@ -1,345 +1,372 b''
1 1 # discovery.py - protocol changeset discovery functions
2 2 #
3 3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from node import nullid, short
9 9 from i18n import _
10 import util, setdiscovery, treediscovery, phases
10 import util, setdiscovery, treediscovery, phases, obsolete
11 11
12 12 def findcommonincoming(repo, remote, heads=None, force=False):
13 13 """Return a tuple (common, anyincoming, heads) used to identify the common
14 14 subset of nodes between repo and remote.
15 15
16 16 "common" is a list of (at least) the heads of the common subset.
17 17 "anyincoming" is testable as a boolean indicating if any nodes are missing
18 18 locally. If remote does not support getbundle, this actually is a list of
19 19 roots of the nodes that would be incoming, to be supplied to
20 20 changegroupsubset. No code except for pull should be relying on this fact
21 21 any longer.
22 22 "heads" is either the supplied heads, or else the remote's heads.
23 23
24 24 If you pass heads and they are all known locally, the reponse lists justs
25 25 these heads in "common" and in "heads".
26 26
27 27 Please use findcommonoutgoing to compute the set of outgoing nodes to give
28 28 extensions a good hook into outgoing.
29 29 """
30 30
31 31 if not remote.capable('getbundle'):
32 32 return treediscovery.findcommonincoming(repo, remote, heads, force)
33 33
34 34 if heads:
35 35 allknown = True
36 36 nm = repo.changelog.nodemap
37 37 for h in heads:
38 38 if nm.get(h) is None:
39 39 allknown = False
40 40 break
41 41 if allknown:
42 42 return (heads, False, heads)
43 43
44 44 res = setdiscovery.findcommonheads(repo.ui, repo, remote,
45 45 abortwhenunrelated=not force)
46 46 common, anyinc, srvheads = res
47 47 return (list(common), anyinc, heads or list(srvheads))
48 48
49 49 class outgoing(object):
50 50 '''Represents the set of nodes present in a local repo but not in a
51 51 (possibly) remote one.
52 52
53 53 Members:
54 54
55 55 missing is a list of all nodes present in local but not in remote.
56 56 common is a list of all nodes shared between the two repos.
57 57 excluded is the list of missing changeset that shouldn't be sent remotely.
58 58 missingheads is the list of heads of missing.
59 59 commonheads is the list of heads of common.
60 60
61 61 The sets are computed on demand from the heads, unless provided upfront
62 62 by discovery.'''
63 63
64 64 def __init__(self, revlog, commonheads, missingheads):
65 65 self.commonheads = commonheads
66 66 self.missingheads = missingheads
67 67 self._revlog = revlog
68 68 self._common = None
69 69 self._missing = None
70 70 self.excluded = []
71 71
72 72 def _computecommonmissing(self):
73 73 sets = self._revlog.findcommonmissing(self.commonheads,
74 74 self.missingheads)
75 75 self._common, self._missing = sets
76 76
77 77 @util.propertycache
78 78 def common(self):
79 79 if self._common is None:
80 80 self._computecommonmissing()
81 81 return self._common
82 82
83 83 @util.propertycache
84 84 def missing(self):
85 85 if self._missing is None:
86 86 self._computecommonmissing()
87 87 return self._missing
88 88
89 89 def findcommonoutgoing(repo, other, onlyheads=None, force=False,
90 90 commoninc=None, portable=False):
91 91 '''Return an outgoing instance to identify the nodes present in repo but
92 92 not in other.
93 93
94 94 If onlyheads is given, only nodes ancestral to nodes in onlyheads
95 95 (inclusive) are included. If you already know the local repo's heads,
96 96 passing them in onlyheads is faster than letting them be recomputed here.
97 97
98 98 If commoninc is given, it must the the result of a prior call to
99 99 findcommonincoming(repo, other, force) to avoid recomputing it here.
100 100
101 101 If portable is given, compute more conservative common and missingheads,
102 102 to make bundles created from the instance more portable.'''
103 103 # declare an empty outgoing object to be filled later
104 104 og = outgoing(repo.changelog, None, None)
105 105
106 106 # get common set if not provided
107 107 if commoninc is None:
108 108 commoninc = findcommonincoming(repo, other, force=force)
109 109 og.commonheads, _any, _hds = commoninc
110 110
111 111 # compute outgoing
112 112 mayexclude = (repo._phasecache.phaseroots[phases.secret] or repo.obsstore)
113 113 if not mayexclude:
114 114 og.missingheads = onlyheads or repo.heads()
115 115 elif onlyheads is None:
116 116 # use visible heads as it should be cached
117 117 og.missingheads = visibleheads(repo)
118 118 # extinct changesets are silently ignored
119 119 og.excluded = [ctx.node() for ctx in repo.set('secret()')]
120 120 else:
121 121 # compute common, missing and exclude secret stuff
122 122 sets = repo.changelog.findcommonmissing(og.commonheads, onlyheads)
123 123 og._common, allmissing = sets
124 124 og._missing = missing = []
125 125 og.excluded = excluded = []
126 126 for node in allmissing:
127 127 ctx = repo[node]
128 128 if not ctx.extinct():
129 129 # extinct changesets are silently ignored
130 130 if ctx.phase() >= phases.secret:
131 131 excluded.append(node)
132 132 else:
133 133 missing.append(node)
134 134 if len(missing) == len(allmissing):
135 135 missingheads = onlyheads
136 136 else: # update missing heads
137 137 missingheads = phases.newheads(repo, onlyheads, excluded)
138 138 og.missingheads = missingheads
139 139 if portable:
140 140 # recompute common and missingheads as if -r<rev> had been given for
141 141 # each head of missing, and --base <rev> for each head of the proper
142 142 # ancestors of missing
143 143 og._computecommonmissing()
144 144 cl = repo.changelog
145 145 missingrevs = set(cl.rev(n) for n in og._missing)
146 146 og._common = set(cl.ancestors(missingrevs)) - missingrevs
147 147 commonheads = set(og.commonheads)
148 148 og.missingheads = [h for h in og.missingheads if h not in commonheads]
149 149
150 150 return og
151 151
152 152 def _headssummary(repo, remote, outgoing):
153 153 """compute a summary of branch and heads status before and after push
154 154
155 155 return {'branch': ([remoteheads], [newheads], [unsyncedheads])} mapping
156 156
157 157 - branch: the branch name
158 158 - remoteheads: the list of remote heads known locally
159 159 None is the branch is new
160 160 - newheads: the new remote heads (known locally) with outgoing pushed
161 161 - unsyncedheads: the list of remote heads unknown locally.
162 162 """
163 163 cl = repo.changelog
164 164 headssum = {}
165 165 # A. Create set of branches involved in the push.
166 166 branches = set(repo[n].branch() for n in outgoing.missing)
167 167 remotemap = remote.branchmap()
168 168 newbranches = branches - set(remotemap)
169 169 branches.difference_update(newbranches)
170 170
171 171 # A. register remote heads
172 172 remotebranches = set()
173 173 for branch, heads in remote.branchmap().iteritems():
174 174 remotebranches.add(branch)
175 175 known = []
176 176 unsynced = []
177 177 for h in heads:
178 178 if h in cl.nodemap:
179 179 known.append(h)
180 180 else:
181 181 unsynced.append(h)
182 182 headssum[branch] = (known, list(known), unsynced)
183 183 # B. add new branch data
184 184 missingctx = list(repo[n] for n in outgoing.missing)
185 185 touchedbranches = set()
186 186 for ctx in missingctx:
187 187 branch = ctx.branch()
188 188 touchedbranches.add(branch)
189 189 if branch not in headssum:
190 190 headssum[branch] = (None, [], [])
191 191
192 192 # C drop data about untouched branches:
193 193 for branch in remotebranches - touchedbranches:
194 194 del headssum[branch]
195 195
196 196 # D. Update newmap with outgoing changes.
197 197 # This will possibly add new heads and remove existing ones.
198 198 newmap = dict((branch, heads[1]) for branch, heads in headssum.iteritems()
199 199 if heads[0] is not None)
200 200 repo._updatebranchcache(newmap, missingctx)
201 201 for branch, newheads in newmap.iteritems():
202 202 headssum[branch][1][:] = newheads
203 203 return headssum
204 204
205 205 def _oldheadssummary(repo, remoteheads, outgoing, inc=False):
206 206 """Compute branchmapsummary for repo without branchmap support"""
207 207
208 208 cl = repo.changelog
209 209 # 1-4b. old servers: Check for new topological heads.
210 210 # Construct {old,new}map with branch = None (topological branch).
211 211 # (code based on _updatebranchcache)
212 212 oldheads = set(h for h in remoteheads if h in cl.nodemap)
213 213 # all nodes in outgoing.missing are children of either:
214 214 # - an element of oldheads
215 215 # - another element of outgoing.missing
216 216 # - nullrev
217 217 # This explains why the new head are very simple to compute.
218 218 r = repo.set('heads(%ln + %ln)', oldheads, outgoing.missing)
219 219 newheads = list(c.node() for c in r)
220 220 unsynced = inc and set([None]) or set()
221 221 return {None: (oldheads, newheads, unsynced)}
222 222
223 223 def checkheads(repo, remote, outgoing, remoteheads, newbranch=False, inc=False):
224 224 """Check that a push won't add any outgoing head
225 225
226 226 raise Abort error and display ui message as needed.
227 227 """
228 228 # Check for each named branch if we're creating new remote heads.
229 229 # To be a remote head after push, node must be either:
230 230 # - unknown locally
231 231 # - a local outgoing head descended from update
232 232 # - a remote head that's known locally and not
233 233 # ancestral to an outgoing head
234 234 if remoteheads == [nullid]:
235 235 # remote is empty, nothing to check.
236 236 return
237 237
238 238 if remote.capable('branchmap'):
239 239 headssum = _headssummary(repo, remote, outgoing)
240 240 else:
241 241 headssum = _oldheadssummary(repo, remoteheads, outgoing, inc)
242 242 newbranches = [branch for branch, heads in headssum.iteritems()
243 243 if heads[0] is None]
244 244 # 1. Check for new branches on the remote.
245 245 if newbranches and not newbranch: # new branch requires --new-branch
246 246 branchnames = ', '.join(sorted(newbranches))
247 247 raise util.Abort(_("push creates new remote branches: %s!")
248 248 % branchnames,
249 249 hint=_("use 'hg push --new-branch' to create"
250 250 " new remote branches"))
251 251
252 252 # 2 compute newly pushed bookmarks. We
253 253 # we don't warned about bookmarked heads.
254 254 localbookmarks = repo._bookmarks
255 255 remotebookmarks = remote.listkeys('bookmarks')
256 256 bookmarkedheads = set()
257 257 for bm in localbookmarks:
258 258 rnode = remotebookmarks.get(bm)
259 259 if rnode and rnode in repo:
260 260 lctx, rctx = repo[bm], repo[rnode]
261 261 if rctx == lctx.ancestor(rctx):
262 262 bookmarkedheads.add(lctx.node())
263 263
264 264 # 3. Check for new heads.
265 265 # If there are more heads after the push than before, a suitable
266 266 # error message, depending on unsynced status, is displayed.
267 267 error = None
268 268 unsynced = False
269 allmissing = set(outgoing.missing)
269 270 for branch, heads in headssum.iteritems():
270 271 if heads[0] is None:
271 272 # Maybe we should abort if we push more that one head
272 273 # for new branches ?
273 274 continue
274 275 if heads[2]:
275 276 unsynced = True
276 277 oldhs = set(heads[0])
277 newhs = set(heads[1])
278 candidate_newhs = set(heads[1])
279 # add unsynced data
280 oldhs.update(heads[2])
281 candidate_newhs.update(heads[2])
278 282 dhs = None
283 if repo.obsstore:
284 # remove future heads which are actually obsolete by another
285 # pushed element:
286 #
287 # XXX There is several case this case does not handle properly
288 #
289 # (1) if <nh> is public, it won't be affected by obsolete marker
290 # and a new is created
291 #
292 # (2) if the new heads have ancestors which are not obsolete and
293 # not ancestors of any other heads we will have a new head too.
294 #
295 # This two case will be easy to handle for know changeset but much
296 # more tricky for unsynced changes.
297 newhs = set()
298 for nh in candidate_newhs:
299 for suc in obsolete.anysuccessors(repo.obsstore, nh):
300 if suc != nh and suc in allmissing:
301 break
302 else:
303 newhs.add(nh)
304 else:
305 newhs = candidate_newhs
279 306 if len(newhs) > len(oldhs):
280 307 # strip updates to existing remote heads from the new heads list
281 308 dhs = list(newhs - bookmarkedheads - oldhs)
282 309 if dhs:
283 310 if error is None:
284 311 if branch not in ('default', None):
285 312 error = _("push creates new remote head %s "
286 313 "on branch '%s'!") % (short(dhs[0]), branch)
287 314 else:
288 315 error = _("push creates new remote head %s!"
289 316 ) % short(dhs[0])
290 317 if heads[2]: # unsynced
291 318 hint = _("you should pull and merge or "
292 319 "use push -f to force")
293 320 else:
294 321 hint = _("did you forget to merge? "
295 322 "use push -f to force")
296 323 if branch is not None:
297 324 repo.ui.note(_("new remote heads on branch '%s'\n") % branch)
298 325 for h in dhs:
299 326 repo.ui.note(_("new remote head %s\n") % short(h))
300 327 if error:
301 328 raise util.Abort(error, hint=hint)
302 329
303 330 # 6. Check for unsynced changes on involved branches.
304 331 if unsynced:
305 332 repo.ui.warn(_("note: unsynced remote changes!\n"))
306 333
307 334 def visibleheads(repo):
308 335 """return the set of visible head of this repo"""
309 336 # XXX we want a cache on this
310 337 sroots = repo._phasecache.phaseroots[phases.secret]
311 338 if sroots or repo.obsstore:
312 339 # XXX very slow revset. storing heads or secret "boundary"
313 340 # would help.
314 341 revset = repo.set('heads(not (%ln:: + extinct()))', sroots)
315 342
316 343 vheads = [ctx.node() for ctx in revset]
317 344 if not vheads:
318 345 vheads.append(nullid)
319 346 else:
320 347 vheads = repo.heads()
321 348 return vheads
322 349
323 350
324 351 def visiblebranchmap(repo):
325 352 """return a branchmap for the visible set"""
326 353 # XXX Recomputing this data on the fly is very slow. We should build a
327 354 # XXX cached version while computin the standard branchmap version.
328 355 sroots = repo._phasecache.phaseroots[phases.secret]
329 356 if sroots or repo.obsstore:
330 357 vbranchmap = {}
331 358 for branch, nodes in repo.branchmap().iteritems():
332 359 # search for secret heads.
333 360 for n in nodes:
334 361 if repo[n].phase() >= phases.secret:
335 362 nodes = None
336 363 break
337 364 # if secret heads were found we must compute them again
338 365 if nodes is None:
339 366 s = repo.set('heads(branch(%s) - secret() - extinct())',
340 367 branch)
341 368 nodes = [c.node() for c in s]
342 369 vbranchmap[branch] = nodes
343 370 else:
344 371 vbranchmap = repo.branchmap()
345 372 return vbranchmap
@@ -1,359 +1,406 b''
1 1 $ cat >> $HGRCPATH << EOF
2 2 > [extensions]
3 3 > graphlog=
4 4 > [phases]
5 5 > # public changeset are not obsolete
6 6 > publish=false
7 7 > EOF
8 8 $ mkcommit() {
9 9 > echo "$1" > "$1"
10 10 > hg add "$1"
11 11 > hg ci -m "add $1"
12 12 > }
13 13 $ getid() {
14 14 > hg id --debug -ir "desc('$1')"
15 15 > }
16 16
17 17
18 18 $ hg init tmpa
19 19 $ cd tmpa
20 20
21 21 Killing a single changeset without replacement
22 22
23 23 $ mkcommit kill_me
24 24 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
25 25 $ hg debugobsolete
26 26 97b7c2d76b1845ed3eb988cd612611e72406cef0 0 {'date': '0 0', 'user': 'babar'}
27 27 $ cd ..
28 28
29 29 Killing a single changeset with replacement
30 30
31 31 $ hg init tmpb
32 32 $ cd tmpb
33 33 $ mkcommit a
34 34 $ mkcommit b
35 35 $ mkcommit original_c
36 36 $ hg up "desc('b')"
37 37 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
38 38 $ mkcommit new_c
39 39 created new head
40 40 $ hg debugobsolete `getid original_c` `getid new_c` -d '56 12'
41 41 $ hg debugobsolete
42 42 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
43 43
44 44 do it again (it read the obsstore before adding new changeset)
45 45
46 46 $ hg up '.^'
47 47 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
48 48 $ mkcommit new_2_c
49 49 created new head
50 50 $ hg debugobsolete -d '1337 0' `getid new_c` `getid new_2_c`
51 51 $ hg debugobsolete
52 52 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
53 53 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
54 54
55 55 Register two markers with a missing node
56 56
57 57 $ hg up '.^'
58 58 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
59 59 $ mkcommit new_3_c
60 60 created new head
61 61 $ hg debugobsolete -d '1338 0' `getid new_2_c` 1337133713371337133713371337133713371337
62 62 $ hg debugobsolete -d '1339 0' 1337133713371337133713371337133713371337 `getid new_3_c`
63 63 $ hg debugobsolete
64 64 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
65 65 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
66 66 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
67 67 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
68 68
69 69 Check that graphlog detect that a changeset is obsolete:
70 70
71 71 $ hg glog
72 72 @ changeset: 5:5601fb93a350
73 73 | tag: tip
74 74 | parent: 1:7c3bad9141dc
75 75 | user: test
76 76 | date: Thu Jan 01 00:00:00 1970 +0000
77 77 | summary: add new_3_c
78 78 |
79 79 o changeset: 1:7c3bad9141dc
80 80 | user: test
81 81 | date: Thu Jan 01 00:00:00 1970 +0000
82 82 | summary: add b
83 83 |
84 84 o changeset: 0:1f0dee641bb7
85 85 user: test
86 86 date: Thu Jan 01 00:00:00 1970 +0000
87 87 summary: add a
88 88
89 89
90 90 Check that public changeset are not accounted as obsolete:
91 91
92 92 $ hg phase --public 2
93 93 $ hg --config 'extensions.graphlog=' glog
94 94 @ changeset: 5:5601fb93a350
95 95 | tag: tip
96 96 | parent: 1:7c3bad9141dc
97 97 | user: test
98 98 | date: Thu Jan 01 00:00:00 1970 +0000
99 99 | summary: add new_3_c
100 100 |
101 101 | o changeset: 2:245bde4270cd
102 102 |/ user: test
103 103 | date: Thu Jan 01 00:00:00 1970 +0000
104 104 | summary: add original_c
105 105 |
106 106 o changeset: 1:7c3bad9141dc
107 107 | user: test
108 108 | date: Thu Jan 01 00:00:00 1970 +0000
109 109 | summary: add b
110 110 |
111 111 o changeset: 0:1f0dee641bb7
112 112 user: test
113 113 date: Thu Jan 01 00:00:00 1970 +0000
114 114 summary: add a
115 115
116 116
117 117 $ cd ..
118 118
119 119 Exchange Test
120 120 ============================
121 121
122 122 Destination repo does not have any data
123 123 ---------------------------------------
124 124
125 125 Try to pull markers
126 126 (extinct changeset are excluded but marker are pushed)
127 127
128 128 $ hg init tmpc
129 129 $ cd tmpc
130 130 $ hg pull ../tmpb
131 131 pulling from ../tmpb
132 132 requesting all changes
133 133 adding changesets
134 134 adding manifests
135 135 adding file changes
136 136 added 4 changesets with 4 changes to 4 files (+1 heads)
137 137 (run 'hg heads' to see heads, 'hg merge' to merge)
138 138 $ hg debugobsolete
139 139 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
140 140 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
141 141 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
142 142 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
143 143
144 144 Rollback//Transaction support
145 145
146 146 $ hg debugobsolete -d '1340 0' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
147 147 $ hg debugobsolete
148 148 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
149 149 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
150 150 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
151 151 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
152 152 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 {'date': '1340 0', 'user': 'test'}
153 153 $ hg rollback -n
154 154 repository tip rolled back to revision 3 (undo debugobsolete)
155 155 $ hg rollback
156 156 repository tip rolled back to revision 3 (undo debugobsolete)
157 157 $ hg debugobsolete
158 158 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
159 159 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
160 160 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
161 161 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
162 162
163 163 $ cd ..
164 164
165 165 Try to pull markers
166 166
167 167 $ hg init tmpd
168 168 $ hg -R tmpb push tmpd
169 169 pushing to tmpd
170 170 searching for changes
171 171 adding changesets
172 172 adding manifests
173 173 adding file changes
174 174 added 4 changesets with 4 changes to 4 files (+1 heads)
175 175 $ hg -R tmpd debugobsolete
176 176 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
177 177 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
178 178 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
179 179 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
180 180
181 181
182 182 Destination repo have existing data
183 183 ---------------------------------------
184 184
185 185 On pull
186 186
187 187 $ hg init tmpe
188 188 $ cd tmpe
189 189 $ hg debugobsolete -d '1339 0' 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339
190 190 $ hg pull ../tmpb
191 191 pulling from ../tmpb
192 192 requesting all changes
193 193 adding changesets
194 194 adding manifests
195 195 adding file changes
196 196 added 4 changesets with 4 changes to 4 files (+1 heads)
197 197 (run 'hg heads' to see heads, 'hg merge' to merge)
198 198 $ hg debugobsolete
199 199 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339 0 {'date': '1339 0', 'user': 'test'}
200 200 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
201 201 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
202 202 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
203 203 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
204 204
205 205
206 206 On push
207 207
208 208 $ hg push ../tmpc
209 209 pushing to ../tmpc
210 210 searching for changes
211 211 no changes found
212 212 [1]
213 213 $ hg -R ../tmpc debugobsolete
214 214 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
215 215 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
216 216 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
217 217 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
218 218 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339 0 {'date': '1339 0', 'user': 'test'}
219 219
220 220 detect outgoing obsolete and unstable
221 221 ---------------------------------------
222 222
223 223
224 224 $ hg glog
225 225 o changeset: 3:5601fb93a350
226 226 | tag: tip
227 227 | parent: 1:7c3bad9141dc
228 228 | user: test
229 229 | date: Thu Jan 01 00:00:00 1970 +0000
230 230 | summary: add new_3_c
231 231 |
232 232 | o changeset: 2:245bde4270cd
233 233 |/ user: test
234 234 | date: Thu Jan 01 00:00:00 1970 +0000
235 235 | summary: add original_c
236 236 |
237 237 o changeset: 1:7c3bad9141dc
238 238 | user: test
239 239 | date: Thu Jan 01 00:00:00 1970 +0000
240 240 | summary: add b
241 241 |
242 242 o changeset: 0:1f0dee641bb7
243 243 user: test
244 244 date: Thu Jan 01 00:00:00 1970 +0000
245 245 summary: add a
246 246
247 247 $ hg up 'desc("new_3_c")'
248 248 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
249 249 $ mkcommit original_d
250 250 $ mkcommit original_e
251 251 $ hg debugobsolete `getid original_d` -d '0 0'
252 252 $ hg log -r 'obsolete()'
253 253 changeset: 4:7c694bff0650
254 254 user: test
255 255 date: Thu Jan 01 00:00:00 1970 +0000
256 256 summary: add original_d
257 257
258 258 $ hg glog -r '::unstable()'
259 259 @ changeset: 5:6e572121998e
260 260 | tag: tip
261 261 | user: test
262 262 | date: Thu Jan 01 00:00:00 1970 +0000
263 263 | summary: add original_e
264 264 |
265 265 x changeset: 4:7c694bff0650
266 266 | user: test
267 267 | date: Thu Jan 01 00:00:00 1970 +0000
268 268 | summary: add original_d
269 269 |
270 270 o changeset: 3:5601fb93a350
271 271 | parent: 1:7c3bad9141dc
272 272 | user: test
273 273 | date: Thu Jan 01 00:00:00 1970 +0000
274 274 | summary: add new_3_c
275 275 |
276 276 o changeset: 1:7c3bad9141dc
277 277 | user: test
278 278 | date: Thu Jan 01 00:00:00 1970 +0000
279 279 | summary: add b
280 280 |
281 281 o changeset: 0:1f0dee641bb7
282 282 user: test
283 283 date: Thu Jan 01 00:00:00 1970 +0000
284 284 summary: add a
285 285
286 286
287 287 refuse to push obsolete changeset
288 288
289 289 $ hg push ../tmpc/ -r 'desc("original_d")'
290 290 pushing to ../tmpc/
291 291 searching for changes
292 292 abort: push includes an obsolete changeset: 7c694bff0650!
293 293 [255]
294 294
295 295 refuse to push unstable changeset
296 296
297 297 $ hg push ../tmpc/
298 298 pushing to ../tmpc/
299 299 searching for changes
300 300 abort: push includes an unstable changeset: 6e572121998e!
301 301 [255]
302 302
303 303 Test that extinct changeset are properly detected
304 304
305 305 $ hg log -r 'extinct()'
306 306
307 307 Don't try to push extinct changeset
308 308
309 309 $ hg init ../tmpf
310 310 $ hg out ../tmpf
311 311 comparing with ../tmpf
312 312 searching for changes
313 313 changeset: 0:1f0dee641bb7
314 314 user: test
315 315 date: Thu Jan 01 00:00:00 1970 +0000
316 316 summary: add a
317 317
318 318 changeset: 1:7c3bad9141dc
319 319 user: test
320 320 date: Thu Jan 01 00:00:00 1970 +0000
321 321 summary: add b
322 322
323 323 changeset: 2:245bde4270cd
324 324 user: test
325 325 date: Thu Jan 01 00:00:00 1970 +0000
326 326 summary: add original_c
327 327
328 328 changeset: 3:5601fb93a350
329 329 parent: 1:7c3bad9141dc
330 330 user: test
331 331 date: Thu Jan 01 00:00:00 1970 +0000
332 332 summary: add new_3_c
333 333
334 334 changeset: 4:7c694bff0650
335 335 user: test
336 336 date: Thu Jan 01 00:00:00 1970 +0000
337 337 summary: add original_d
338 338
339 339 changeset: 5:6e572121998e
340 340 tag: tip
341 341 user: test
342 342 date: Thu Jan 01 00:00:00 1970 +0000
343 343 summary: add original_e
344 344
345 345 $ hg push ../tmpf -f # -f because be push unstable too
346 346 pushing to ../tmpf
347 347 searching for changes
348 348 adding changesets
349 349 adding manifests
350 350 adding file changes
351 351 added 6 changesets with 6 changes to 6 files (+1 heads)
352 352
353 353 no warning displayed
354 354
355 355 $ hg push ../tmpf
356 356 pushing to ../tmpf
357 357 searching for changes
358 358 no changes found
359 359 [1]
360
361 Do not warn about new head when the new head is a successors of a remote one
362
363 $ hg glog
364 @ changeset: 5:6e572121998e
365 | tag: tip
366 | user: test
367 | date: Thu Jan 01 00:00:00 1970 +0000
368 | summary: add original_e
369 |
370 x changeset: 4:7c694bff0650
371 | user: test
372 | date: Thu Jan 01 00:00:00 1970 +0000
373 | summary: add original_d
374 |
375 o changeset: 3:5601fb93a350
376 | parent: 1:7c3bad9141dc
377 | user: test
378 | date: Thu Jan 01 00:00:00 1970 +0000
379 | summary: add new_3_c
380 |
381 | o changeset: 2:245bde4270cd
382 |/ user: test
383 | date: Thu Jan 01 00:00:00 1970 +0000
384 | summary: add original_c
385 |
386 o changeset: 1:7c3bad9141dc
387 | user: test
388 | date: Thu Jan 01 00:00:00 1970 +0000
389 | summary: add b
390 |
391 o changeset: 0:1f0dee641bb7
392 user: test
393 date: Thu Jan 01 00:00:00 1970 +0000
394 summary: add a
395
396 $ hg up -q 'desc(new_3_c)'
397 $ mkcommit obsolete_e
398 created new head
399 $ hg debugobsolete `getid 'original_e'` `getid 'obsolete_e'`
400 $ hg push ../tmpf
401 pushing to ../tmpf
402 searching for changes
403 adding changesets
404 adding manifests
405 adding file changes
406 added 1 changesets with 1 changes to 1 files (+1 heads)
General Comments 0
You need to be logged in to leave comments. Login now