##// END OF EJS Templates
discovery: improve "note: unsynced remote changes!" warning...
Mads Kiilerich -
r20501:8a9e0b52 default
parent child Browse files
Show More
@@ -1,356 +1,358 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, bookmarks
10 import util, setdiscovery, treediscovery, phases, obsolete, bookmarks
11 import branchmap
11 import branchmap
12
12
13 def findcommonincoming(repo, remote, heads=None, force=False):
13 def findcommonincoming(repo, remote, heads=None, force=False):
14 """Return a tuple (common, anyincoming, heads) used to identify the common
14 """Return a tuple (common, anyincoming, heads) used to identify the common
15 subset of nodes between repo and remote.
15 subset of nodes between repo and remote.
16
16
17 "common" is a list of (at least) the heads of the common subset.
17 "common" is a list of (at least) the heads of the common subset.
18 "anyincoming" is testable as a boolean indicating if any nodes are missing
18 "anyincoming" is testable as a boolean indicating if any nodes are missing
19 locally. If remote does not support getbundle, this actually is a list of
19 locally. If remote does not support getbundle, this actually is a list of
20 roots of the nodes that would be incoming, to be supplied to
20 roots of the nodes that would be incoming, to be supplied to
21 changegroupsubset. No code except for pull should be relying on this fact
21 changegroupsubset. No code except for pull should be relying on this fact
22 any longer.
22 any longer.
23 "heads" is either the supplied heads, or else the remote's heads.
23 "heads" is either the supplied heads, or else the remote's heads.
24
24
25 If you pass heads and they are all known locally, the response lists just
25 If you pass heads and they are all known locally, the response lists just
26 these heads in "common" and in "heads".
26 these heads in "common" and in "heads".
27
27
28 Please use findcommonoutgoing to compute the set of outgoing nodes to give
28 Please use findcommonoutgoing to compute the set of outgoing nodes to give
29 extensions a good hook into outgoing.
29 extensions a good hook into outgoing.
30 """
30 """
31
31
32 if not remote.capable('getbundle'):
32 if not remote.capable('getbundle'):
33 return treediscovery.findcommonincoming(repo, remote, heads, force)
33 return treediscovery.findcommonincoming(repo, remote, heads, force)
34
34
35 if heads:
35 if heads:
36 allknown = True
36 allknown = True
37 knownnode = repo.changelog.hasnode # no nodemap until it is filtered
37 knownnode = repo.changelog.hasnode # no nodemap until it is filtered
38 for h in heads:
38 for h in heads:
39 if not knownnode(h):
39 if not knownnode(h):
40 allknown = False
40 allknown = False
41 break
41 break
42 if allknown:
42 if allknown:
43 return (heads, False, heads)
43 return (heads, False, heads)
44
44
45 res = setdiscovery.findcommonheads(repo.ui, repo, remote,
45 res = setdiscovery.findcommonheads(repo.ui, repo, remote,
46 abortwhenunrelated=not force)
46 abortwhenunrelated=not force)
47 common, anyinc, srvheads = res
47 common, anyinc, srvheads = res
48 return (list(common), anyinc, heads or list(srvheads))
48 return (list(common), anyinc, heads or list(srvheads))
49
49
50 class outgoing(object):
50 class outgoing(object):
51 '''Represents the set of nodes present in a local repo but not in a
51 '''Represents the set of nodes present in a local repo but not in a
52 (possibly) remote one.
52 (possibly) remote one.
53
53
54 Members:
54 Members:
55
55
56 missing is a list of all nodes present in local but not in remote.
56 missing is a list of all nodes present in local but not in remote.
57 common is a list of all nodes shared between the two repos.
57 common is a list of all nodes shared between the two repos.
58 excluded is the list of missing changeset that shouldn't be sent remotely.
58 excluded is the list of missing changeset that shouldn't be sent remotely.
59 missingheads is the list of heads of missing.
59 missingheads is the list of heads of missing.
60 commonheads is the list of heads of common.
60 commonheads is the list of heads of common.
61
61
62 The sets are computed on demand from the heads, unless provided upfront
62 The sets are computed on demand from the heads, unless provided upfront
63 by discovery.'''
63 by discovery.'''
64
64
65 def __init__(self, revlog, commonheads, missingheads):
65 def __init__(self, revlog, commonheads, missingheads):
66 self.commonheads = commonheads
66 self.commonheads = commonheads
67 self.missingheads = missingheads
67 self.missingheads = missingheads
68 self._revlog = revlog
68 self._revlog = revlog
69 self._common = None
69 self._common = None
70 self._missing = None
70 self._missing = None
71 self.excluded = []
71 self.excluded = []
72
72
73 def _computecommonmissing(self):
73 def _computecommonmissing(self):
74 sets = self._revlog.findcommonmissing(self.commonheads,
74 sets = self._revlog.findcommonmissing(self.commonheads,
75 self.missingheads)
75 self.missingheads)
76 self._common, self._missing = sets
76 self._common, self._missing = sets
77
77
78 @util.propertycache
78 @util.propertycache
79 def common(self):
79 def common(self):
80 if self._common is None:
80 if self._common is None:
81 self._computecommonmissing()
81 self._computecommonmissing()
82 return self._common
82 return self._common
83
83
84 @util.propertycache
84 @util.propertycache
85 def missing(self):
85 def missing(self):
86 if self._missing is None:
86 if self._missing is None:
87 self._computecommonmissing()
87 self._computecommonmissing()
88 return self._missing
88 return self._missing
89
89
90 def findcommonoutgoing(repo, other, onlyheads=None, force=False,
90 def findcommonoutgoing(repo, other, onlyheads=None, force=False,
91 commoninc=None, portable=False):
91 commoninc=None, portable=False):
92 '''Return an outgoing instance to identify the nodes present in repo but
92 '''Return an outgoing instance to identify the nodes present in repo but
93 not in other.
93 not in other.
94
94
95 If onlyheads is given, only nodes ancestral to nodes in onlyheads
95 If onlyheads is given, only nodes ancestral to nodes in onlyheads
96 (inclusive) are included. If you already know the local repo's heads,
96 (inclusive) are included. If you already know the local repo's heads,
97 passing them in onlyheads is faster than letting them be recomputed here.
97 passing them in onlyheads is faster than letting them be recomputed here.
98
98
99 If commoninc is given, it must be the result of a prior call to
99 If commoninc is given, it must be the result of a prior call to
100 findcommonincoming(repo, other, force) to avoid recomputing it here.
100 findcommonincoming(repo, other, force) to avoid recomputing it here.
101
101
102 If portable is given, compute more conservative common and missingheads,
102 If portable is given, compute more conservative common and missingheads,
103 to make bundles created from the instance more portable.'''
103 to make bundles created from the instance more portable.'''
104 # declare an empty outgoing object to be filled later
104 # declare an empty outgoing object to be filled later
105 og = outgoing(repo.changelog, None, None)
105 og = outgoing(repo.changelog, None, None)
106
106
107 # get common set if not provided
107 # get common set if not provided
108 if commoninc is None:
108 if commoninc is None:
109 commoninc = findcommonincoming(repo, other, force=force)
109 commoninc = findcommonincoming(repo, other, force=force)
110 og.commonheads, _any, _hds = commoninc
110 og.commonheads, _any, _hds = commoninc
111
111
112 # compute outgoing
112 # compute outgoing
113 mayexclude = (repo._phasecache.phaseroots[phases.secret] or repo.obsstore)
113 mayexclude = (repo._phasecache.phaseroots[phases.secret] or repo.obsstore)
114 if not mayexclude:
114 if not mayexclude:
115 og.missingheads = onlyheads or repo.heads()
115 og.missingheads = onlyheads or repo.heads()
116 elif onlyheads is None:
116 elif onlyheads is None:
117 # use visible heads as it should be cached
117 # use visible heads as it should be cached
118 og.missingheads = repo.filtered("served").heads()
118 og.missingheads = repo.filtered("served").heads()
119 og.excluded = [ctx.node() for ctx in repo.set('secret() or extinct()')]
119 og.excluded = [ctx.node() for ctx in repo.set('secret() or extinct()')]
120 else:
120 else:
121 # compute common, missing and exclude secret stuff
121 # compute common, missing and exclude secret stuff
122 sets = repo.changelog.findcommonmissing(og.commonheads, onlyheads)
122 sets = repo.changelog.findcommonmissing(og.commonheads, onlyheads)
123 og._common, allmissing = sets
123 og._common, allmissing = sets
124 og._missing = missing = []
124 og._missing = missing = []
125 og.excluded = excluded = []
125 og.excluded = excluded = []
126 for node in allmissing:
126 for node in allmissing:
127 ctx = repo[node]
127 ctx = repo[node]
128 if ctx.phase() >= phases.secret or ctx.extinct():
128 if ctx.phase() >= phases.secret or ctx.extinct():
129 excluded.append(node)
129 excluded.append(node)
130 else:
130 else:
131 missing.append(node)
131 missing.append(node)
132 if len(missing) == len(allmissing):
132 if len(missing) == len(allmissing):
133 missingheads = onlyheads
133 missingheads = onlyheads
134 else: # update missing heads
134 else: # update missing heads
135 missingheads = phases.newheads(repo, onlyheads, excluded)
135 missingheads = phases.newheads(repo, onlyheads, excluded)
136 og.missingheads = missingheads
136 og.missingheads = missingheads
137 if portable:
137 if portable:
138 # recompute common and missingheads as if -r<rev> had been given for
138 # recompute common and missingheads as if -r<rev> had been given for
139 # each head of missing, and --base <rev> for each head of the proper
139 # each head of missing, and --base <rev> for each head of the proper
140 # ancestors of missing
140 # ancestors of missing
141 og._computecommonmissing()
141 og._computecommonmissing()
142 cl = repo.changelog
142 cl = repo.changelog
143 missingrevs = set(cl.rev(n) for n in og._missing)
143 missingrevs = set(cl.rev(n) for n in og._missing)
144 og._common = set(cl.ancestors(missingrevs)) - missingrevs
144 og._common = set(cl.ancestors(missingrevs)) - missingrevs
145 commonheads = set(og.commonheads)
145 commonheads = set(og.commonheads)
146 og.missingheads = [h for h in og.missingheads if h not in commonheads]
146 og.missingheads = [h for h in og.missingheads if h not in commonheads]
147
147
148 return og
148 return og
149
149
150 def _headssummary(repo, remote, outgoing):
150 def _headssummary(repo, remote, outgoing):
151 """compute a summary of branch and heads status before and after push
151 """compute a summary of branch and heads status before and after push
152
152
153 return {'branch': ([remoteheads], [newheads], [unsyncedheads])} mapping
153 return {'branch': ([remoteheads], [newheads], [unsyncedheads])} mapping
154
154
155 - branch: the branch name
155 - branch: the branch name
156 - remoteheads: the list of remote heads known locally
156 - remoteheads: the list of remote heads known locally
157 None if the branch is new
157 None if the branch is new
158 - newheads: the new remote heads (known locally) with outgoing pushed
158 - newheads: the new remote heads (known locally) with outgoing pushed
159 - unsyncedheads: the list of remote heads unknown locally.
159 - unsyncedheads: the list of remote heads unknown locally.
160 """
160 """
161 cl = repo.changelog
161 cl = repo.changelog
162 headssum = {}
162 headssum = {}
163 # A. Create set of branches involved in the push.
163 # A. Create set of branches involved in the push.
164 branches = set(repo[n].branch() for n in outgoing.missing)
164 branches = set(repo[n].branch() for n in outgoing.missing)
165 remotemap = remote.branchmap()
165 remotemap = remote.branchmap()
166 newbranches = branches - set(remotemap)
166 newbranches = branches - set(remotemap)
167 branches.difference_update(newbranches)
167 branches.difference_update(newbranches)
168
168
169 # A. register remote heads
169 # A. register remote heads
170 remotebranches = set()
170 remotebranches = set()
171 for branch, heads in remote.branchmap().iteritems():
171 for branch, heads in remote.branchmap().iteritems():
172 remotebranches.add(branch)
172 remotebranches.add(branch)
173 known = []
173 known = []
174 unsynced = []
174 unsynced = []
175 knownnode = cl.hasnode # do not use nodemap until it is filtered
175 knownnode = cl.hasnode # do not use nodemap until it is filtered
176 for h in heads:
176 for h in heads:
177 if knownnode(h):
177 if knownnode(h):
178 known.append(h)
178 known.append(h)
179 else:
179 else:
180 unsynced.append(h)
180 unsynced.append(h)
181 headssum[branch] = (known, list(known), unsynced)
181 headssum[branch] = (known, list(known), unsynced)
182 # B. add new branch data
182 # B. add new branch data
183 missingctx = list(repo[n] for n in outgoing.missing)
183 missingctx = list(repo[n] for n in outgoing.missing)
184 touchedbranches = set()
184 touchedbranches = set()
185 for ctx in missingctx:
185 for ctx in missingctx:
186 branch = ctx.branch()
186 branch = ctx.branch()
187 touchedbranches.add(branch)
187 touchedbranches.add(branch)
188 if branch not in headssum:
188 if branch not in headssum:
189 headssum[branch] = (None, [], [])
189 headssum[branch] = (None, [], [])
190
190
191 # C drop data about untouched branches:
191 # C drop data about untouched branches:
192 for branch in remotebranches - touchedbranches:
192 for branch in remotebranches - touchedbranches:
193 del headssum[branch]
193 del headssum[branch]
194
194
195 # D. Update newmap with outgoing changes.
195 # D. Update newmap with outgoing changes.
196 # This will possibly add new heads and remove existing ones.
196 # This will possibly add new heads and remove existing ones.
197 newmap = branchmap.branchcache((branch, heads[1])
197 newmap = branchmap.branchcache((branch, heads[1])
198 for branch, heads in headssum.iteritems()
198 for branch, heads in headssum.iteritems()
199 if heads[0] is not None)
199 if heads[0] is not None)
200 newmap.update(repo, (ctx.rev() for ctx in missingctx))
200 newmap.update(repo, (ctx.rev() for ctx in missingctx))
201 for branch, newheads in newmap.iteritems():
201 for branch, newheads in newmap.iteritems():
202 headssum[branch][1][:] = newheads
202 headssum[branch][1][:] = newheads
203 return headssum
203 return headssum
204
204
205 def _oldheadssummary(repo, remoteheads, outgoing, inc=False):
205 def _oldheadssummary(repo, remoteheads, outgoing, inc=False):
206 """Compute branchmapsummary for repo without branchmap support"""
206 """Compute branchmapsummary for repo without branchmap support"""
207
207
208 # 1-4b. old servers: Check for new topological heads.
208 # 1-4b. old servers: Check for new topological heads.
209 # Construct {old,new}map with branch = None (topological branch).
209 # Construct {old,new}map with branch = None (topological branch).
210 # (code based on update)
210 # (code based on update)
211 knownnode = repo.changelog.hasnode # no nodemap until it is filtered
211 knownnode = repo.changelog.hasnode # no nodemap until it is filtered
212 oldheads = set(h for h in remoteheads if knownnode(h))
212 oldheads = set(h for h in remoteheads if knownnode(h))
213 # all nodes in outgoing.missing are children of either:
213 # all nodes in outgoing.missing are children of either:
214 # - an element of oldheads
214 # - an element of oldheads
215 # - another element of outgoing.missing
215 # - another element of outgoing.missing
216 # - nullrev
216 # - nullrev
217 # This explains why the new head are very simple to compute.
217 # This explains why the new head are very simple to compute.
218 r = repo.set('heads(%ln + %ln)', oldheads, outgoing.missing)
218 r = repo.set('heads(%ln + %ln)', oldheads, outgoing.missing)
219 newheads = list(c.node() for c in r)
219 newheads = list(c.node() for c in r)
220 unsynced = inc and set([None]) or set()
220 unsynced = inc and set([None]) or set()
221 return {None: (oldheads, newheads, unsynced)}
221 return {None: (oldheads, newheads, unsynced)}
222
222
223 def checkheads(repo, remote, outgoing, remoteheads, newbranch=False, inc=False,
223 def checkheads(repo, remote, outgoing, remoteheads, newbranch=False, inc=False,
224 newbookmarks=[]):
224 newbookmarks=[]):
225 """Check that a push won't add any outgoing head
225 """Check that a push won't add any outgoing head
226
226
227 raise Abort error and display ui message as needed.
227 raise Abort error and display ui message as needed.
228 """
228 """
229 # Check for each named branch if we're creating new remote heads.
229 # Check for each named branch if we're creating new remote heads.
230 # To be a remote head after push, node must be either:
230 # To be a remote head after push, node must be either:
231 # - unknown locally
231 # - unknown locally
232 # - a local outgoing head descended from update
232 # - a local outgoing head descended from update
233 # - a remote head that's known locally and not
233 # - a remote head that's known locally and not
234 # ancestral to an outgoing head
234 # ancestral to an outgoing head
235 if remoteheads == [nullid]:
235 if remoteheads == [nullid]:
236 # remote is empty, nothing to check.
236 # remote is empty, nothing to check.
237 return
237 return
238
238
239 if remote.capable('branchmap'):
239 if remote.capable('branchmap'):
240 headssum = _headssummary(repo, remote, outgoing)
240 headssum = _headssummary(repo, remote, outgoing)
241 else:
241 else:
242 headssum = _oldheadssummary(repo, remoteheads, outgoing, inc)
242 headssum = _oldheadssummary(repo, remoteheads, outgoing, inc)
243 newbranches = [branch for branch, heads in headssum.iteritems()
243 newbranches = [branch for branch, heads in headssum.iteritems()
244 if heads[0] is None]
244 if heads[0] is None]
245 # 1. Check for new branches on the remote.
245 # 1. Check for new branches on the remote.
246 if newbranches and not newbranch: # new branch requires --new-branch
246 if newbranches and not newbranch: # new branch requires --new-branch
247 branchnames = ', '.join(sorted(newbranches))
247 branchnames = ', '.join(sorted(newbranches))
248 raise util.Abort(_("push creates new remote branches: %s!")
248 raise util.Abort(_("push creates new remote branches: %s!")
249 % branchnames,
249 % branchnames,
250 hint=_("use 'hg push --new-branch' to create"
250 hint=_("use 'hg push --new-branch' to create"
251 " new remote branches"))
251 " new remote branches"))
252
252
253 # 2. Compute newly pushed bookmarks. We don't warn about bookmarked heads.
253 # 2. Compute newly pushed bookmarks. We don't warn about bookmarked heads.
254 localbookmarks = repo._bookmarks
254 localbookmarks = repo._bookmarks
255 remotebookmarks = remote.listkeys('bookmarks')
255 remotebookmarks = remote.listkeys('bookmarks')
256 bookmarkedheads = set()
256 bookmarkedheads = set()
257 for bm in localbookmarks:
257 for bm in localbookmarks:
258 rnode = remotebookmarks.get(bm)
258 rnode = remotebookmarks.get(bm)
259 if rnode and rnode in repo:
259 if rnode and rnode in repo:
260 lctx, rctx = repo[bm], repo[rnode]
260 lctx, rctx = repo[bm], repo[rnode]
261 if bookmarks.validdest(repo, rctx, lctx):
261 if bookmarks.validdest(repo, rctx, lctx):
262 bookmarkedheads.add(lctx.node())
262 bookmarkedheads.add(lctx.node())
263 else:
263 else:
264 if bm in newbookmarks:
264 if bm in newbookmarks:
265 bookmarkedheads.add(repo[bm].node())
265 bookmarkedheads.add(repo[bm].node())
266
266
267 # 3. Check for new heads.
267 # 3. Check for new heads.
268 # If there are more heads after the push than before, a suitable
268 # If there are more heads after the push than before, a suitable
269 # error message, depending on unsynced status, is displayed.
269 # error message, depending on unsynced status, is displayed.
270 error = None
270 error = None
271 unsynced = False
272 allmissing = set(outgoing.missing)
271 allmissing = set(outgoing.missing)
273 allfuturecommon = set(c.node() for c in repo.set('%ld', outgoing.common))
272 allfuturecommon = set(c.node() for c in repo.set('%ld', outgoing.common))
274 allfuturecommon.update(allmissing)
273 allfuturecommon.update(allmissing)
275 for branch, heads in sorted(headssum.iteritems()):
274 for branch, heads in sorted(headssum.iteritems()):
276 remoteheads, newheads, unsyncedheads = heads
275 remoteheads, newheads, unsyncedheads = heads
277 candidate_newhs = set(newheads)
276 candidate_newhs = set(newheads)
278 # add unsynced data
277 # add unsynced data
279 if remoteheads is None:
278 if remoteheads is None:
280 oldhs = set()
279 oldhs = set()
281 else:
280 else:
282 oldhs = set(remoteheads)
281 oldhs = set(remoteheads)
283 oldhs.update(unsyncedheads)
282 oldhs.update(unsyncedheads)
284 candidate_newhs.update(unsyncedheads)
283 candidate_newhs.update(unsyncedheads)
285 dhs = None # delta heads, the new heads on branch
284 dhs = None # delta heads, the new heads on branch
286 discardedheads = set()
285 discardedheads = set()
287 if repo.obsstore:
286 if repo.obsstore:
288 # remove future heads which are actually obsoleted by another
287 # remove future heads which are actually obsoleted by another
289 # pushed element:
288 # pushed element:
290 #
289 #
291 # XXX as above, There are several cases this case does not handle
290 # XXX as above, There are several cases this case does not handle
292 # XXX properly
291 # XXX properly
293 #
292 #
294 # (1) if <nh> is public, it won't be affected by obsolete marker
293 # (1) if <nh> is public, it won't be affected by obsolete marker
295 # and a new is created
294 # and a new is created
296 #
295 #
297 # (2) if the new heads have ancestors which are not obsolete and
296 # (2) if the new heads have ancestors which are not obsolete and
298 # not ancestors of any other heads we will have a new head too.
297 # not ancestors of any other heads we will have a new head too.
299 #
298 #
300 # These two cases will be easy to handle for known changeset but
299 # These two cases will be easy to handle for known changeset but
301 # much more tricky for unsynced changes.
300 # much more tricky for unsynced changes.
302 newhs = set()
301 newhs = set()
303 for nh in candidate_newhs:
302 for nh in candidate_newhs:
304 if nh in repo and repo[nh].phase() <= phases.public:
303 if nh in repo and repo[nh].phase() <= phases.public:
305 newhs.add(nh)
304 newhs.add(nh)
306 else:
305 else:
307 for suc in obsolete.allsuccessors(repo.obsstore, [nh]):
306 for suc in obsolete.allsuccessors(repo.obsstore, [nh]):
308 if suc != nh and suc in allfuturecommon:
307 if suc != nh and suc in allfuturecommon:
309 discardedheads.add(nh)
308 discardedheads.add(nh)
310 break
309 break
311 else:
310 else:
312 newhs.add(nh)
311 newhs.add(nh)
313 else:
312 else:
314 newhs = candidate_newhs
313 newhs = candidate_newhs
315 if [h for h in unsyncedheads if h not in discardedheads]:
314 unsynced = sorted(h for h in unsyncedheads if h not in discardedheads)
316 unsynced = True
315 if unsynced:
316 heads = ' '.join(short(h) for h in unsynced)
317 if branch is None:
318 repo.ui.warn(_("remote has heads that are "
319 "not known locally: %s\n") % heads)
320 else:
321 repo.ui.warn(_("remote has heads on branch '%s' that are "
322 "not known locally: %s\n") % (branch, heads))
317 if remoteheads is None:
323 if remoteheads is None:
318 if len(newhs) > 1:
324 if len(newhs) > 1:
319 dhs = list(newhs)
325 dhs = list(newhs)
320 if error is None:
326 if error is None:
321 error = (_("push creates new branch '%s' "
327 error = (_("push creates new branch '%s' "
322 "with multiple heads") % (branch))
328 "with multiple heads") % (branch))
323 hint = _("merge or"
329 hint = _("merge or"
324 " see \"hg help push\" for details about"
330 " see \"hg help push\" for details about"
325 " pushing new heads")
331 " pushing new heads")
326 elif len(newhs) > len(oldhs):
332 elif len(newhs) > len(oldhs):
327 # remove bookmarked or existing remote heads from the new heads list
333 # remove bookmarked or existing remote heads from the new heads list
328 dhs = sorted(newhs - bookmarkedheads - oldhs)
334 dhs = sorted(newhs - bookmarkedheads - oldhs)
329 if dhs:
335 if dhs:
330 if error is None:
336 if error is None:
331 if branch not in ('default', None):
337 if branch not in ('default', None):
332 error = _("push creates new remote head %s "
338 error = _("push creates new remote head %s "
333 "on branch '%s'!") % (short(dhs[0]), branch)
339 "on branch '%s'!") % (short(dhs[0]), branch)
334 else:
340 else:
335 error = _("push creates new remote head %s!"
341 error = _("push creates new remote head %s!"
336 ) % short(dhs[0])
342 ) % short(dhs[0])
337 if unsyncedheads:
343 if unsyncedheads:
338 hint = _("pull and merge or"
344 hint = _("pull and merge or"
339 " see \"hg help push\" for details about"
345 " see \"hg help push\" for details about"
340 " pushing new heads")
346 " pushing new heads")
341 else:
347 else:
342 hint = _("merge or"
348 hint = _("merge or"
343 " see \"hg help push\" for details about"
349 " see \"hg help push\" for details about"
344 " pushing new heads")
350 " pushing new heads")
345 if branch is None:
351 if branch is None:
346 repo.ui.note(_("new remote heads:\n"))
352 repo.ui.note(_("new remote heads:\n"))
347 else:
353 else:
348 repo.ui.note(_("new remote heads on branch '%s':\n") % branch)
354 repo.ui.note(_("new remote heads on branch '%s':\n") % branch)
349 for h in dhs:
355 for h in dhs:
350 repo.ui.note((" %s\n") % short(h))
356 repo.ui.note((" %s\n") % short(h))
351 if error:
357 if error:
352 raise util.Abort(error, hint=hint)
358 raise util.Abort(error, hint=hint)
353
354 # 6. Check for unsynced changes on involved branches.
355 if unsynced:
356 repo.ui.warn(_("note: unsynced remote changes!\n"))
@@ -1,752 +1,755 b''
1 $ hg init a
1 $ hg init a
2 $ cd a
2 $ cd a
3 $ echo foo > t1
3 $ echo foo > t1
4 $ hg add t1
4 $ hg add t1
5 $ hg commit -m "1"
5 $ hg commit -m "1"
6
6
7 $ cd ..
7 $ cd ..
8 $ hg clone a b
8 $ hg clone a b
9 updating to branch default
9 updating to branch default
10 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
10 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
11
11
12 $ cd a
12 $ cd a
13 $ echo foo > t2
13 $ echo foo > t2
14 $ hg add t2
14 $ hg add t2
15 $ hg commit -m "2"
15 $ hg commit -m "2"
16
16
17 $ cd ../b
17 $ cd ../b
18 $ echo foo > t3
18 $ echo foo > t3
19 $ hg add t3
19 $ hg add t3
20 $ hg commit -m "3"
20 $ hg commit -m "3"
21
21
22 $ hg push ../a
22 $ hg push ../a
23 pushing to ../a
23 pushing to ../a
24 searching for changes
24 searching for changes
25 remote has heads on branch 'default' that are not known locally: 1c9246a22a0a
25 abort: push creates new remote head 1e108cc5548c!
26 abort: push creates new remote head 1e108cc5548c!
26 (pull and merge or see "hg help push" for details about pushing new heads)
27 (pull and merge or see "hg help push" for details about pushing new heads)
27 [255]
28 [255]
28
29
29 $ hg push --debug ../a
30 $ hg push --debug ../a
30 pushing to ../a
31 pushing to ../a
31 query 1; heads
32 query 1; heads
32 searching for changes
33 searching for changes
33 taking quick initial sample
34 taking quick initial sample
34 searching: 2 queries
35 searching: 2 queries
35 query 2; still undecided: 1, sample size is: 1
36 query 2; still undecided: 1, sample size is: 1
36 2 total queries
37 2 total queries
37 listing keys for "bookmarks"
38 listing keys for "bookmarks"
39 remote has heads on branch 'default' that are not known locally: 1c9246a22a0a
38 new remote heads on branch 'default':
40 new remote heads on branch 'default':
39 1e108cc5548c
41 1e108cc5548c
40 abort: push creates new remote head 1e108cc5548c!
42 abort: push creates new remote head 1e108cc5548c!
41 (pull and merge or see "hg help push" for details about pushing new heads)
43 (pull and merge or see "hg help push" for details about pushing new heads)
42 [255]
44 [255]
43
45
44 $ hg pull ../a
46 $ hg pull ../a
45 pulling from ../a
47 pulling from ../a
46 searching for changes
48 searching for changes
47 adding changesets
49 adding changesets
48 adding manifests
50 adding manifests
49 adding file changes
51 adding file changes
50 added 1 changesets with 1 changes to 1 files (+1 heads)
52 added 1 changesets with 1 changes to 1 files (+1 heads)
51 (run 'hg heads' to see heads, 'hg merge' to merge)
53 (run 'hg heads' to see heads, 'hg merge' to merge)
52
54
53 $ hg push ../a
55 $ hg push ../a
54 pushing to ../a
56 pushing to ../a
55 searching for changes
57 searching for changes
56 abort: push creates new remote head 1e108cc5548c!
58 abort: push creates new remote head 1e108cc5548c!
57 (merge or see "hg help push" for details about pushing new heads)
59 (merge or see "hg help push" for details about pushing new heads)
58 [255]
60 [255]
59
61
60 $ hg merge
62 $ hg merge
61 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
63 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
62 (branch merge, don't forget to commit)
64 (branch merge, don't forget to commit)
63
65
64 $ hg commit -m "4"
66 $ hg commit -m "4"
65 $ hg push ../a
67 $ hg push ../a
66 pushing to ../a
68 pushing to ../a
67 searching for changes
69 searching for changes
68 adding changesets
70 adding changesets
69 adding manifests
71 adding manifests
70 adding file changes
72 adding file changes
71 added 2 changesets with 1 changes to 1 files
73 added 2 changesets with 1 changes to 1 files
72
74
73 $ cd ..
75 $ cd ..
74
76
75 $ hg init c
77 $ hg init c
76 $ cd c
78 $ cd c
77 $ for i in 0 1 2; do
79 $ for i in 0 1 2; do
78 > echo $i >> foo
80 > echo $i >> foo
79 > hg ci -Am $i
81 > hg ci -Am $i
80 > done
82 > done
81 adding foo
83 adding foo
82 $ cd ..
84 $ cd ..
83
85
84 $ hg clone c d
86 $ hg clone c d
85 updating to branch default
87 updating to branch default
86 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
88 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
87
89
88 $ cd d
90 $ cd d
89 $ for i in 0 1; do
91 $ for i in 0 1; do
90 > hg co -C $i
92 > hg co -C $i
91 > echo d-$i >> foo
93 > echo d-$i >> foo
92 > hg ci -m d-$i
94 > hg ci -m d-$i
93 > done
95 > done
94 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
96 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
95 created new head
97 created new head
96 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
98 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
97 created new head
99 created new head
98
100
99 $ HGMERGE=true hg merge 3
101 $ HGMERGE=true hg merge 3
100 merging foo
102 merging foo
101 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
103 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
102 (branch merge, don't forget to commit)
104 (branch merge, don't forget to commit)
103
105
104 $ hg ci -m c-d
106 $ hg ci -m c-d
105
107
106 $ hg push ../c
108 $ hg push ../c
107 pushing to ../c
109 pushing to ../c
108 searching for changes
110 searching for changes
109 abort: push creates new remote head 6346d66eb9f5!
111 abort: push creates new remote head 6346d66eb9f5!
110 (merge or see "hg help push" for details about pushing new heads)
112 (merge or see "hg help push" for details about pushing new heads)
111 [255]
113 [255]
112
114
113 $ hg push -r 2 ../c
115 $ hg push -r 2 ../c
114 pushing to ../c
116 pushing to ../c
115 searching for changes
117 searching for changes
116 no changes found
118 no changes found
117 [1]
119 [1]
118
120
119 $ hg push -r 3 ../c
121 $ hg push -r 3 ../c
120 pushing to ../c
122 pushing to ../c
121 searching for changes
123 searching for changes
122 abort: push creates new remote head a5dda829a167!
124 abort: push creates new remote head a5dda829a167!
123 (merge or see "hg help push" for details about pushing new heads)
125 (merge or see "hg help push" for details about pushing new heads)
124 [255]
126 [255]
125
127
126 $ hg push -v -r 3 -r 4 ../c
128 $ hg push -v -r 3 -r 4 ../c
127 pushing to ../c
129 pushing to ../c
128 searching for changes
130 searching for changes
129 new remote heads on branch 'default':
131 new remote heads on branch 'default':
130 a5dda829a167
132 a5dda829a167
131 ee8fbc7a0295
133 ee8fbc7a0295
132 abort: push creates new remote head a5dda829a167!
134 abort: push creates new remote head a5dda829a167!
133 (merge or see "hg help push" for details about pushing new heads)
135 (merge or see "hg help push" for details about pushing new heads)
134 [255]
136 [255]
135
137
136 $ hg push -v -f -r 3 -r 4 ../c
138 $ hg push -v -f -r 3 -r 4 ../c
137 pushing to ../c
139 pushing to ../c
138 searching for changes
140 searching for changes
139 2 changesets found
141 2 changesets found
140 adding changesets
142 adding changesets
141 adding manifests
143 adding manifests
142 adding file changes
144 adding file changes
143 added 2 changesets with 2 changes to 1 files (+2 heads)
145 added 2 changesets with 2 changes to 1 files (+2 heads)
144
146
145 $ hg push -r 5 ../c
147 $ hg push -r 5 ../c
146 pushing to ../c
148 pushing to ../c
147 searching for changes
149 searching for changes
148 adding changesets
150 adding changesets
149 adding manifests
151 adding manifests
150 adding file changes
152 adding file changes
151 added 1 changesets with 1 changes to 1 files (-1 heads)
153 added 1 changesets with 1 changes to 1 files (-1 heads)
152
154
153 $ hg in ../c
155 $ hg in ../c
154 comparing with ../c
156 comparing with ../c
155 searching for changes
157 searching for changes
156 no changes found
158 no changes found
157 [1]
159 [1]
158
160
159
161
160 Issue450: push -r warns about remote head creation even if no heads
162 Issue450: push -r warns about remote head creation even if no heads
161 will be created
163 will be created
162
164
163 $ hg init ../e
165 $ hg init ../e
164 $ hg push -r 0 ../e
166 $ hg push -r 0 ../e
165 pushing to ../e
167 pushing to ../e
166 searching for changes
168 searching for changes
167 adding changesets
169 adding changesets
168 adding manifests
170 adding manifests
169 adding file changes
171 adding file changes
170 added 1 changesets with 1 changes to 1 files
172 added 1 changesets with 1 changes to 1 files
171
173
172 $ hg push -r 1 ../e
174 $ hg push -r 1 ../e
173 pushing to ../e
175 pushing to ../e
174 searching for changes
176 searching for changes
175 adding changesets
177 adding changesets
176 adding manifests
178 adding manifests
177 adding file changes
179 adding file changes
178 added 1 changesets with 1 changes to 1 files
180 added 1 changesets with 1 changes to 1 files
179
181
180 $ cd ..
182 $ cd ..
181
183
182
184
183 Issue736: named branches are not considered for detection of
185 Issue736: named branches are not considered for detection of
184 unmerged heads in "hg push"
186 unmerged heads in "hg push"
185
187
186 $ hg init f
188 $ hg init f
187 $ cd f
189 $ cd f
188 $ hg -q branch a
190 $ hg -q branch a
189 $ echo 0 > foo
191 $ echo 0 > foo
190 $ hg -q ci -Am 0
192 $ hg -q ci -Am 0
191 $ echo 1 > foo
193 $ echo 1 > foo
192 $ hg -q ci -m 1
194 $ hg -q ci -m 1
193 $ hg -q up 0
195 $ hg -q up 0
194 $ echo 2 > foo
196 $ echo 2 > foo
195 $ hg -q ci -m 2
197 $ hg -q ci -m 2
196 $ hg -q up 0
198 $ hg -q up 0
197 $ hg -q branch b
199 $ hg -q branch b
198 $ echo 3 > foo
200 $ echo 3 > foo
199 $ hg -q ci -m 3
201 $ hg -q ci -m 3
200 $ cd ..
202 $ cd ..
201
203
202 $ hg -q clone f g
204 $ hg -q clone f g
203 $ cd g
205 $ cd g
204
206
205 Push on existing branch and new branch:
207 Push on existing branch and new branch:
206
208
207 $ hg -q up 1
209 $ hg -q up 1
208 $ echo 4 > foo
210 $ echo 4 > foo
209 $ hg -q ci -m 4
211 $ hg -q ci -m 4
210 $ hg -q up 0
212 $ hg -q up 0
211 $ echo 5 > foo
213 $ echo 5 > foo
212 $ hg -q branch c
214 $ hg -q branch c
213 $ hg -q ci -m 5
215 $ hg -q ci -m 5
214
216
215 $ hg push ../f
217 $ hg push ../f
216 pushing to ../f
218 pushing to ../f
217 searching for changes
219 searching for changes
218 abort: push creates new remote branches: c!
220 abort: push creates new remote branches: c!
219 (use 'hg push --new-branch' to create new remote branches)
221 (use 'hg push --new-branch' to create new remote branches)
220 [255]
222 [255]
221
223
222 $ hg push -r 4 -r 5 ../f
224 $ hg push -r 4 -r 5 ../f
223 pushing to ../f
225 pushing to ../f
224 searching for changes
226 searching for changes
225 abort: push creates new remote branches: c!
227 abort: push creates new remote branches: c!
226 (use 'hg push --new-branch' to create new remote branches)
228 (use 'hg push --new-branch' to create new remote branches)
227 [255]
229 [255]
228
230
229
231
230 Multiple new branches:
232 Multiple new branches:
231
233
232 $ hg -q branch d
234 $ hg -q branch d
233 $ echo 6 > foo
235 $ echo 6 > foo
234 $ hg -q ci -m 6
236 $ hg -q ci -m 6
235
237
236 $ hg push ../f
238 $ hg push ../f
237 pushing to ../f
239 pushing to ../f
238 searching for changes
240 searching for changes
239 abort: push creates new remote branches: c, d!
241 abort: push creates new remote branches: c, d!
240 (use 'hg push --new-branch' to create new remote branches)
242 (use 'hg push --new-branch' to create new remote branches)
241 [255]
243 [255]
242
244
243 $ hg push -r 4 -r 6 ../f
245 $ hg push -r 4 -r 6 ../f
244 pushing to ../f
246 pushing to ../f
245 searching for changes
247 searching for changes
246 abort: push creates new remote branches: c, d!
248 abort: push creates new remote branches: c, d!
247 (use 'hg push --new-branch' to create new remote branches)
249 (use 'hg push --new-branch' to create new remote branches)
248 [255]
250 [255]
249
251
250 $ cd ../g
252 $ cd ../g
251
253
252
254
253 Fail on multiple head push:
255 Fail on multiple head push:
254
256
255 $ hg -q up 1
257 $ hg -q up 1
256 $ echo 7 > foo
258 $ echo 7 > foo
257 $ hg -q ci -m 7
259 $ hg -q ci -m 7
258
260
259 $ hg push -r 4 -r 7 ../f
261 $ hg push -r 4 -r 7 ../f
260 pushing to ../f
262 pushing to ../f
261 searching for changes
263 searching for changes
262 abort: push creates new remote head 0b715ef6ff8f on branch 'a'!
264 abort: push creates new remote head 0b715ef6ff8f on branch 'a'!
263 (merge or see "hg help push" for details about pushing new heads)
265 (merge or see "hg help push" for details about pushing new heads)
264 [255]
266 [255]
265
267
266 Push replacement head on existing branches:
268 Push replacement head on existing branches:
267
269
268 $ hg -q up 3
270 $ hg -q up 3
269 $ echo 8 > foo
271 $ echo 8 > foo
270 $ hg -q ci -m 8
272 $ hg -q ci -m 8
271
273
272 $ hg push -r 7 -r 8 ../f
274 $ hg push -r 7 -r 8 ../f
273 pushing to ../f
275 pushing to ../f
274 searching for changes
276 searching for changes
275 adding changesets
277 adding changesets
276 adding manifests
278 adding manifests
277 adding file changes
279 adding file changes
278 added 2 changesets with 2 changes to 1 files
280 added 2 changesets with 2 changes to 1 files
279
281
280
282
281 Merge of branch a to other branch b followed by unrelated push
283 Merge of branch a to other branch b followed by unrelated push
282 on branch a:
284 on branch a:
283
285
284 $ hg -q up 7
286 $ hg -q up 7
285 $ HGMERGE=true hg -q merge 8
287 $ HGMERGE=true hg -q merge 8
286 $ hg -q ci -m 9
288 $ hg -q ci -m 9
287 $ hg -q up 8
289 $ hg -q up 8
288 $ echo 10 > foo
290 $ echo 10 > foo
289 $ hg -q ci -m 10
291 $ hg -q ci -m 10
290
292
291 $ hg push -r 9 ../f
293 $ hg push -r 9 ../f
292 pushing to ../f
294 pushing to ../f
293 searching for changes
295 searching for changes
294 adding changesets
296 adding changesets
295 adding manifests
297 adding manifests
296 adding file changes
298 adding file changes
297 added 1 changesets with 1 changes to 1 files (-1 heads)
299 added 1 changesets with 1 changes to 1 files (-1 heads)
298
300
299 $ hg push -r 10 ../f
301 $ hg push -r 10 ../f
300 pushing to ../f
302 pushing to ../f
301 searching for changes
303 searching for changes
302 adding changesets
304 adding changesets
303 adding manifests
305 adding manifests
304 adding file changes
306 adding file changes
305 added 1 changesets with 1 changes to 1 files (+1 heads)
307 added 1 changesets with 1 changes to 1 files (+1 heads)
306
308
307
309
308 Cheating the counting algorithm:
310 Cheating the counting algorithm:
309
311
310 $ hg -q up 9
312 $ hg -q up 9
311 $ HGMERGE=true hg -q merge 2
313 $ HGMERGE=true hg -q merge 2
312 $ hg -q ci -m 11
314 $ hg -q ci -m 11
313 $ hg -q up 1
315 $ hg -q up 1
314 $ echo 12 > foo
316 $ echo 12 > foo
315 $ hg -q ci -m 12
317 $ hg -q ci -m 12
316
318
317 $ hg push -r 11 -r 12 ../f
319 $ hg push -r 11 -r 12 ../f
318 pushing to ../f
320 pushing to ../f
319 searching for changes
321 searching for changes
320 adding changesets
322 adding changesets
321 adding manifests
323 adding manifests
322 adding file changes
324 adding file changes
323 added 2 changesets with 2 changes to 1 files
325 added 2 changesets with 2 changes to 1 files
324
326
325
327
326 Failed push of new named branch:
328 Failed push of new named branch:
327
329
328 $ echo 12 > foo
330 $ echo 12 > foo
329 $ hg -q ci -m 12a
331 $ hg -q ci -m 12a
330 [1]
332 [1]
331 $ hg -q up 11
333 $ hg -q up 11
332 $ echo 13 > foo
334 $ echo 13 > foo
333 $ hg -q branch e
335 $ hg -q branch e
334 $ hg -q ci -m 13d
336 $ hg -q ci -m 13d
335
337
336 $ hg push -r 12 -r 13 ../f
338 $ hg push -r 12 -r 13 ../f
337 pushing to ../f
339 pushing to ../f
338 searching for changes
340 searching for changes
339 abort: push creates new remote branches: e!
341 abort: push creates new remote branches: e!
340 (use 'hg push --new-branch' to create new remote branches)
342 (use 'hg push --new-branch' to create new remote branches)
341 [255]
343 [255]
342
344
343
345
344 Using --new-branch to push new named branch:
346 Using --new-branch to push new named branch:
345
347
346 $ hg push --new-branch -r 12 -r 13 ../f
348 $ hg push --new-branch -r 12 -r 13 ../f
347 pushing to ../f
349 pushing to ../f
348 searching for changes
350 searching for changes
349 adding changesets
351 adding changesets
350 adding manifests
352 adding manifests
351 adding file changes
353 adding file changes
352 added 1 changesets with 1 changes to 1 files
354 added 1 changesets with 1 changes to 1 files
353
355
354 Pushing muliple headed new branch:
356 Pushing muliple headed new branch:
355
357
356 $ echo 14 > foo
358 $ echo 14 > foo
357 $ hg -q branch f
359 $ hg -q branch f
358 $ hg -q ci -m 14
360 $ hg -q ci -m 14
359 $ echo 15 > foo
361 $ echo 15 > foo
360 $ hg -q ci -m 15
362 $ hg -q ci -m 15
361 $ hg -q up 14
363 $ hg -q up 14
362 $ echo 16 > foo
364 $ echo 16 > foo
363 $ hg -q ci -m 16
365 $ hg -q ci -m 16
364 $ hg push --branch f --new-branch ../f
366 $ hg push --branch f --new-branch ../f
365 pushing to ../f
367 pushing to ../f
366 searching for changes
368 searching for changes
367 abort: push creates new branch 'f' with multiple heads
369 abort: push creates new branch 'f' with multiple heads
368 (merge or see "hg help push" for details about pushing new heads)
370 (merge or see "hg help push" for details about pushing new heads)
369 [255]
371 [255]
370 $ hg push --branch f --new-branch --force ../f
372 $ hg push --branch f --new-branch --force ../f
371 pushing to ../f
373 pushing to ../f
372 searching for changes
374 searching for changes
373 adding changesets
375 adding changesets
374 adding manifests
376 adding manifests
375 adding file changes
377 adding file changes
376 added 3 changesets with 3 changes to 1 files (+1 heads)
378 added 3 changesets with 3 changes to 1 files (+1 heads)
377
379
378 Checking prepush logic does not allow silently pushing
380 Checking prepush logic does not allow silently pushing
379 multiple new heads:
381 multiple new heads:
380
382
381 $ cd ..
383 $ cd ..
382 $ hg init h
384 $ hg init h
383 $ echo init > h/init
385 $ echo init > h/init
384 $ hg -R h ci -Am init
386 $ hg -R h ci -Am init
385 adding init
387 adding init
386 $ echo a > h/a
388 $ echo a > h/a
387 $ hg -R h ci -Am a
389 $ hg -R h ci -Am a
388 adding a
390 adding a
389 $ hg clone h i
391 $ hg clone h i
390 updating to branch default
392 updating to branch default
391 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
393 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
392 $ hg -R h up 0
394 $ hg -R h up 0
393 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
395 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
394 $ echo b > h/b
396 $ echo b > h/b
395 $ hg -R h ci -Am b
397 $ hg -R h ci -Am b
396 adding b
398 adding b
397 created new head
399 created new head
398 $ hg -R i up 0
400 $ hg -R i up 0
399 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
401 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
400 $ echo c > i/c
402 $ echo c > i/c
401 $ hg -R i ci -Am c
403 $ hg -R i ci -Am c
402 adding c
404 adding c
403 created new head
405 created new head
404
406
405 $ hg -R i push h
407 $ hg -R i push h
406 pushing to h
408 pushing to h
407 searching for changes
409 searching for changes
410 remote has heads on branch 'default' that are not known locally: ce4212fc8847
408 abort: push creates new remote head 97bd0c84d346!
411 abort: push creates new remote head 97bd0c84d346!
409 (pull and merge or see "hg help push" for details about pushing new heads)
412 (pull and merge or see "hg help push" for details about pushing new heads)
410 [255]
413 [255]
411
414
412
415
413 Check prepush logic with merged branches:
416 Check prepush logic with merged branches:
414
417
415 $ hg init j
418 $ hg init j
416 $ hg -R j branch a
419 $ hg -R j branch a
417 marked working directory as branch a
420 marked working directory as branch a
418 (branches are permanent and global, did you want a bookmark?)
421 (branches are permanent and global, did you want a bookmark?)
419 $ echo init > j/foo
422 $ echo init > j/foo
420 $ hg -R j ci -Am init
423 $ hg -R j ci -Am init
421 adding foo
424 adding foo
422 $ hg clone j k
425 $ hg clone j k
423 updating to branch a
426 updating to branch a
424 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
427 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
425 $ echo a1 > j/foo
428 $ echo a1 > j/foo
426 $ hg -R j ci -m a1
429 $ hg -R j ci -m a1
427 $ hg -R k branch b
430 $ hg -R k branch b
428 marked working directory as branch b
431 marked working directory as branch b
429 (branches are permanent and global, did you want a bookmark?)
432 (branches are permanent and global, did you want a bookmark?)
430 $ echo b > k/foo
433 $ echo b > k/foo
431 $ hg -R k ci -m b
434 $ hg -R k ci -m b
432 $ hg -R k up 0
435 $ hg -R k up 0
433 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
436 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
434
437
435 $ hg -R k merge b
438 $ hg -R k merge b
436 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
439 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
437 (branch merge, don't forget to commit)
440 (branch merge, don't forget to commit)
438
441
439 $ hg -R k ci -m merge
442 $ hg -R k ci -m merge
440
443
441 $ hg -R k push -r a j
444 $ hg -R k push -r a j
442 pushing to j
445 pushing to j
443 searching for changes
446 searching for changes
444 abort: push creates new remote branches: b!
447 abort: push creates new remote branches: b!
445 (use 'hg push --new-branch' to create new remote branches)
448 (use 'hg push --new-branch' to create new remote branches)
446 [255]
449 [255]
447
450
448
451
449 Prepush -r should not allow you to sneak in new heads:
452 Prepush -r should not allow you to sneak in new heads:
450
453
451 $ hg init l
454 $ hg init l
452 $ cd l
455 $ cd l
453 $ echo a >> foo
456 $ echo a >> foo
454 $ hg -q add foo
457 $ hg -q add foo
455 $ hg -q branch a
458 $ hg -q branch a
456 $ hg -q ci -ma
459 $ hg -q ci -ma
457 $ hg -q up null
460 $ hg -q up null
458 $ echo a >> foo
461 $ echo a >> foo
459 $ hg -q add foo
462 $ hg -q add foo
460 $ hg -q branch b
463 $ hg -q branch b
461 $ hg -q ci -mb
464 $ hg -q ci -mb
462 $ cd ..
465 $ cd ..
463 $ hg -q clone l m -u a
466 $ hg -q clone l m -u a
464 $ cd m
467 $ cd m
465 $ hg -q merge b
468 $ hg -q merge b
466 $ hg -q ci -mmb
469 $ hg -q ci -mmb
467 $ hg -q up 0
470 $ hg -q up 0
468 $ echo a >> foo
471 $ echo a >> foo
469 $ hg -q ci -ma2
472 $ hg -q ci -ma2
470 $ hg -q up 2
473 $ hg -q up 2
471 $ echo a >> foo
474 $ echo a >> foo
472 $ hg -q branch -f b
475 $ hg -q branch -f b
473 $ hg -q ci -mb2
476 $ hg -q ci -mb2
474 $ hg -q merge 3
477 $ hg -q merge 3
475 $ hg -q ci -mma
478 $ hg -q ci -mma
476
479
477 $ hg push ../l -b b
480 $ hg push ../l -b b
478 pushing to ../l
481 pushing to ../l
479 searching for changes
482 searching for changes
480 abort: push creates new remote head 451211cc22b0 on branch 'a'!
483 abort: push creates new remote head 451211cc22b0 on branch 'a'!
481 (merge or see "hg help push" for details about pushing new heads)
484 (merge or see "hg help push" for details about pushing new heads)
482 [255]
485 [255]
483
486
484 $ cd ..
487 $ cd ..
485
488
486
489
487 Check prepush with new branch head on former topo non-head:
490 Check prepush with new branch head on former topo non-head:
488
491
489 $ hg init n
492 $ hg init n
490 $ cd n
493 $ cd n
491 $ hg branch A
494 $ hg branch A
492 marked working directory as branch A
495 marked working directory as branch A
493 (branches are permanent and global, did you want a bookmark?)
496 (branches are permanent and global, did you want a bookmark?)
494 $ echo a >a
497 $ echo a >a
495 $ hg ci -Ama
498 $ hg ci -Ama
496 adding a
499 adding a
497 $ hg branch B
500 $ hg branch B
498 marked working directory as branch B
501 marked working directory as branch B
499 (branches are permanent and global, did you want a bookmark?)
502 (branches are permanent and global, did you want a bookmark?)
500 $ echo b >b
503 $ echo b >b
501 $ hg ci -Amb
504 $ hg ci -Amb
502 adding b
505 adding b
503
506
504 b is now branch head of B, and a topological head
507 b is now branch head of B, and a topological head
505 a is now branch head of A, but not a topological head
508 a is now branch head of A, but not a topological head
506
509
507 $ hg clone . inner
510 $ hg clone . inner
508 updating to branch B
511 updating to branch B
509 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
512 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
510 $ cd inner
513 $ cd inner
511 $ hg up B
514 $ hg up B
512 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
515 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
513 $ echo b1 >b1
516 $ echo b1 >b1
514 $ hg ci -Amb1
517 $ hg ci -Amb1
515 adding b1
518 adding b1
516
519
517 in the clone b1 is now the head of B
520 in the clone b1 is now the head of B
518
521
519 $ cd ..
522 $ cd ..
520 $ hg up 0
523 $ hg up 0
521 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
524 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
522 $ echo a2 >a2
525 $ echo a2 >a2
523 $ hg ci -Ama2
526 $ hg ci -Ama2
524 adding a2
527 adding a2
525
528
526 a2 is now the new branch head of A, and a new topological head
529 a2 is now the new branch head of A, and a new topological head
527 it replaces a former inner branch head, so it should at most warn about
530 it replaces a former inner branch head, so it should at most warn about
528 A, not B
531 A, not B
529
532
530 glog of local:
533 glog of local:
531
534
532 $ hg log -G --template "{rev}: {branches} {desc}\n"
535 $ hg log -G --template "{rev}: {branches} {desc}\n"
533 @ 2: A a2
536 @ 2: A a2
534 |
537 |
535 | o 1: B b
538 | o 1: B b
536 |/
539 |/
537 o 0: A a
540 o 0: A a
538
541
539 glog of remote:
542 glog of remote:
540
543
541 $ hg log -G -R inner --template "{rev}: {branches} {desc}\n"
544 $ hg log -G -R inner --template "{rev}: {branches} {desc}\n"
542 @ 2: B b1
545 @ 2: B b1
543 |
546 |
544 o 1: B b
547 o 1: B b
545 |
548 |
546 o 0: A a
549 o 0: A a
547
550
548 outgoing:
551 outgoing:
549
552
550 $ hg out inner --template "{rev}: {branches} {desc}\n"
553 $ hg out inner --template "{rev}: {branches} {desc}\n"
551 comparing with inner
554 comparing with inner
552 searching for changes
555 searching for changes
553 2: A a2
556 2: A a2
554
557
555 $ hg push inner
558 $ hg push inner
556 pushing to inner
559 pushing to inner
557 searching for changes
560 searching for changes
558 adding changesets
561 adding changesets
559 adding manifests
562 adding manifests
560 adding file changes
563 adding file changes
561 added 1 changesets with 1 changes to 1 files (+1 heads)
564 added 1 changesets with 1 changes to 1 files (+1 heads)
562
565
563 $ cd ..
566 $ cd ..
564
567
565
568
566 Check prepush with new branch head on former topo head:
569 Check prepush with new branch head on former topo head:
567
570
568 $ hg init o
571 $ hg init o
569 $ cd o
572 $ cd o
570 $ hg branch A
573 $ hg branch A
571 marked working directory as branch A
574 marked working directory as branch A
572 (branches are permanent and global, did you want a bookmark?)
575 (branches are permanent and global, did you want a bookmark?)
573 $ echo a >a
576 $ echo a >a
574 $ hg ci -Ama
577 $ hg ci -Ama
575 adding a
578 adding a
576 $ hg branch B
579 $ hg branch B
577 marked working directory as branch B
580 marked working directory as branch B
578 (branches are permanent and global, did you want a bookmark?)
581 (branches are permanent and global, did you want a bookmark?)
579 $ echo b >b
582 $ echo b >b
580 $ hg ci -Amb
583 $ hg ci -Amb
581 adding b
584 adding b
582
585
583 b is now branch head of B, and a topological head
586 b is now branch head of B, and a topological head
584
587
585 $ hg up 0
588 $ hg up 0
586 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
589 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
587 $ echo a1 >a1
590 $ echo a1 >a1
588 $ hg ci -Ama1
591 $ hg ci -Ama1
589 adding a1
592 adding a1
590
593
591 a1 is now branch head of A, and a topological head
594 a1 is now branch head of A, and a topological head
592
595
593 $ hg clone . inner
596 $ hg clone . inner
594 updating to branch A
597 updating to branch A
595 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
598 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
596 $ cd inner
599 $ cd inner
597 $ hg up B
600 $ hg up B
598 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
601 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
599 $ echo b1 >b1
602 $ echo b1 >b1
600 $ hg ci -Amb1
603 $ hg ci -Amb1
601 adding b1
604 adding b1
602
605
603 in the clone b1 is now the head of B
606 in the clone b1 is now the head of B
604
607
605 $ cd ..
608 $ cd ..
606 $ echo a2 >a2
609 $ echo a2 >a2
607 $ hg ci -Ama2
610 $ hg ci -Ama2
608 adding a2
611 adding a2
609
612
610 a2 is now the new branch head of A, and a topological head
613 a2 is now the new branch head of A, and a topological head
611 it replaces a former topological and branch head, so this should not warn
614 it replaces a former topological and branch head, so this should not warn
612
615
613 glog of local:
616 glog of local:
614
617
615 $ hg log -G --template "{rev}: {branches} {desc}\n"
618 $ hg log -G --template "{rev}: {branches} {desc}\n"
616 @ 3: A a2
619 @ 3: A a2
617 |
620 |
618 o 2: A a1
621 o 2: A a1
619 |
622 |
620 | o 1: B b
623 | o 1: B b
621 |/
624 |/
622 o 0: A a
625 o 0: A a
623
626
624 glog of remote:
627 glog of remote:
625
628
626 $ hg log -G -R inner --template "{rev}: {branches} {desc}\n"
629 $ hg log -G -R inner --template "{rev}: {branches} {desc}\n"
627 @ 3: B b1
630 @ 3: B b1
628 |
631 |
629 | o 2: A a1
632 | o 2: A a1
630 | |
633 | |
631 o | 1: B b
634 o | 1: B b
632 |/
635 |/
633 o 0: A a
636 o 0: A a
634
637
635 outgoing:
638 outgoing:
636
639
637 $ hg out inner --template "{rev}: {branches} {desc}\n"
640 $ hg out inner --template "{rev}: {branches} {desc}\n"
638 comparing with inner
641 comparing with inner
639 searching for changes
642 searching for changes
640 3: A a2
643 3: A a2
641
644
642 $ hg push inner
645 $ hg push inner
643 pushing to inner
646 pushing to inner
644 searching for changes
647 searching for changes
645 adding changesets
648 adding changesets
646 adding manifests
649 adding manifests
647 adding file changes
650 adding file changes
648 added 1 changesets with 1 changes to 1 files
651 added 1 changesets with 1 changes to 1 files
649
652
650 $ cd ..
653 $ cd ..
651
654
652
655
653 Check prepush with new branch head and new child of former branch head
656 Check prepush with new branch head and new child of former branch head
654 but child is on different branch:
657 but child is on different branch:
655
658
656 $ hg init p
659 $ hg init p
657 $ cd p
660 $ cd p
658 $ hg branch A
661 $ hg branch A
659 marked working directory as branch A
662 marked working directory as branch A
660 (branches are permanent and global, did you want a bookmark?)
663 (branches are permanent and global, did you want a bookmark?)
661 $ echo a0 >a
664 $ echo a0 >a
662 $ hg ci -Ama0
665 $ hg ci -Ama0
663 adding a
666 adding a
664 $ echo a1 >a
667 $ echo a1 >a
665 $ hg ci -ma1
668 $ hg ci -ma1
666 $ hg up null
669 $ hg up null
667 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
670 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
668 $ hg branch B
671 $ hg branch B
669 marked working directory as branch B
672 marked working directory as branch B
670 (branches are permanent and global, did you want a bookmark?)
673 (branches are permanent and global, did you want a bookmark?)
671 $ echo b0 >b
674 $ echo b0 >b
672 $ hg ci -Amb0
675 $ hg ci -Amb0
673 adding b
676 adding b
674 $ echo b1 >b
677 $ echo b1 >b
675 $ hg ci -mb1
678 $ hg ci -mb1
676
679
677 $ hg clone . inner
680 $ hg clone . inner
678 updating to branch B
681 updating to branch B
679 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
682 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
680
683
681 $ hg up A
684 $ hg up A
682 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
685 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
683 $ hg branch -f B
686 $ hg branch -f B
684 marked working directory as branch B
687 marked working directory as branch B
685 (branches are permanent and global, did you want a bookmark?)
688 (branches are permanent and global, did you want a bookmark?)
686 $ echo a3 >a
689 $ echo a3 >a
687 $ hg ci -ma3
690 $ hg ci -ma3
688 created new head
691 created new head
689 $ hg up 3
692 $ hg up 3
690 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
693 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
691 $ hg branch -f A
694 $ hg branch -f A
692 marked working directory as branch A
695 marked working directory as branch A
693 (branches are permanent and global, did you want a bookmark?)
696 (branches are permanent and global, did you want a bookmark?)
694 $ echo b3 >b
697 $ echo b3 >b
695 $ hg ci -mb3
698 $ hg ci -mb3
696 created new head
699 created new head
697
700
698 glog of local:
701 glog of local:
699
702
700 $ hg log -G --template "{rev}: {branches} {desc}\n"
703 $ hg log -G --template "{rev}: {branches} {desc}\n"
701 @ 5: A b3
704 @ 5: A b3
702 |
705 |
703 | o 4: B a3
706 | o 4: B a3
704 | |
707 | |
705 o | 3: B b1
708 o | 3: B b1
706 | |
709 | |
707 o | 2: B b0
710 o | 2: B b0
708 /
711 /
709 o 1: A a1
712 o 1: A a1
710 |
713 |
711 o 0: A a0
714 o 0: A a0
712
715
713 glog of remote:
716 glog of remote:
714
717
715 $ hg log -G -R inner --template "{rev}: {branches} {desc}\n"
718 $ hg log -G -R inner --template "{rev}: {branches} {desc}\n"
716 @ 3: B b1
719 @ 3: B b1
717 |
720 |
718 o 2: B b0
721 o 2: B b0
719
722
720 o 1: A a1
723 o 1: A a1
721 |
724 |
722 o 0: A a0
725 o 0: A a0
723
726
724 outgoing:
727 outgoing:
725
728
726 $ hg out inner --template "{rev}: {branches} {desc}\n"
729 $ hg out inner --template "{rev}: {branches} {desc}\n"
727 comparing with inner
730 comparing with inner
728 searching for changes
731 searching for changes
729 4: B a3
732 4: B a3
730 5: A b3
733 5: A b3
731
734
732 $ hg push inner
735 $ hg push inner
733 pushing to inner
736 pushing to inner
734 searching for changes
737 searching for changes
735 abort: push creates new remote head 7d0f4fb6cf04 on branch 'A'!
738 abort: push creates new remote head 7d0f4fb6cf04 on branch 'A'!
736 (merge or see "hg help push" for details about pushing new heads)
739 (merge or see "hg help push" for details about pushing new heads)
737 [255]
740 [255]
738
741
739 $ hg push inner -r4 -r5
742 $ hg push inner -r4 -r5
740 pushing to inner
743 pushing to inner
741 searching for changes
744 searching for changes
742 abort: push creates new remote head 7d0f4fb6cf04 on branch 'A'!
745 abort: push creates new remote head 7d0f4fb6cf04 on branch 'A'!
743 (merge or see "hg help push" for details about pushing new heads)
746 (merge or see "hg help push" for details about pushing new heads)
744 [255]
747 [255]
745
748
746 $ hg in inner
749 $ hg in inner
747 comparing with inner
750 comparing with inner
748 searching for changes
751 searching for changes
749 no changes found
752 no changes found
750 [1]
753 [1]
751
754
752 $ cd ..
755 $ cd ..
@@ -1,384 +1,384 b''
1
1
2
2
3 This test tries to exercise the ssh functionality with a dummy script
3 This test tries to exercise the ssh functionality with a dummy script
4
4
5 creating 'remote' repo
5 creating 'remote' repo
6
6
7 $ hg init remote
7 $ hg init remote
8 $ cd remote
8 $ cd remote
9 $ echo this > foo
9 $ echo this > foo
10 $ echo this > fooO
10 $ echo this > fooO
11 $ hg ci -A -m "init" foo fooO
11 $ hg ci -A -m "init" foo fooO
12 $ cat <<EOF > .hg/hgrc
12 $ cat <<EOF > .hg/hgrc
13 > [server]
13 > [server]
14 > uncompressed = True
14 > uncompressed = True
15 >
15 >
16 > [hooks]
16 > [hooks]
17 > changegroup = python "$TESTDIR/printenv.py" changegroup-in-remote 0 ../dummylog
17 > changegroup = python "$TESTDIR/printenv.py" changegroup-in-remote 0 ../dummylog
18 > EOF
18 > EOF
19 $ cd ..
19 $ cd ..
20
20
21 repo not found error
21 repo not found error
22
22
23 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/nonexistent local
23 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/nonexistent local
24 remote: abort: there is no Mercurial repository here (.hg not found)!
24 remote: abort: there is no Mercurial repository here (.hg not found)!
25 abort: no suitable response from remote hg!
25 abort: no suitable response from remote hg!
26 [255]
26 [255]
27
27
28 non-existent absolute path
28 non-existent absolute path
29
29
30 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy//`pwd`/nonexistent local
30 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy//`pwd`/nonexistent local
31 remote: abort: there is no Mercurial repository here (.hg not found)!
31 remote: abort: there is no Mercurial repository here (.hg not found)!
32 abort: no suitable response from remote hg!
32 abort: no suitable response from remote hg!
33 [255]
33 [255]
34
34
35 clone remote via stream
35 clone remote via stream
36
36
37 $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/remote local-stream
37 $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/remote local-stream
38 streaming all changes
38 streaming all changes
39 4 files to transfer, 392 bytes of data
39 4 files to transfer, 392 bytes of data
40 transferred 392 bytes in * seconds (*/sec) (glob)
40 transferred 392 bytes in * seconds (*/sec) (glob)
41 updating to branch default
41 updating to branch default
42 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
42 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
43 $ cd local-stream
43 $ cd local-stream
44 $ hg verify
44 $ hg verify
45 checking changesets
45 checking changesets
46 checking manifests
46 checking manifests
47 crosschecking files in changesets and manifests
47 crosschecking files in changesets and manifests
48 checking files
48 checking files
49 2 files, 1 changesets, 2 total revisions
49 2 files, 1 changesets, 2 total revisions
50 $ cd ..
50 $ cd ..
51
51
52 clone remote via pull
52 clone remote via pull
53
53
54 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local
54 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local
55 requesting all changes
55 requesting all changes
56 adding changesets
56 adding changesets
57 adding manifests
57 adding manifests
58 adding file changes
58 adding file changes
59 added 1 changesets with 2 changes to 2 files
59 added 1 changesets with 2 changes to 2 files
60 updating to branch default
60 updating to branch default
61 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
61 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
62
62
63 verify
63 verify
64
64
65 $ cd local
65 $ cd local
66 $ hg verify
66 $ hg verify
67 checking changesets
67 checking changesets
68 checking manifests
68 checking manifests
69 crosschecking files in changesets and manifests
69 crosschecking files in changesets and manifests
70 checking files
70 checking files
71 2 files, 1 changesets, 2 total revisions
71 2 files, 1 changesets, 2 total revisions
72 $ echo '[hooks]' >> .hg/hgrc
72 $ echo '[hooks]' >> .hg/hgrc
73 $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup-in-local 0 ../dummylog" >> .hg/hgrc
73 $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup-in-local 0 ../dummylog" >> .hg/hgrc
74
74
75 empty default pull
75 empty default pull
76
76
77 $ hg paths
77 $ hg paths
78 default = ssh://user@dummy/remote
78 default = ssh://user@dummy/remote
79 $ hg pull -e "python \"$TESTDIR/dummyssh\""
79 $ hg pull -e "python \"$TESTDIR/dummyssh\""
80 pulling from ssh://user@dummy/remote
80 pulling from ssh://user@dummy/remote
81 searching for changes
81 searching for changes
82 no changes found
82 no changes found
83
83
84 local change
84 local change
85
85
86 $ echo bleah > foo
86 $ echo bleah > foo
87 $ hg ci -m "add"
87 $ hg ci -m "add"
88
88
89 updating rc
89 updating rc
90
90
91 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
91 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
92 $ echo "[ui]" >> .hg/hgrc
92 $ echo "[ui]" >> .hg/hgrc
93 $ echo "ssh = python \"$TESTDIR/dummyssh\"" >> .hg/hgrc
93 $ echo "ssh = python \"$TESTDIR/dummyssh\"" >> .hg/hgrc
94
94
95 find outgoing
95 find outgoing
96
96
97 $ hg out ssh://user@dummy/remote
97 $ hg out ssh://user@dummy/remote
98 comparing with ssh://user@dummy/remote
98 comparing with ssh://user@dummy/remote
99 searching for changes
99 searching for changes
100 changeset: 1:a28a9d1a809c
100 changeset: 1:a28a9d1a809c
101 tag: tip
101 tag: tip
102 user: test
102 user: test
103 date: Thu Jan 01 00:00:00 1970 +0000
103 date: Thu Jan 01 00:00:00 1970 +0000
104 summary: add
104 summary: add
105
105
106
106
107 find incoming on the remote side
107 find incoming on the remote side
108
108
109 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/local
109 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/local
110 comparing with ssh://user@dummy/local
110 comparing with ssh://user@dummy/local
111 searching for changes
111 searching for changes
112 changeset: 1:a28a9d1a809c
112 changeset: 1:a28a9d1a809c
113 tag: tip
113 tag: tip
114 user: test
114 user: test
115 date: Thu Jan 01 00:00:00 1970 +0000
115 date: Thu Jan 01 00:00:00 1970 +0000
116 summary: add
116 summary: add
117
117
118
118
119 find incoming on the remote side (using absolute path)
119 find incoming on the remote side (using absolute path)
120
120
121 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/`pwd`"
121 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/`pwd`"
122 comparing with ssh://user@dummy/$TESTTMP/local
122 comparing with ssh://user@dummy/$TESTTMP/local
123 searching for changes
123 searching for changes
124 changeset: 1:a28a9d1a809c
124 changeset: 1:a28a9d1a809c
125 tag: tip
125 tag: tip
126 user: test
126 user: test
127 date: Thu Jan 01 00:00:00 1970 +0000
127 date: Thu Jan 01 00:00:00 1970 +0000
128 summary: add
128 summary: add
129
129
130
130
131 push
131 push
132
132
133 $ hg push
133 $ hg push
134 pushing to ssh://user@dummy/remote
134 pushing to ssh://user@dummy/remote
135 searching for changes
135 searching for changes
136 remote: adding changesets
136 remote: adding changesets
137 remote: adding manifests
137 remote: adding manifests
138 remote: adding file changes
138 remote: adding file changes
139 remote: added 1 changesets with 1 changes to 1 files
139 remote: added 1 changesets with 1 changes to 1 files
140 $ cd ../remote
140 $ cd ../remote
141
141
142 check remote tip
142 check remote tip
143
143
144 $ hg tip
144 $ hg tip
145 changeset: 1:a28a9d1a809c
145 changeset: 1:a28a9d1a809c
146 tag: tip
146 tag: tip
147 user: test
147 user: test
148 date: Thu Jan 01 00:00:00 1970 +0000
148 date: Thu Jan 01 00:00:00 1970 +0000
149 summary: add
149 summary: add
150
150
151 $ hg verify
151 $ hg verify
152 checking changesets
152 checking changesets
153 checking manifests
153 checking manifests
154 crosschecking files in changesets and manifests
154 crosschecking files in changesets and manifests
155 checking files
155 checking files
156 2 files, 2 changesets, 3 total revisions
156 2 files, 2 changesets, 3 total revisions
157 $ hg cat -r tip foo
157 $ hg cat -r tip foo
158 bleah
158 bleah
159 $ echo z > z
159 $ echo z > z
160 $ hg ci -A -m z z
160 $ hg ci -A -m z z
161 created new head
161 created new head
162
162
163 test pushkeys and bookmarks
163 test pushkeys and bookmarks
164
164
165 $ cd ../local
165 $ cd ../local
166 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote namespaces
166 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote namespaces
167 bookmarks
167 bookmarks
168 namespaces
168 namespaces
169 phases
169 phases
170 $ hg book foo -r 0
170 $ hg book foo -r 0
171 $ hg out -B
171 $ hg out -B
172 comparing with ssh://user@dummy/remote
172 comparing with ssh://user@dummy/remote
173 searching for changed bookmarks
173 searching for changed bookmarks
174 foo 1160648e36ce
174 foo 1160648e36ce
175 $ hg push -B foo
175 $ hg push -B foo
176 pushing to ssh://user@dummy/remote
176 pushing to ssh://user@dummy/remote
177 searching for changes
177 searching for changes
178 no changes found
178 no changes found
179 exporting bookmark foo
179 exporting bookmark foo
180 [1]
180 [1]
181 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote bookmarks
181 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote bookmarks
182 foo 1160648e36cec0054048a7edc4110c6f84fde594
182 foo 1160648e36cec0054048a7edc4110c6f84fde594
183 $ hg book -f foo
183 $ hg book -f foo
184 $ hg push --traceback
184 $ hg push --traceback
185 pushing to ssh://user@dummy/remote
185 pushing to ssh://user@dummy/remote
186 searching for changes
186 searching for changes
187 no changes found
187 no changes found
188 updating bookmark foo
188 updating bookmark foo
189 [1]
189 [1]
190 $ hg book -d foo
190 $ hg book -d foo
191 $ hg in -B
191 $ hg in -B
192 comparing with ssh://user@dummy/remote
192 comparing with ssh://user@dummy/remote
193 searching for changed bookmarks
193 searching for changed bookmarks
194 foo a28a9d1a809c
194 foo a28a9d1a809c
195 $ hg book -f -r 0 foo
195 $ hg book -f -r 0 foo
196 $ hg pull -B foo
196 $ hg pull -B foo
197 pulling from ssh://user@dummy/remote
197 pulling from ssh://user@dummy/remote
198 no changes found
198 no changes found
199 updating bookmark foo
199 updating bookmark foo
200 importing bookmark foo
200 importing bookmark foo
201 $ hg book -d foo
201 $ hg book -d foo
202 $ hg push -B foo
202 $ hg push -B foo
203 pushing to ssh://user@dummy/remote
203 pushing to ssh://user@dummy/remote
204 searching for changes
204 searching for changes
205 no changes found
205 no changes found
206 deleting remote bookmark foo
206 deleting remote bookmark foo
207 [1]
207 [1]
208
208
209 a bad, evil hook that prints to stdout
209 a bad, evil hook that prints to stdout
210
210
211 $ cat <<EOF > $TESTTMP/badhook
211 $ cat <<EOF > $TESTTMP/badhook
212 > import sys
212 > import sys
213 > sys.stdout.write("KABOOM\n")
213 > sys.stdout.write("KABOOM\n")
214 > EOF
214 > EOF
215
215
216 $ echo '[hooks]' >> ../remote/.hg/hgrc
216 $ echo '[hooks]' >> ../remote/.hg/hgrc
217 $ echo "changegroup.stdout = python $TESTTMP/badhook" >> ../remote/.hg/hgrc
217 $ echo "changegroup.stdout = python $TESTTMP/badhook" >> ../remote/.hg/hgrc
218 $ echo r > r
218 $ echo r > r
219 $ hg ci -A -m z r
219 $ hg ci -A -m z r
220
220
221 push should succeed even though it has an unexpected response
221 push should succeed even though it has an unexpected response
222
222
223 $ hg push
223 $ hg push
224 pushing to ssh://user@dummy/remote
224 pushing to ssh://user@dummy/remote
225 searching for changes
225 searching for changes
226 note: unsynced remote changes!
226 remote has heads on branch 'default' that are not known locally: 6c0482d977a3
227 remote: adding changesets
227 remote: adding changesets
228 remote: adding manifests
228 remote: adding manifests
229 remote: adding file changes
229 remote: adding file changes
230 remote: added 1 changesets with 1 changes to 1 files
230 remote: added 1 changesets with 1 changes to 1 files
231 remote: KABOOM
231 remote: KABOOM
232 $ hg -R ../remote heads
232 $ hg -R ../remote heads
233 changeset: 3:1383141674ec
233 changeset: 3:1383141674ec
234 tag: tip
234 tag: tip
235 parent: 1:a28a9d1a809c
235 parent: 1:a28a9d1a809c
236 user: test
236 user: test
237 date: Thu Jan 01 00:00:00 1970 +0000
237 date: Thu Jan 01 00:00:00 1970 +0000
238 summary: z
238 summary: z
239
239
240 changeset: 2:6c0482d977a3
240 changeset: 2:6c0482d977a3
241 parent: 0:1160648e36ce
241 parent: 0:1160648e36ce
242 user: test
242 user: test
243 date: Thu Jan 01 00:00:00 1970 +0000
243 date: Thu Jan 01 00:00:00 1970 +0000
244 summary: z
244 summary: z
245
245
246
246
247 clone bookmarks
247 clone bookmarks
248
248
249 $ hg -R ../remote bookmark test
249 $ hg -R ../remote bookmark test
250 $ hg -R ../remote bookmarks
250 $ hg -R ../remote bookmarks
251 * test 2:6c0482d977a3
251 * test 2:6c0482d977a3
252 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local-bookmarks
252 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local-bookmarks
253 requesting all changes
253 requesting all changes
254 adding changesets
254 adding changesets
255 adding manifests
255 adding manifests
256 adding file changes
256 adding file changes
257 added 4 changesets with 5 changes to 4 files (+1 heads)
257 added 4 changesets with 5 changes to 4 files (+1 heads)
258 updating to branch default
258 updating to branch default
259 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
259 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
260 $ hg -R local-bookmarks bookmarks
260 $ hg -R local-bookmarks bookmarks
261 test 2:6c0482d977a3
261 test 2:6c0482d977a3
262
262
263 passwords in ssh urls are not supported
263 passwords in ssh urls are not supported
264 (we use a glob here because different Python versions give different
264 (we use a glob here because different Python versions give different
265 results here)
265 results here)
266
266
267 $ hg push ssh://user:erroneouspwd@dummy/remote
267 $ hg push ssh://user:erroneouspwd@dummy/remote
268 pushing to ssh://user:*@dummy/remote (glob)
268 pushing to ssh://user:*@dummy/remote (glob)
269 abort: password in URL not supported!
269 abort: password in URL not supported!
270 [255]
270 [255]
271
271
272 $ cd ..
272 $ cd ..
273
273
274 hide outer repo
274 hide outer repo
275 $ hg init
275 $ hg init
276
276
277 Test remote paths with spaces (issue2983):
277 Test remote paths with spaces (issue2983):
278
278
279 $ hg init --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
279 $ hg init --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
280 $ touch "$TESTTMP/a repo/test"
280 $ touch "$TESTTMP/a repo/test"
281 $ hg -R 'a repo' commit -A -m "test"
281 $ hg -R 'a repo' commit -A -m "test"
282 adding test
282 adding test
283 $ hg -R 'a repo' tag tag
283 $ hg -R 'a repo' tag tag
284 $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
284 $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
285 73649e48688a
285 73649e48688a
286
286
287 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
287 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
288
288
289 $ hg clone --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
289 $ hg clone --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
290 destination directory: a repo
290 destination directory: a repo
291 abort: destination 'a repo' is not empty
291 abort: destination 'a repo' is not empty
292 [255]
292 [255]
293
293
294 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
294 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
295 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
295 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
296 parameters:
296 parameters:
297
297
298 $ cat > ssh.sh << EOF
298 $ cat > ssh.sh << EOF
299 > userhost="\$1"
299 > userhost="\$1"
300 > SSH_ORIGINAL_COMMAND="\$2"
300 > SSH_ORIGINAL_COMMAND="\$2"
301 > export SSH_ORIGINAL_COMMAND
301 > export SSH_ORIGINAL_COMMAND
302 > PYTHONPATH="$PYTHONPATH"
302 > PYTHONPATH="$PYTHONPATH"
303 > export PYTHONPATH
303 > export PYTHONPATH
304 > python "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
304 > python "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
305 > EOF
305 > EOF
306
306
307 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
307 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
308 73649e48688a
308 73649e48688a
309
309
310 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
310 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
311 remote: Illegal repository "$TESTTMP/a'repo" (glob)
311 remote: Illegal repository "$TESTTMP/a'repo" (glob)
312 abort: no suitable response from remote hg!
312 abort: no suitable response from remote hg!
313 [255]
313 [255]
314
314
315 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
315 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
316 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
316 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
317 abort: no suitable response from remote hg!
317 abort: no suitable response from remote hg!
318 [255]
318 [255]
319
319
320 $ SSH_ORIGINAL_COMMAND="'hg' -R 'a'repo' serve --stdio" python "$TESTDIR/../contrib/hg-ssh"
320 $ SSH_ORIGINAL_COMMAND="'hg' -R 'a'repo' serve --stdio" python "$TESTDIR/../contrib/hg-ssh"
321 Illegal command "'hg' -R 'a'repo' serve --stdio": No closing quotation
321 Illegal command "'hg' -R 'a'repo' serve --stdio": No closing quotation
322 [255]
322 [255]
323
323
324 Test hg-ssh in read-only mode:
324 Test hg-ssh in read-only mode:
325
325
326 $ cat > ssh.sh << EOF
326 $ cat > ssh.sh << EOF
327 > userhost="\$1"
327 > userhost="\$1"
328 > SSH_ORIGINAL_COMMAND="\$2"
328 > SSH_ORIGINAL_COMMAND="\$2"
329 > export SSH_ORIGINAL_COMMAND
329 > export SSH_ORIGINAL_COMMAND
330 > PYTHONPATH="$PYTHONPATH"
330 > PYTHONPATH="$PYTHONPATH"
331 > export PYTHONPATH
331 > export PYTHONPATH
332 > python "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
332 > python "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
333 > EOF
333 > EOF
334
334
335 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
335 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
336 requesting all changes
336 requesting all changes
337 adding changesets
337 adding changesets
338 adding manifests
338 adding manifests
339 adding file changes
339 adding file changes
340 added 4 changesets with 5 changes to 4 files (+1 heads)
340 added 4 changesets with 5 changes to 4 files (+1 heads)
341 updating to branch default
341 updating to branch default
342 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
342 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
343
343
344 $ cd read-only-local
344 $ cd read-only-local
345 $ echo "baz" > bar
345 $ echo "baz" > bar
346 $ hg ci -A -m "unpushable commit" bar
346 $ hg ci -A -m "unpushable commit" bar
347 $ hg push --ssh "sh ../ssh.sh"
347 $ hg push --ssh "sh ../ssh.sh"
348 pushing to ssh://user@dummy/*/remote (glob)
348 pushing to ssh://user@dummy/*/remote (glob)
349 searching for changes
349 searching for changes
350 remote: Permission denied
350 remote: Permission denied
351 remote: abort: prechangegroup.hg-ssh hook failed
351 remote: abort: prechangegroup.hg-ssh hook failed
352 remote: Permission denied
352 remote: Permission denied
353 remote: abort: prepushkey.hg-ssh hook failed
353 remote: abort: prepushkey.hg-ssh hook failed
354 abort: unexpected response: empty string
354 abort: unexpected response: empty string
355 [255]
355 [255]
356
356
357 $ cd ..
357 $ cd ..
358
358
359 $ cat dummylog
359 $ cat dummylog
360 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
360 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
361 Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio
361 Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio
362 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
362 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
363 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
363 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
364 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
364 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
365 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
365 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
366 Got arguments 1:user@dummy 2:hg -R local serve --stdio
366 Got arguments 1:user@dummy 2:hg -R local serve --stdio
367 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
367 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
368 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
368 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
369 changegroup-in-remote hook: HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_SOURCE=serve HG_URL=remote:ssh:127.0.0.1
369 changegroup-in-remote hook: HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_SOURCE=serve HG_URL=remote:ssh:127.0.0.1
370 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
370 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
371 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
371 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
372 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
372 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
373 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
373 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
374 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
374 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
375 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
375 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
376 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
376 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
377 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
377 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
378 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
378 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
379 changegroup-in-remote hook: HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 HG_SOURCE=serve HG_URL=remote:ssh:127.0.0.1
379 changegroup-in-remote hook: HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 HG_SOURCE=serve HG_URL=remote:ssh:127.0.0.1
380 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
380 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
381 Got arguments 1:user@dummy 2:hg init 'a repo'
381 Got arguments 1:user@dummy 2:hg init 'a repo'
382 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
382 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
383 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
383 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
384 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
384 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
General Comments 0
You need to be logged in to leave comments. Login now