##// END OF EJS Templates
checkheads: check successors for new heads in both missing and common...
Pierre-Yves David -
r17548:eaa5fcc5 default
parent child Browse files
Show More
@@ -1,372 +1,374 b''
1 # discovery.py - protocol changeset discovery functions
1 # discovery.py - protocol changeset discovery functions
2 #
2 #
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
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 node import nullid, short
8 from node import nullid, short
9 from i18n import _
9 from i18n import _
10 import util, setdiscovery, treediscovery, phases, obsolete
10 import util, setdiscovery, treediscovery, phases, obsolete
11
11
12 def findcommonincoming(repo, remote, heads=None, force=False):
12 def findcommonincoming(repo, remote, heads=None, force=False):
13 """Return a tuple (common, anyincoming, heads) used to identify the common
13 """Return a tuple (common, anyincoming, heads) used to identify the common
14 subset of nodes between repo and remote.
14 subset of nodes between repo and remote.
15
15
16 "common" is a list of (at least) the heads of the common subset.
16 "common" is a list of (at least) the heads of the common subset.
17 "anyincoming" is testable as a boolean indicating if any nodes are missing
17 "anyincoming" is testable as a boolean indicating if any nodes are missing
18 locally. If remote does not support getbundle, this actually is a list of
18 locally. If remote does not support getbundle, this actually is a list of
19 roots of the nodes that would be incoming, to be supplied to
19 roots of the nodes that would be incoming, to be supplied to
20 changegroupsubset. No code except for pull should be relying on this fact
20 changegroupsubset. No code except for pull should be relying on this fact
21 any longer.
21 any longer.
22 "heads" is either the supplied heads, or else the remote's heads.
22 "heads" is either the supplied heads, or else the remote's heads.
23
23
24 If you pass heads and they are all known locally, the response lists just
24 If you pass heads and they are all known locally, the response lists just
25 these heads in "common" and in "heads".
25 these heads in "common" and in "heads".
26
26
27 Please use findcommonoutgoing to compute the set of outgoing nodes to give
27 Please use findcommonoutgoing to compute the set of outgoing nodes to give
28 extensions a good hook into outgoing.
28 extensions a good hook into outgoing.
29 """
29 """
30
30
31 if not remote.capable('getbundle'):
31 if not remote.capable('getbundle'):
32 return treediscovery.findcommonincoming(repo, remote, heads, force)
32 return treediscovery.findcommonincoming(repo, remote, heads, force)
33
33
34 if heads:
34 if heads:
35 allknown = True
35 allknown = True
36 nm = repo.changelog.nodemap
36 nm = repo.changelog.nodemap
37 for h in heads:
37 for h in heads:
38 if nm.get(h) is None:
38 if nm.get(h) is None:
39 allknown = False
39 allknown = False
40 break
40 break
41 if allknown:
41 if allknown:
42 return (heads, False, heads)
42 return (heads, False, heads)
43
43
44 res = setdiscovery.findcommonheads(repo.ui, repo, remote,
44 res = setdiscovery.findcommonheads(repo.ui, repo, remote,
45 abortwhenunrelated=not force)
45 abortwhenunrelated=not force)
46 common, anyinc, srvheads = res
46 common, anyinc, srvheads = res
47 return (list(common), anyinc, heads or list(srvheads))
47 return (list(common), anyinc, heads or list(srvheads))
48
48
49 class outgoing(object):
49 class outgoing(object):
50 '''Represents the set of nodes present in a local repo but not in a
50 '''Represents the set of nodes present in a local repo but not in a
51 (possibly) remote one.
51 (possibly) remote one.
52
52
53 Members:
53 Members:
54
54
55 missing is a list of all nodes present in local but not in remote.
55 missing is a list of all nodes present in local but not in remote.
56 common is a list of all nodes shared between the two repos.
56 common is a list of all nodes shared between the two repos.
57 excluded is the list of missing changeset that shouldn't be sent remotely.
57 excluded is the list of missing changeset that shouldn't be sent remotely.
58 missingheads is the list of heads of missing.
58 missingheads is the list of heads of missing.
59 commonheads is the list of heads of common.
59 commonheads is the list of heads of common.
60
60
61 The sets are computed on demand from the heads, unless provided upfront
61 The sets are computed on demand from the heads, unless provided upfront
62 by discovery.'''
62 by discovery.'''
63
63
64 def __init__(self, revlog, commonheads, missingheads):
64 def __init__(self, revlog, commonheads, missingheads):
65 self.commonheads = commonheads
65 self.commonheads = commonheads
66 self.missingheads = missingheads
66 self.missingheads = missingheads
67 self._revlog = revlog
67 self._revlog = revlog
68 self._common = None
68 self._common = None
69 self._missing = None
69 self._missing = None
70 self.excluded = []
70 self.excluded = []
71
71
72 def _computecommonmissing(self):
72 def _computecommonmissing(self):
73 sets = self._revlog.findcommonmissing(self.commonheads,
73 sets = self._revlog.findcommonmissing(self.commonheads,
74 self.missingheads)
74 self.missingheads)
75 self._common, self._missing = sets
75 self._common, self._missing = sets
76
76
77 @util.propertycache
77 @util.propertycache
78 def common(self):
78 def common(self):
79 if self._common is None:
79 if self._common is None:
80 self._computecommonmissing()
80 self._computecommonmissing()
81 return self._common
81 return self._common
82
82
83 @util.propertycache
83 @util.propertycache
84 def missing(self):
84 def missing(self):
85 if self._missing is None:
85 if self._missing is None:
86 self._computecommonmissing()
86 self._computecommonmissing()
87 return self._missing
87 return self._missing
88
88
89 def findcommonoutgoing(repo, other, onlyheads=None, force=False,
89 def findcommonoutgoing(repo, other, onlyheads=None, force=False,
90 commoninc=None, portable=False):
90 commoninc=None, portable=False):
91 '''Return an outgoing instance to identify the nodes present in repo but
91 '''Return an outgoing instance to identify the nodes present in repo but
92 not in other.
92 not in other.
93
93
94 If onlyheads is given, only nodes ancestral to nodes in onlyheads
94 If onlyheads is given, only nodes ancestral to nodes in onlyheads
95 (inclusive) are included. If you already know the local repo's heads,
95 (inclusive) are included. If you already know the local repo's heads,
96 passing them in onlyheads is faster than letting them be recomputed here.
96 passing them in onlyheads is faster than letting them be recomputed here.
97
97
98 If commoninc is given, it must be the result of a prior call to
98 If commoninc is given, it must be the result of a prior call to
99 findcommonincoming(repo, other, force) to avoid recomputing it here.
99 findcommonincoming(repo, other, force) to avoid recomputing it here.
100
100
101 If portable is given, compute more conservative common and missingheads,
101 If portable is given, compute more conservative common and missingheads,
102 to make bundles created from the instance more portable.'''
102 to make bundles created from the instance more portable.'''
103 # declare an empty outgoing object to be filled later
103 # declare an empty outgoing object to be filled later
104 og = outgoing(repo.changelog, None, None)
104 og = outgoing(repo.changelog, None, None)
105
105
106 # get common set if not provided
106 # get common set if not provided
107 if commoninc is None:
107 if commoninc is None:
108 commoninc = findcommonincoming(repo, other, force=force)
108 commoninc = findcommonincoming(repo, other, force=force)
109 og.commonheads, _any, _hds = commoninc
109 og.commonheads, _any, _hds = commoninc
110
110
111 # compute outgoing
111 # compute outgoing
112 mayexclude = (repo._phasecache.phaseroots[phases.secret] or repo.obsstore)
112 mayexclude = (repo._phasecache.phaseroots[phases.secret] or repo.obsstore)
113 if not mayexclude:
113 if not mayexclude:
114 og.missingheads = onlyheads or repo.heads()
114 og.missingheads = onlyheads or repo.heads()
115 elif onlyheads is None:
115 elif onlyheads is None:
116 # use visible heads as it should be cached
116 # use visible heads as it should be cached
117 og.missingheads = visibleheads(repo)
117 og.missingheads = visibleheads(repo)
118 og.excluded = [ctx.node() for ctx in repo.set('secret() or extinct()')]
118 og.excluded = [ctx.node() for ctx in repo.set('secret() or extinct()')]
119 else:
119 else:
120 # compute common, missing and exclude secret stuff
120 # compute common, missing and exclude secret stuff
121 sets = repo.changelog.findcommonmissing(og.commonheads, onlyheads)
121 sets = repo.changelog.findcommonmissing(og.commonheads, onlyheads)
122 og._common, allmissing = sets
122 og._common, allmissing = sets
123 og._missing = missing = []
123 og._missing = missing = []
124 og.excluded = excluded = []
124 og.excluded = excluded = []
125 for node in allmissing:
125 for node in allmissing:
126 ctx = repo[node]
126 ctx = repo[node]
127 if ctx.phase() >= phases.secret or ctx.extinct():
127 if ctx.phase() >= phases.secret or ctx.extinct():
128 excluded.append(node)
128 excluded.append(node)
129 else:
129 else:
130 missing.append(node)
130 missing.append(node)
131 if len(missing) == len(allmissing):
131 if len(missing) == len(allmissing):
132 missingheads = onlyheads
132 missingheads = onlyheads
133 else: # update missing heads
133 else: # update missing heads
134 missingheads = phases.newheads(repo, onlyheads, excluded)
134 missingheads = phases.newheads(repo, onlyheads, excluded)
135 og.missingheads = missingheads
135 og.missingheads = missingheads
136 if portable:
136 if portable:
137 # recompute common and missingheads as if -r<rev> had been given for
137 # recompute common and missingheads as if -r<rev> had been given for
138 # each head of missing, and --base <rev> for each head of the proper
138 # each head of missing, and --base <rev> for each head of the proper
139 # ancestors of missing
139 # ancestors of missing
140 og._computecommonmissing()
140 og._computecommonmissing()
141 cl = repo.changelog
141 cl = repo.changelog
142 missingrevs = set(cl.rev(n) for n in og._missing)
142 missingrevs = set(cl.rev(n) for n in og._missing)
143 og._common = set(cl.ancestors(missingrevs)) - missingrevs
143 og._common = set(cl.ancestors(missingrevs)) - missingrevs
144 commonheads = set(og.commonheads)
144 commonheads = set(og.commonheads)
145 og.missingheads = [h for h in og.missingheads if h not in commonheads]
145 og.missingheads = [h for h in og.missingheads if h not in commonheads]
146
146
147 return og
147 return og
148
148
149 def _headssummary(repo, remote, outgoing):
149 def _headssummary(repo, remote, outgoing):
150 """compute a summary of branch and heads status before and after push
150 """compute a summary of branch and heads status before and after push
151
151
152 return {'branch': ([remoteheads], [newheads], [unsyncedheads])} mapping
152 return {'branch': ([remoteheads], [newheads], [unsyncedheads])} mapping
153
153
154 - branch: the branch name
154 - branch: the branch name
155 - remoteheads: the list of remote heads known locally
155 - remoteheads: the list of remote heads known locally
156 None is the branch is new
156 None is the branch is new
157 - newheads: the new remote heads (known locally) with outgoing pushed
157 - newheads: the new remote heads (known locally) with outgoing pushed
158 - unsyncedheads: the list of remote heads unknown locally.
158 - unsyncedheads: the list of remote heads unknown locally.
159 """
159 """
160 cl = repo.changelog
160 cl = repo.changelog
161 headssum = {}
161 headssum = {}
162 # A. Create set of branches involved in the push.
162 # A. Create set of branches involved in the push.
163 branches = set(repo[n].branch() for n in outgoing.missing)
163 branches = set(repo[n].branch() for n in outgoing.missing)
164 remotemap = remote.branchmap()
164 remotemap = remote.branchmap()
165 newbranches = branches - set(remotemap)
165 newbranches = branches - set(remotemap)
166 branches.difference_update(newbranches)
166 branches.difference_update(newbranches)
167
167
168 # A. register remote heads
168 # A. register remote heads
169 remotebranches = set()
169 remotebranches = set()
170 for branch, heads in remote.branchmap().iteritems():
170 for branch, heads in remote.branchmap().iteritems():
171 remotebranches.add(branch)
171 remotebranches.add(branch)
172 known = []
172 known = []
173 unsynced = []
173 unsynced = []
174 for h in heads:
174 for h in heads:
175 if h in cl.nodemap:
175 if h in cl.nodemap:
176 known.append(h)
176 known.append(h)
177 else:
177 else:
178 unsynced.append(h)
178 unsynced.append(h)
179 headssum[branch] = (known, list(known), unsynced)
179 headssum[branch] = (known, list(known), unsynced)
180 # B. add new branch data
180 # B. add new branch data
181 missingctx = list(repo[n] for n in outgoing.missing)
181 missingctx = list(repo[n] for n in outgoing.missing)
182 touchedbranches = set()
182 touchedbranches = set()
183 for ctx in missingctx:
183 for ctx in missingctx:
184 branch = ctx.branch()
184 branch = ctx.branch()
185 touchedbranches.add(branch)
185 touchedbranches.add(branch)
186 if branch not in headssum:
186 if branch not in headssum:
187 headssum[branch] = (None, [], [])
187 headssum[branch] = (None, [], [])
188
188
189 # C drop data about untouched branches:
189 # C drop data about untouched branches:
190 for branch in remotebranches - touchedbranches:
190 for branch in remotebranches - touchedbranches:
191 del headssum[branch]
191 del headssum[branch]
192
192
193 # D. Update newmap with outgoing changes.
193 # D. Update newmap with outgoing changes.
194 # This will possibly add new heads and remove existing ones.
194 # This will possibly add new heads and remove existing ones.
195 newmap = dict((branch, heads[1]) for branch, heads in headssum.iteritems()
195 newmap = dict((branch, heads[1]) for branch, heads in headssum.iteritems()
196 if heads[0] is not None)
196 if heads[0] is not None)
197 repo._updatebranchcache(newmap, missingctx)
197 repo._updatebranchcache(newmap, missingctx)
198 for branch, newheads in newmap.iteritems():
198 for branch, newheads in newmap.iteritems():
199 headssum[branch][1][:] = newheads
199 headssum[branch][1][:] = newheads
200 return headssum
200 return headssum
201
201
202 def _oldheadssummary(repo, remoteheads, outgoing, inc=False):
202 def _oldheadssummary(repo, remoteheads, outgoing, inc=False):
203 """Compute branchmapsummary for repo without branchmap support"""
203 """Compute branchmapsummary for repo without branchmap support"""
204
204
205 cl = repo.changelog
205 cl = repo.changelog
206 # 1-4b. old servers: Check for new topological heads.
206 # 1-4b. old servers: Check for new topological heads.
207 # Construct {old,new}map with branch = None (topological branch).
207 # Construct {old,new}map with branch = None (topological branch).
208 # (code based on _updatebranchcache)
208 # (code based on _updatebranchcache)
209 oldheads = set(h for h in remoteheads if h in cl.nodemap)
209 oldheads = set(h for h in remoteheads if h in cl.nodemap)
210 # all nodes in outgoing.missing are children of either:
210 # all nodes in outgoing.missing are children of either:
211 # - an element of oldheads
211 # - an element of oldheads
212 # - another element of outgoing.missing
212 # - another element of outgoing.missing
213 # - nullrev
213 # - nullrev
214 # This explains why the new head are very simple to compute.
214 # This explains why the new head are very simple to compute.
215 r = repo.set('heads(%ln + %ln)', oldheads, outgoing.missing)
215 r = repo.set('heads(%ln + %ln)', oldheads, outgoing.missing)
216 newheads = list(c.node() for c in r)
216 newheads = list(c.node() for c in r)
217 unsynced = inc and set([None]) or set()
217 unsynced = inc and set([None]) or set()
218 return {None: (oldheads, newheads, unsynced)}
218 return {None: (oldheads, newheads, unsynced)}
219
219
220 def checkheads(repo, remote, outgoing, remoteheads, newbranch=False, inc=False):
220 def checkheads(repo, remote, outgoing, remoteheads, newbranch=False, inc=False):
221 """Check that a push won't add any outgoing head
221 """Check that a push won't add any outgoing head
222
222
223 raise Abort error and display ui message as needed.
223 raise Abort error and display ui message as needed.
224 """
224 """
225 # Check for each named branch if we're creating new remote heads.
225 # Check for each named branch if we're creating new remote heads.
226 # To be a remote head after push, node must be either:
226 # To be a remote head after push, node must be either:
227 # - unknown locally
227 # - unknown locally
228 # - a local outgoing head descended from update
228 # - a local outgoing head descended from update
229 # - a remote head that's known locally and not
229 # - a remote head that's known locally and not
230 # ancestral to an outgoing head
230 # ancestral to an outgoing head
231 if remoteheads == [nullid]:
231 if remoteheads == [nullid]:
232 # remote is empty, nothing to check.
232 # remote is empty, nothing to check.
233 return
233 return
234
234
235 if remote.capable('branchmap'):
235 if remote.capable('branchmap'):
236 headssum = _headssummary(repo, remote, outgoing)
236 headssum = _headssummary(repo, remote, outgoing)
237 else:
237 else:
238 headssum = _oldheadssummary(repo, remoteheads, outgoing, inc)
238 headssum = _oldheadssummary(repo, remoteheads, outgoing, inc)
239 newbranches = [branch for branch, heads in headssum.iteritems()
239 newbranches = [branch for branch, heads in headssum.iteritems()
240 if heads[0] is None]
240 if heads[0] is None]
241 # 1. Check for new branches on the remote.
241 # 1. Check for new branches on the remote.
242 if newbranches and not newbranch: # new branch requires --new-branch
242 if newbranches and not newbranch: # new branch requires --new-branch
243 branchnames = ', '.join(sorted(newbranches))
243 branchnames = ', '.join(sorted(newbranches))
244 raise util.Abort(_("push creates new remote branches: %s!")
244 raise util.Abort(_("push creates new remote branches: %s!")
245 % branchnames,
245 % branchnames,
246 hint=_("use 'hg push --new-branch' to create"
246 hint=_("use 'hg push --new-branch' to create"
247 " new remote branches"))
247 " new remote branches"))
248
248
249 # 2 compute newly pushed bookmarks. We
249 # 2 compute newly pushed bookmarks. We
250 # we don't warned about bookmarked heads.
250 # we don't warned about bookmarked heads.
251 localbookmarks = repo._bookmarks
251 localbookmarks = repo._bookmarks
252 remotebookmarks = remote.listkeys('bookmarks')
252 remotebookmarks = remote.listkeys('bookmarks')
253 bookmarkedheads = set()
253 bookmarkedheads = set()
254 for bm in localbookmarks:
254 for bm in localbookmarks:
255 rnode = remotebookmarks.get(bm)
255 rnode = remotebookmarks.get(bm)
256 if rnode and rnode in repo:
256 if rnode and rnode in repo:
257 lctx, rctx = repo[bm], repo[rnode]
257 lctx, rctx = repo[bm], repo[rnode]
258 if rctx == lctx.ancestor(rctx):
258 if rctx == lctx.ancestor(rctx):
259 bookmarkedheads.add(lctx.node())
259 bookmarkedheads.add(lctx.node())
260
260
261 # 3. Check for new heads.
261 # 3. Check for new heads.
262 # If there are more heads after the push than before, a suitable
262 # If there are more heads after the push than before, a suitable
263 # error message, depending on unsynced status, is displayed.
263 # error message, depending on unsynced status, is displayed.
264 error = None
264 error = None
265 unsynced = False
265 unsynced = False
266 allmissing = set(outgoing.missing)
266 allmissing = set(outgoing.missing)
267 allfuturecommon = set(c.node() for c in repo.set('%ld', outgoing.common))
268 allfuturecommon.update(allmissing)
267 for branch, heads in headssum.iteritems():
269 for branch, heads in headssum.iteritems():
268 if heads[0] is None:
270 if heads[0] is None:
269 # Maybe we should abort if we push more that one head
271 # Maybe we should abort if we push more that one head
270 # for new branches ?
272 # for new branches ?
271 continue
273 continue
272 if heads[2]:
274 if heads[2]:
273 unsynced = True
275 unsynced = True
274 oldhs = set(heads[0])
276 oldhs = set(heads[0])
275 candidate_newhs = set(heads[1])
277 candidate_newhs = set(heads[1])
276 # add unsynced data
278 # add unsynced data
277 oldhs.update(heads[2])
279 oldhs.update(heads[2])
278 candidate_newhs.update(heads[2])
280 candidate_newhs.update(heads[2])
279 dhs = None
281 dhs = None
280 if repo.obsstore:
282 if repo.obsstore:
281 # remove future heads which are actually obsolete by another
283 # remove future heads which are actually obsolete by another
282 # pushed element:
284 # pushed element:
283 #
285 #
284 # XXX There is several case this case does not handle properly
286 # XXX There is several case this case does not handle properly
285 #
287 #
286 # (1) if <nh> is public, it won't be affected by obsolete marker
288 # (1) if <nh> is public, it won't be affected by obsolete marker
287 # and a new is created
289 # and a new is created
288 #
290 #
289 # (2) if the new heads have ancestors which are not obsolete and
291 # (2) if the new heads have ancestors which are not obsolete and
290 # not ancestors of any other heads we will have a new head too.
292 # not ancestors of any other heads we will have a new head too.
291 #
293 #
292 # This two case will be easy to handle for know changeset but much
294 # This two case will be easy to handle for know changeset but much
293 # more tricky for unsynced changes.
295 # more tricky for unsynced changes.
294 newhs = set()
296 newhs = set()
295 for nh in candidate_newhs:
297 for nh in candidate_newhs:
296 if repo[nh].phase() <= phases.public:
298 if nh in repo and repo[nh].phase() <= phases.public:
297 newhs.add(nh)
299 newhs.add(nh)
298 else:
300 else:
299 for suc in obsolete.anysuccessors(repo.obsstore, nh):
301 for suc in obsolete.anysuccessors(repo.obsstore, nh):
300 if suc != nh and suc in allmissing:
302 if suc != nh and suc in allfuturecommon:
301 break
303 break
302 else:
304 else:
303 newhs.add(nh)
305 newhs.add(nh)
304 else:
306 else:
305 newhs = candidate_newhs
307 newhs = candidate_newhs
306 if len(newhs) > len(oldhs):
308 if len(newhs) > len(oldhs):
307 # strip updates to existing remote heads from the new heads list
309 # strip updates to existing remote heads from the new heads list
308 dhs = list(newhs - bookmarkedheads - oldhs)
310 dhs = list(newhs - bookmarkedheads - oldhs)
309 if dhs:
311 if dhs:
310 if error is None:
312 if error is None:
311 if branch not in ('default', None):
313 if branch not in ('default', None):
312 error = _("push creates new remote head %s "
314 error = _("push creates new remote head %s "
313 "on branch '%s'!") % (short(dhs[0]), branch)
315 "on branch '%s'!") % (short(dhs[0]), branch)
314 else:
316 else:
315 error = _("push creates new remote head %s!"
317 error = _("push creates new remote head %s!"
316 ) % short(dhs[0])
318 ) % short(dhs[0])
317 if heads[2]: # unsynced
319 if heads[2]: # unsynced
318 hint = _("you should pull and merge or "
320 hint = _("you should pull and merge or "
319 "use push -f to force")
321 "use push -f to force")
320 else:
322 else:
321 hint = _("did you forget to merge? "
323 hint = _("did you forget to merge? "
322 "use push -f to force")
324 "use push -f to force")
323 if branch is not None:
325 if branch is not None:
324 repo.ui.note(_("new remote heads on branch '%s'\n") % branch)
326 repo.ui.note(_("new remote heads on branch '%s'\n") % branch)
325 for h in dhs:
327 for h in dhs:
326 repo.ui.note(_("new remote head %s\n") % short(h))
328 repo.ui.note(_("new remote head %s\n") % short(h))
327 if error:
329 if error:
328 raise util.Abort(error, hint=hint)
330 raise util.Abort(error, hint=hint)
329
331
330 # 6. Check for unsynced changes on involved branches.
332 # 6. Check for unsynced changes on involved branches.
331 if unsynced:
333 if unsynced:
332 repo.ui.warn(_("note: unsynced remote changes!\n"))
334 repo.ui.warn(_("note: unsynced remote changes!\n"))
333
335
334 def visibleheads(repo):
336 def visibleheads(repo):
335 """return the set of visible head of this repo"""
337 """return the set of visible head of this repo"""
336 # XXX we want a cache on this
338 # XXX we want a cache on this
337 sroots = repo._phasecache.phaseroots[phases.secret]
339 sroots = repo._phasecache.phaseroots[phases.secret]
338 if sroots or repo.obsstore:
340 if sroots or repo.obsstore:
339 # XXX very slow revset. storing heads or secret "boundary"
341 # XXX very slow revset. storing heads or secret "boundary"
340 # would help.
342 # would help.
341 revset = repo.set('heads(not (%ln:: + extinct()))', sroots)
343 revset = repo.set('heads(not (%ln:: + extinct()))', sroots)
342
344
343 vheads = [ctx.node() for ctx in revset]
345 vheads = [ctx.node() for ctx in revset]
344 if not vheads:
346 if not vheads:
345 vheads.append(nullid)
347 vheads.append(nullid)
346 else:
348 else:
347 vheads = repo.heads()
349 vheads = repo.heads()
348 return vheads
350 return vheads
349
351
350
352
351 def visiblebranchmap(repo):
353 def visiblebranchmap(repo):
352 """return a branchmap for the visible set"""
354 """return a branchmap for the visible set"""
353 # XXX Recomputing this data on the fly is very slow. We should build a
355 # XXX Recomputing this data on the fly is very slow. We should build a
354 # XXX cached version while computing the standard branchmap version.
356 # XXX cached version while computing the standard branchmap version.
355 sroots = repo._phasecache.phaseroots[phases.secret]
357 sroots = repo._phasecache.phaseroots[phases.secret]
356 if sroots or repo.obsstore:
358 if sroots or repo.obsstore:
357 vbranchmap = {}
359 vbranchmap = {}
358 for branch, nodes in repo.branchmap().iteritems():
360 for branch, nodes in repo.branchmap().iteritems():
359 # search for secret heads.
361 # search for secret heads.
360 for n in nodes:
362 for n in nodes:
361 if repo[n].phase() >= phases.secret:
363 if repo[n].phase() >= phases.secret:
362 nodes = None
364 nodes = None
363 break
365 break
364 # if secret heads were found we must compute them again
366 # if secret heads were found we must compute them again
365 if nodes is None:
367 if nodes is None:
366 s = repo.set('heads(branch(%s) - secret() - extinct())',
368 s = repo.set('heads(branch(%s) - secret() - extinct())',
367 branch)
369 branch)
368 nodes = [c.node() for c in s]
370 nodes = [c.node() for c in s]
369 vbranchmap[branch] = nodes
371 vbranchmap[branch] = nodes
370 else:
372 else:
371 vbranchmap = repo.branchmap()
373 vbranchmap = repo.branchmap()
372 return vbranchmap
374 return vbranchmap
@@ -1,298 +1,298 b''
1 $ "$TESTDIR/hghave" serve || exit 80
1 $ "$TESTDIR/hghave" serve || exit 80
2
2
3 initialize
3 initialize
4
4
5 $ hg init a
5 $ hg init a
6 $ cd a
6 $ cd a
7 $ echo 'test' > test
7 $ echo 'test' > test
8 $ hg commit -Am'test'
8 $ hg commit -Am'test'
9 adding test
9 adding test
10
10
11 set bookmarks
11 set bookmarks
12
12
13 $ hg bookmark X
13 $ hg bookmark X
14 $ hg bookmark Y
14 $ hg bookmark Y
15 $ hg bookmark Z
15 $ hg bookmark Z
16
16
17 import bookmark by name
17 import bookmark by name
18
18
19 $ hg init ../b
19 $ hg init ../b
20 $ cd ../b
20 $ cd ../b
21 $ hg book Y
21 $ hg book Y
22 $ hg book
22 $ hg book
23 * Y -1:000000000000
23 * Y -1:000000000000
24 $ hg pull ../a
24 $ hg pull ../a
25 pulling from ../a
25 pulling from ../a
26 requesting all changes
26 requesting all changes
27 adding changesets
27 adding changesets
28 adding manifests
28 adding manifests
29 adding file changes
29 adding file changes
30 added 1 changesets with 1 changes to 1 files
30 added 1 changesets with 1 changes to 1 files
31 updating bookmark Y
31 updating bookmark Y
32 adding remote bookmark X
32 adding remote bookmark X
33 adding remote bookmark Z
33 adding remote bookmark Z
34 (run 'hg update' to get a working copy)
34 (run 'hg update' to get a working copy)
35 $ hg bookmarks
35 $ hg bookmarks
36 X 0:4e3505fd9583
36 X 0:4e3505fd9583
37 Y 0:4e3505fd9583
37 Y 0:4e3505fd9583
38 Z 0:4e3505fd9583
38 Z 0:4e3505fd9583
39 $ hg debugpushkey ../a namespaces
39 $ hg debugpushkey ../a namespaces
40 bookmarks
40 bookmarks
41 phases
41 phases
42 namespaces
42 namespaces
43 $ hg debugpushkey ../a bookmarks
43 $ hg debugpushkey ../a bookmarks
44 Y 4e3505fd95835d721066b76e75dbb8cc554d7f77
44 Y 4e3505fd95835d721066b76e75dbb8cc554d7f77
45 X 4e3505fd95835d721066b76e75dbb8cc554d7f77
45 X 4e3505fd95835d721066b76e75dbb8cc554d7f77
46 Z 4e3505fd95835d721066b76e75dbb8cc554d7f77
46 Z 4e3505fd95835d721066b76e75dbb8cc554d7f77
47 $ hg pull -B X ../a
47 $ hg pull -B X ../a
48 pulling from ../a
48 pulling from ../a
49 no changes found
49 no changes found
50 importing bookmark X
50 importing bookmark X
51 $ hg bookmark
51 $ hg bookmark
52 X 0:4e3505fd9583
52 X 0:4e3505fd9583
53 Y 0:4e3505fd9583
53 Y 0:4e3505fd9583
54 Z 0:4e3505fd9583
54 Z 0:4e3505fd9583
55
55
56 export bookmark by name
56 export bookmark by name
57
57
58 $ hg bookmark W
58 $ hg bookmark W
59 $ hg bookmark foo
59 $ hg bookmark foo
60 $ hg bookmark foobar
60 $ hg bookmark foobar
61 $ hg push -B W ../a
61 $ hg push -B W ../a
62 pushing to ../a
62 pushing to ../a
63 searching for changes
63 searching for changes
64 no changes found
64 no changes found
65 exporting bookmark W
65 exporting bookmark W
66 [1]
66 [1]
67 $ hg -R ../a bookmarks
67 $ hg -R ../a bookmarks
68 W -1:000000000000
68 W -1:000000000000
69 X 0:4e3505fd9583
69 X 0:4e3505fd9583
70 Y 0:4e3505fd9583
70 Y 0:4e3505fd9583
71 * Z 0:4e3505fd9583
71 * Z 0:4e3505fd9583
72
72
73 delete a remote bookmark
73 delete a remote bookmark
74
74
75 $ hg book -d W
75 $ hg book -d W
76 $ hg push -B W ../a
76 $ hg push -B W ../a
77 pushing to ../a
77 pushing to ../a
78 searching for changes
78 searching for changes
79 no changes found
79 no changes found
80 deleting remote bookmark W
80 deleting remote bookmark W
81 [1]
81 [1]
82
82
83 push/pull name that doesn't exist
83 push/pull name that doesn't exist
84
84
85 $ hg push -B badname ../a
85 $ hg push -B badname ../a
86 pushing to ../a
86 pushing to ../a
87 searching for changes
87 searching for changes
88 no changes found
88 no changes found
89 bookmark badname does not exist on the local or remote repository!
89 bookmark badname does not exist on the local or remote repository!
90 [2]
90 [2]
91 $ hg pull -B anotherbadname ../a
91 $ hg pull -B anotherbadname ../a
92 pulling from ../a
92 pulling from ../a
93 abort: remote bookmark anotherbadname not found!
93 abort: remote bookmark anotherbadname not found!
94 [255]
94 [255]
95
95
96 divergent bookmarks
96 divergent bookmarks
97
97
98 $ cd ../a
98 $ cd ../a
99 $ echo c1 > f1
99 $ echo c1 > f1
100 $ hg ci -Am1
100 $ hg ci -Am1
101 adding f1
101 adding f1
102 $ hg book -f X
102 $ hg book -f X
103 $ hg book
103 $ hg book
104 * X 1:0d2164f0ce0d
104 * X 1:0d2164f0ce0d
105 Y 0:4e3505fd9583
105 Y 0:4e3505fd9583
106 Z 1:0d2164f0ce0d
106 Z 1:0d2164f0ce0d
107
107
108 $ cd ../b
108 $ cd ../b
109 $ hg up
109 $ hg up
110 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
110 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
111 updating bookmark foobar
111 updating bookmark foobar
112 $ echo c2 > f2
112 $ echo c2 > f2
113 $ hg ci -Am2
113 $ hg ci -Am2
114 adding f2
114 adding f2
115 $ hg book -f X
115 $ hg book -f X
116 $ hg book
116 $ hg book
117 * X 1:9b140be10808
117 * X 1:9b140be10808
118 Y 0:4e3505fd9583
118 Y 0:4e3505fd9583
119 Z 0:4e3505fd9583
119 Z 0:4e3505fd9583
120 foo -1:000000000000
120 foo -1:000000000000
121 foobar 1:9b140be10808
121 foobar 1:9b140be10808
122
122
123 $ hg pull --config paths.foo=../a foo
123 $ hg pull --config paths.foo=../a foo
124 pulling from $TESTTMP/a (glob)
124 pulling from $TESTTMP/a (glob)
125 searching for changes
125 searching for changes
126 adding changesets
126 adding changesets
127 adding manifests
127 adding manifests
128 adding file changes
128 adding file changes
129 added 1 changesets with 1 changes to 1 files (+1 heads)
129 added 1 changesets with 1 changes to 1 files (+1 heads)
130 divergent bookmark X stored as X@foo
130 divergent bookmark X stored as X@foo
131 updating bookmark Z
131 updating bookmark Z
132 (run 'hg heads' to see heads, 'hg merge' to merge)
132 (run 'hg heads' to see heads, 'hg merge' to merge)
133 $ hg book
133 $ hg book
134 * X 1:9b140be10808
134 * X 1:9b140be10808
135 X@foo 2:0d2164f0ce0d
135 X@foo 2:0d2164f0ce0d
136 Y 0:4e3505fd9583
136 Y 0:4e3505fd9583
137 Z 2:0d2164f0ce0d
137 Z 2:0d2164f0ce0d
138 foo -1:000000000000
138 foo -1:000000000000
139 foobar 1:9b140be10808
139 foobar 1:9b140be10808
140 $ hg push -f ../a
140 $ hg push -f ../a
141 pushing to ../a
141 pushing to ../a
142 searching for changes
142 searching for changes
143 adding changesets
143 adding changesets
144 adding manifests
144 adding manifests
145 adding file changes
145 adding file changes
146 added 1 changesets with 1 changes to 1 files (+1 heads)
146 added 1 changesets with 1 changes to 1 files (+1 heads)
147 $ hg -R ../a book
147 $ hg -R ../a book
148 * X 1:0d2164f0ce0d
148 * X 1:0d2164f0ce0d
149 Y 0:4e3505fd9583
149 Y 0:4e3505fd9583
150 Z 1:0d2164f0ce0d
150 Z 1:0d2164f0ce0d
151
151
152 update a remote bookmark from a non-head to a head
152 update a remote bookmark from a non-head to a head
153
153
154 $ hg up -q Y
154 $ hg up -q Y
155 $ echo c3 > f2
155 $ echo c3 > f2
156 $ hg ci -Am3
156 $ hg ci -Am3
157 adding f2
157 adding f2
158 created new head
158 created new head
159 $ hg push ../a
159 $ hg push ../a
160 pushing to ../a
160 pushing to ../a
161 searching for changes
161 searching for changes
162 adding changesets
162 adding changesets
163 adding manifests
163 adding manifests
164 adding file changes
164 adding file changes
165 added 1 changesets with 1 changes to 1 files (+1 heads)
165 added 1 changesets with 1 changes to 1 files (+1 heads)
166 updating bookmark Y
166 updating bookmark Y
167 $ hg -R ../a book
167 $ hg -R ../a book
168 * X 1:0d2164f0ce0d
168 * X 1:0d2164f0ce0d
169 Y 3:f6fc62dde3c0
169 Y 3:f6fc62dde3c0
170 Z 1:0d2164f0ce0d
170 Z 1:0d2164f0ce0d
171
171
172 diverging a remote bookmark fails
172 diverging a remote bookmark fails
173
173
174 $ hg up -q 4e3505fd9583
174 $ hg up -q 4e3505fd9583
175 $ echo c4 > f2
175 $ echo c4 > f2
176 $ hg ci -Am4
176 $ hg ci -Am4
177 adding f2
177 adding f2
178 created new head
178 created new head
179 $ hg book -f Y
179 $ hg book -f Y
180
180
181 $ cat <<EOF > ../a/.hg/hgrc
181 $ cat <<EOF > ../a/.hg/hgrc
182 > [web]
182 > [web]
183 > push_ssl = false
183 > push_ssl = false
184 > allow_push = *
184 > allow_push = *
185 > EOF
185 > EOF
186
186
187 $ hg -R ../a serve -p $HGPORT2 -d --pid-file=../hg2.pid
187 $ hg -R ../a serve -p $HGPORT2 -d --pid-file=../hg2.pid
188 $ cat ../hg2.pid >> $DAEMON_PIDS
188 $ cat ../hg2.pid >> $DAEMON_PIDS
189
189
190 $ hg push http://localhost:$HGPORT2/
190 $ hg push http://localhost:$HGPORT2/
191 pushing to http://localhost:$HGPORT2/
191 pushing to http://localhost:$HGPORT2/
192 searching for changes
192 searching for changes
193 abort: push creates new remote head 4efff6d98829!
193 abort: push creates new remote head 4efff6d98829!
194 (did you forget to merge? use push -f to force)
194 (did you forget to merge? use push -f to force)
195 [255]
195 [255]
196 $ hg -R ../a book
196 $ hg -R ../a book
197 * X 1:0d2164f0ce0d
197 * X 1:0d2164f0ce0d
198 Y 3:f6fc62dde3c0
198 Y 3:f6fc62dde3c0
199 Z 1:0d2164f0ce0d
199 Z 1:0d2164f0ce0d
200
200
201 hgweb
201 hgweb
202
202
203 $ cat <<EOF > .hg/hgrc
203 $ cat <<EOF > .hg/hgrc
204 > [web]
204 > [web]
205 > push_ssl = false
205 > push_ssl = false
206 > allow_push = *
206 > allow_push = *
207 > EOF
207 > EOF
208
208
209 $ hg serve -p $HGPORT -d --pid-file=../hg.pid -E errors.log
209 $ hg serve -p $HGPORT -d --pid-file=../hg.pid -E errors.log
210 $ cat ../hg.pid >> $DAEMON_PIDS
210 $ cat ../hg.pid >> $DAEMON_PIDS
211 $ cd ../a
211 $ cd ../a
212
212
213 $ hg debugpushkey http://localhost:$HGPORT/ namespaces
213 $ hg debugpushkey http://localhost:$HGPORT/ namespaces
214 bookmarks
214 bookmarks
215 phases
215 phases
216 namespaces
216 namespaces
217 $ hg debugpushkey http://localhost:$HGPORT/ bookmarks
217 $ hg debugpushkey http://localhost:$HGPORT/ bookmarks
218 Y 4efff6d98829d9c824c621afd6e3f01865f5439f
218 Y 4efff6d98829d9c824c621afd6e3f01865f5439f
219 foobar 9b140be1080824d768c5a4691a564088eede71f9
219 foobar 9b140be1080824d768c5a4691a564088eede71f9
220 Z 0d2164f0ce0d8f1d6f94351eba04b794909be66c
220 Z 0d2164f0ce0d8f1d6f94351eba04b794909be66c
221 foo 0000000000000000000000000000000000000000
221 foo 0000000000000000000000000000000000000000
222 X 9b140be1080824d768c5a4691a564088eede71f9
222 X 9b140be1080824d768c5a4691a564088eede71f9
223 $ hg out -B http://localhost:$HGPORT/
223 $ hg out -B http://localhost:$HGPORT/
224 comparing with http://localhost:$HGPORT/
224 comparing with http://localhost:$HGPORT/
225 searching for changed bookmarks
225 searching for changed bookmarks
226 no changed bookmarks found
226 no changed bookmarks found
227 [1]
227 [1]
228 $ hg push -B Z http://localhost:$HGPORT/
228 $ hg push -B Z http://localhost:$HGPORT/
229 pushing to http://localhost:$HGPORT/
229 pushing to http://localhost:$HGPORT/
230 searching for changes
230 searching for changes
231 no changes found
231 no changes found
232 exporting bookmark Z
232 exporting bookmark Z
233 [1]
233 [1]
234 $ hg book -d Z
234 $ hg book -d Z
235 $ hg in -B http://localhost:$HGPORT/
235 $ hg in -B http://localhost:$HGPORT/
236 comparing with http://localhost:$HGPORT/
236 comparing with http://localhost:$HGPORT/
237 searching for changed bookmarks
237 searching for changed bookmarks
238 Z 0d2164f0ce0d
238 Z 0d2164f0ce0d
239 foo 000000000000
239 foo 000000000000
240 foobar 9b140be10808
240 foobar 9b140be10808
241 $ hg pull -B Z http://localhost:$HGPORT/
241 $ hg pull -B Z http://localhost:$HGPORT/
242 pulling from http://localhost:$HGPORT/
242 pulling from http://localhost:$HGPORT/
243 no changes found
243 no changes found
244 adding remote bookmark foobar
244 adding remote bookmark foobar
245 adding remote bookmark Z
245 adding remote bookmark Z
246 adding remote bookmark foo
246 adding remote bookmark foo
247 divergent bookmark X stored as X@1
247 divergent bookmark X stored as X@1
248 importing bookmark Z
248 importing bookmark Z
249 $ hg clone http://localhost:$HGPORT/ cloned-bookmarks
249 $ hg clone http://localhost:$HGPORT/ cloned-bookmarks
250 requesting all changes
250 requesting all changes
251 adding changesets
251 adding changesets
252 adding manifests
252 adding manifests
253 adding file changes
253 adding file changes
254 added 5 changesets with 5 changes to 3 files (+3 heads)
254 added 5 changesets with 5 changes to 3 files (+3 heads)
255 updating to branch default
255 updating to branch default
256 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
256 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
257 $ hg -R cloned-bookmarks bookmarks
257 $ hg -R cloned-bookmarks bookmarks
258 X 1:9b140be10808
258 X 1:9b140be10808
259 Y 4:4efff6d98829
259 Y 4:4efff6d98829
260 Z 2:0d2164f0ce0d
260 Z 2:0d2164f0ce0d
261 foo -1:000000000000
261 foo -1:000000000000
262 foobar 1:9b140be10808
262 foobar 1:9b140be10808
263
263
264 $ cd ..
264 $ cd ..
265
265
266 Pushing a bookmark should only push the changes required by that
266 Pushing a bookmark should only push the changes required by that
267 bookmark, not all outgoing changes:
267 bookmark, not all outgoing changes:
268 $ hg clone http://localhost:$HGPORT/ addmarks
268 $ hg clone http://localhost:$HGPORT/ addmarks
269 requesting all changes
269 requesting all changes
270 adding changesets
270 adding changesets
271 adding manifests
271 adding manifests
272 adding file changes
272 adding file changes
273 added 5 changesets with 5 changes to 3 files (+3 heads)
273 added 5 changesets with 5 changes to 3 files (+3 heads)
274 updating to branch default
274 updating to branch default
275 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
275 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
276 $ cd addmarks
276 $ cd addmarks
277 $ echo foo > foo
277 $ echo foo > foo
278 $ hg add foo
278 $ hg add foo
279 $ hg commit -m 'add foo'
279 $ hg commit -m 'add foo'
280 $ echo bar > bar
280 $ echo bar > bar
281 $ hg add bar
281 $ hg add bar
282 $ hg commit -m 'add bar'
282 $ hg commit -m 'add bar'
283 $ hg co "tip^"
283 $ hg co "tip^"
284 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
284 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
285 $ hg book add-foo
285 $ hg book add-foo
286 $ hg book -r tip add-bar
286 $ hg book -r tip add-bar
287 Note: this push *must* push only a single changeset, as that's the point
287 Note: this push *must* push only a single changeset, as that's the point
288 of this test.
288 of this test.
289 $ hg push -B add-foo
289 $ hg push -B add-foo --traceback
290 pushing to http://localhost:$HGPORT/
290 pushing to http://localhost:$HGPORT/
291 searching for changes
291 searching for changes
292 remote: adding changesets
292 remote: adding changesets
293 remote: adding manifests
293 remote: adding manifests
294 remote: adding file changes
294 remote: adding file changes
295 remote: added 1 changesets with 1 changes to 1 files
295 remote: added 1 changesets with 1 changes to 1 files
296 exporting bookmark add-foo
296 exporting bookmark add-foo
297
297
298 $ cd ..
298 $ cd ..
@@ -1,161 +1,273 b''
1 Check that obsolete properly strip heads
1 Check that obsolete properly strip heads
2 $ cat > obs.py << EOF
2 $ cat > obs.py << EOF
3 > import mercurial.obsolete
3 > import mercurial.obsolete
4 > mercurial.obsolete._enabled = True
4 > mercurial.obsolete._enabled = True
5 > EOF
5 > EOF
6 $ cat >> $HGRCPATH << EOF
6 $ cat >> $HGRCPATH << EOF
7 > [phases]
7 > [phases]
8 > # public changeset are not obsolete
8 > # public changeset are not obsolete
9 > publish=false
9 > publish=false
10 > [ui]
10 > [ui]
11 > logtemplate='{node|short} ({phase}) {desc|firstline}\n'
11 > logtemplate='{node|short} ({phase}) {desc|firstline}\n'
12 > [extensions]
12 > [extensions]
13 > graphlog=
13 > graphlog=
14 > EOF
14 > EOF
15 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
15 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
16 $ mkcommit() {
16 $ mkcommit() {
17 > echo "$1" > "$1"
17 > echo "$1" > "$1"
18 > hg add "$1"
18 > hg add "$1"
19 > hg ci -m "add $1"
19 > hg ci -m "add $1"
20 > }
20 > }
21 $ getid() {
21 $ getid() {
22 > hg id --debug -ir "desc('$1')"
22 > hg id --debug -ir "desc('$1')"
23 > }
23 > }
24
24
25
25
26 $ hg init remote
26 $ hg init remote
27 $ cd remote
27 $ cd remote
28 $ mkcommit base
28 $ mkcommit base
29 $ hg phase --public .
29 $ hg phase --public .
30 $ cd ..
30 $ cd ..
31 $ cp -r remote base
31 $ cp -r remote base
32 $ hg clone remote local
32 $ hg clone remote local
33 updating to branch default
33 updating to branch default
34 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
34 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
35 $ cd local
35 $ cd local
36
36
37 New head replaces old head
37 New head replaces old head
38 ==========================
38 ==========================
39
39
40 setup
40 setup
41
41
42 $ mkcommit old
42 $ mkcommit old
43 $ hg push
43 $ hg push
44 pushing to $TESTTMP/remote
44 pushing to $TESTTMP/remote
45 searching for changes
45 searching for changes
46 adding changesets
46 adding changesets
47 adding manifests
47 adding manifests
48 adding file changes
48 adding file changes
49 added 1 changesets with 1 changes to 1 files
49 added 1 changesets with 1 changes to 1 files
50 $ hg up -q '.^'
50 $ hg up -q '.^'
51 $ mkcommit new
51 $ mkcommit new
52 created new head
52 created new head
53 $ hg debugobsolete `getid old` `getid new`
53 $ hg debugobsolete `getid old` `getid new`
54 $ hg glog --hidden
54 $ hg glog --hidden
55 @ 71e3228bffe1 (draft) add new
55 @ 71e3228bffe1 (draft) add new
56 |
56 |
57 | x c70b08862e08 (draft) add old
57 | x c70b08862e08 (draft) add old
58 |/
58 |/
59 o b4952fcf48cf (public) add base
59 o b4952fcf48cf (public) add base
60
60
61 $ cp -r ../remote ../backup1
61 $ cp -r ../remote ../backup1
62
62
63 old exists remotely as draft. It is obsoleted by new that we now push.
63 old exists remotely as draft. It is obsoleted by new that we now push.
64 Push should not warn about creating new head
64 Push should not warn about creating new head
65
65
66 $ hg push
66 $ hg push
67 pushing to $TESTTMP/remote
67 pushing to $TESTTMP/remote
68 searching for changes
68 searching for changes
69 adding changesets
69 adding changesets
70 adding manifests
70 adding manifests
71 adding file changes
71 adding file changes
72 added 1 changesets with 1 changes to 1 files (+1 heads)
72 added 1 changesets with 1 changes to 1 files (+1 heads)
73
73
74 old head is now public (public local version)
74 old head is now public (public local version)
75 =============================================
75 =============================================
76
76
77 setup
77 setup
78
78
79 $ rm -fr ../remote
79 $ rm -fr ../remote
80 $ cp -r ../backup1 ../remote
80 $ cp -r ../backup1 ../remote
81 $ hg -R ../remote phase --public c70b08862e08
81 $ hg -R ../remote phase --public c70b08862e08
82 $ hg pull -v
82 $ hg pull -v
83 pulling from $TESTTMP/remote
83 pulling from $TESTTMP/remote
84 searching for changes
84 searching for changes
85 no changes found
85 no changes found
86 $ hg glog --hidden
86 $ hg glog --hidden
87 @ 71e3228bffe1 (draft) add new
87 @ 71e3228bffe1 (draft) add new
88 |
88 |
89 | o c70b08862e08 (public) add old
89 | o c70b08862e08 (public) add old
90 |/
90 |/
91 o b4952fcf48cf (public) add base
91 o b4952fcf48cf (public) add base
92
92
93
93
94 Abort: old will still be an head because it's public.
94 Abort: old will still be an head because it's public.
95
95
96 $ hg push
96 $ hg push
97 pushing to $TESTTMP/remote
97 pushing to $TESTTMP/remote
98 searching for changes
98 searching for changes
99 abort: push creates new remote head 71e3228bffe1!
99 abort: push creates new remote head 71e3228bffe1!
100 (did you forget to merge? use push -f to force)
100 (did you forget to merge? use push -f to force)
101 [255]
101 [255]
102
102
103 old head is now public (public remote version)
103 old head is now public (public remote version)
104 ==============================================
104 ==============================================
105
105
106 TODO: Not implemented yet.
106 TODO: Not implemented yet.
107
107
108 # setup
108 # setup
109 #
109 #
110 # $ rm -fr ../remote
110 # $ rm -fr ../remote
111 # $ cp -r ../backup1 ../remote
111 # $ cp -r ../backup1 ../remote
112 # $ hg -R ../remote phase --public c70b08862e08
112 # $ hg -R ../remote phase --public c70b08862e08
113 # $ hg phase --draft --force c70b08862e08
113 # $ hg phase --draft --force c70b08862e08
114 # $ hg glog --hidden
114 # $ hg glog --hidden
115 # @ 71e3228bffe1 (draft) add new
115 # @ 71e3228bffe1 (draft) add new
116 # |
116 # |
117 # | x c70b08862e08 (draft) add old
117 # | x c70b08862e08 (draft) add old
118 # |/
118 # |/
119 # o b4952fcf48cf (public) add base
119 # o b4952fcf48cf (public) add base
120 #
120 #
121 #
121 #
122 #
122 #
123 # Abort: old will still be an head because it's public.
123 # Abort: old will still be an head because it's public.
124 #
124 #
125 # $ hg push
125 # $ hg push
126 # pushing to $TESTTMP/remote
126 # pushing to $TESTTMP/remote
127 # searching for changes
127 # searching for changes
128 # abort: push creates new remote head 71e3228bffe1!
128 # abort: push creates new remote head 71e3228bffe1!
129 # (did you forget to merge? use push -f to force)
129 # (did you forget to merge? use push -f to force)
130 # [255]
130 # [255]
131
131
132 old head is obsolete but replacement is not pushed
132 old head is obsolete but replacement is not pushed
133 ==================================================
133 ==================================================
134
134
135 setup
135 setup
136
136
137 $ rm -fr ../remote
137 $ rm -fr ../remote
138 $ cp -r ../backup1 ../remote
138 $ cp -r ../backup1 ../remote
139 $ hg phase --draft --force '(0::) - 0'
139 $ hg phase --draft --force '(0::) - 0'
140 $ hg up -q '.^'
140 $ hg up -q '.^'
141 $ mkcommit other
141 $ mkcommit other
142 created new head
142 created new head
143 $ hg glog --hidden
143 $ hg glog --hidden
144 @ d7d41ccbd4de (draft) add other
144 @ d7d41ccbd4de (draft) add other
145 |
145 |
146 | o 71e3228bffe1 (draft) add new
146 | o 71e3228bffe1 (draft) add new
147 |/
147 |/
148 | x c70b08862e08 (draft) add old
148 | x c70b08862e08 (draft) add old
149 |/
149 |/
150 o b4952fcf48cf (public) add base
150 o b4952fcf48cf (public) add base
151
151
152
152
153 old exists remotely as draft. It is obsoleted by new but we don't push new.
153 old exists remotely as draft. It is obsoleted by new but we don't push new.
154 Push should abort on new head
154 Push should abort on new head
155
155
156 $ hg push -r 'desc("other")'
156 $ hg push -r 'desc("other")'
157 pushing to $TESTTMP/remote
157 pushing to $TESTTMP/remote
158 searching for changes
158 searching for changes
159 abort: push creates new remote head d7d41ccbd4de!
159 abort: push creates new remote head d7d41ccbd4de!
160 (did you forget to merge? use push -f to force)
160 (did you forget to merge? use push -f to force)
161 [255]
161 [255]
162
163
164
165 Both precursors and successors are already know remotely. Descendant adds heads
166 ===============================================================================
167
168 setup. (The obsolete marker is known locally only
169
170 $ cd ..
171 $ rm -rf local
172 $ hg clone remote local
173 updating to branch default
174 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
175 $ cd local
176 $ mkcommit old
177 old already tracked!
178 nothing changed
179 [1]
180 $ hg up -q '.^'
181 $ mkcommit new
182 created new head
183 $ hg push -f
184 pushing to $TESTTMP/remote
185 searching for changes
186 adding changesets
187 adding manifests
188 adding file changes
189 added 1 changesets with 1 changes to 1 files (+1 heads)
190 $ mkcommit desc1
191 $ hg up -q '.^'
192 $ mkcommit desc2
193 created new head
194 $ hg debugobsolete `getid old` `getid new`
195 $ hg glog --hidden
196 @ 5fe37041cc2b (draft) add desc2
197 |
198 | o a3ef1d111c5f (draft) add desc1
199 |/
200 o 71e3228bffe1 (draft) add new
201 |
202 | x c70b08862e08 (draft) add old
203 |/
204 o b4952fcf48cf (public) add base
205
206 $ hg glog --hidden -R ../remote
207 o 71e3228bffe1 (draft) add new
208 |
209 | o c70b08862e08 (draft) add old
210 |/
211 @ b4952fcf48cf (public) add base
212
213 $ cp -r ../remote ../backup2
214
215 Push should not warn about adding new heads. We create one, but we'll delete
216 one anyway.
217
218 $ hg push
219 pushing to $TESTTMP/remote
220 searching for changes
221 adding changesets
222 adding manifests
223 adding file changes
224 added 2 changesets with 2 changes to 2 files (+1 heads)
225
226
227 Remote head is unknown but obsoleted by a local changeset
228 =========================================================
229
230 setup
231
232 $ rm -fr ../remote
233 $ cp -r ../backup1 ../remote
234 $ cd ..
235 $ rm -rf local
236 $ hg clone remote local -r 0
237 adding changesets
238 adding manifests
239 adding file changes
240 added 1 changesets with 1 changes to 1 files
241 updating to branch default
242 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
243 $ cd local
244 $ mkcommit new
245 $ hg -R ../remote id --debug -r tip
246 c70b08862e0838ea6d7c59c85da2f1ed6c8d67da tip
247 $ hg id --debug -r tip
248 71e3228bffe1886550777233d6c97bb5a6b2a650 tip
249 $ hg debugobsolete c70b08862e0838ea6d7c59c85da2f1ed6c8d67da 71e3228bffe1886550777233d6c97bb5a6b2a650
250 $ hg glog --hidden
251 @ 71e3228bffe1 (draft) add new
252 |
253 o b4952fcf48cf (public) add base
254
255 $ hg glog --hidden -R ../remote
256 o c70b08862e08 (draft) add old
257 |
258 @ b4952fcf48cf (public) add base
259
260
261 Push should not complain about new heads.
262
263 It should not complain about "unsynced remote changes!" either but that's not
264 handled yet.
265
266 $ hg push --traceback
267 pushing to $TESTTMP/remote
268 searching for changes
269 note: unsynced remote changes!
270 adding changesets
271 adding manifests
272 adding file changes
273 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